我正在用纯JS制作一个小的html5画布游戏(使用Ecmascript 6的标准)。 到目前为止,一切进展顺利,但现在我遇到了一个反复出现的TypeError(未捕获的TypeError:无法读取未定义的属性'位置')。
这种情况经常发生,当游戏检查两个阵列内的对象之间的碰撞时(更具体地说:子弹和敌人之间的碰撞检测)。
大多数情况下,我的碰撞检测功能正常。当我认为我已经解决了这个问题时,它会在一段时间后再次发生。
这是我的代码:
const collisionCheckBulletEnemy = () => {
for(let i = bullets.length -1; i >= 0; i--){
for(let j = enemies.length -1; j >= 0; j--){
if(collisionCheck(bullets[i], enemies[j], 10, 10)){
bullets.splice(i, 1);
enemies.splice(j, 1);
}
}
}
}
这是碰撞检测功能:
const collisionCheck = (a, b, marginA, marginB) => {
// margins can be added to make things a little easier/harder on the user
if(!marginA){
marginA = 0;
}
if(!marginB){
marginB = 0;
}
return !(
a.position.x - marginA > b.position.x + b.width + marginB ||
a.position.x + a.width + marginA < b.position.x - marginB ||
a.position.y - marginA > b.position.y + b.height + marginB ||
a.position.y + a.height + marginA < b.position.y - marginB
);
}
答案 0 :(得分:3)
这种情况正在发生,因为有时参数a
或b
会传递到函数中,即使它只是undefined
值。尝试执行undefined.position
会导致类型错误。
简单,苛刻的解决方案只是将条件放在最上面:
if (!a || !b) {
return 0; // or whatever your default value is supposed to be
};
真正的,更好的解决方案是弄清楚为什么bullets
和enemies
包含一些未定义的值。
阅读完代码后,我认为这就是答案:
如果i = bullets.length - 1
:
if(collisionCheck(bullets[i], enemies[j], 10, 10)) {
bullets.splice(i, 1);
enemies.splice(j, 1);
}
特别是这部分bullets.splice(i, 1);
你将数组缩短了1,但你永远不会减少i
。
因此,如果bullets[i]
是数组中的最后一个元素,那么bullets[i]
为undefined
,因为javascript不会抛出indexOutOfBounds
之类的错误。
现在你开始发现你的代码中存在的一个巨大缺陷就是当从数组中删除子弹时它不会停止循环,并且你只注意到它是最后一个索引。即使它不是最后一个索引,它也会继续循环使用另一个看起来不像你的意图的子弹。
相反,你应该突破循环,因为如果你的子弹击中你的子弹,你不应该继续检查同一子弹的碰撞:
if(collisionCheck(bullets[i], enemies[j], 10, 10)) {
bullets.splice(i, 1);
enemies.splice(j, 1);
break;
}