子弹消失或玩家被击中时玩家均受伤害的原因排查
问题分析与修复方案
你的核心问题出在碰撞检测的逻辑缺陷上:
- 碰撞判断用的是子弹创建瞬间的玩家位置,没有实时获取玩家移动后的最新位置,导致玩家移动后,旧位置和子弹位置可能误判碰撞,甚至子弹出界时触发掉血。
- 仅用子弹左上角的单点位置判断是否在玩家范围内,没有考虑子弹的整体矩形,精度极低,容易出现误触发。
修复步骤
- 实时获取玩家位置:将玩家位置的获取移到
moveBullet函数内部,确保每次碰撞判断都用玩家当前的最新位置。 - 改用矩形碰撞检测:获取子弹的完整边界矩形,通过判断两个矩形是否重叠来确认碰撞,这是更准确的碰撞判断方式。
修改后的完整代码
function shootPlayer() { if (!document.body.contains(enemy)) return; // Stop if the enemy is removed const enemyRect = enemy.getBoundingClientRect(); const enemyCenterX = enemyRect.left + enemyRect.width / 2; const enemyCenterY = enemyRect.top + enemyRect.height / 2; const playerRectInitial = player.getBoundingClientRect(); const playerCenterX = playerRectInitial.left + playerRectInitial.width / 2; const playerCenterY = playerRectInitial.top + playerRectInitial.height / 2; const angle = Math.atan2(playerCenterY - enemyCenterY, playerCenterX - enemyCenterX); const bullet = document.createElement('div'); bullet.className = 'bullet'; bullet.style.position = 'absolute'; bullet.style.top = `${enemyCenterY}px`; bullet.style.left = `${enemyCenterX}px`; document.body.appendChild(bullet); const bulletSpeed = 5; const bulletDamage = 5; function moveBullet() { // 实时获取玩家和子弹的最新边界 const playerRect = player.getBoundingClientRect(); const bulletRect = bullet.getBoundingClientRect(); let bulletTop = parseFloat(bullet.style.top); let bulletLeft = parseFloat(bullet.style.left); bulletTop += bulletSpeed * Math.sin(angle); bulletLeft += bulletSpeed * Math.cos(angle); bullet.style.top = `${bulletTop}px`; bullet.style.left = `${bulletLeft}px`; console.log(`Bullet Position: (${bulletLeft}, ${bulletTop})`); // 准确的矩形碰撞判定逻辑 if ( bulletRect.right >= playerRect.left && bulletRect.left <= playerRect.right && bulletRect.bottom >= playerRect.top && bulletRect.top <= playerRect.bottom ) { decreasePlayerHealth(bulletDamage); bullet.remove(); console.log('Bullet hit the player.'); return; } // 检查子弹是否出界并移除 if (bulletTop < 0 || bulletTop > window.innerHeight || bulletLeft < 0 || bulletLeft > window.innerWidth) { bullet.remove(); console.log('Bullet despawned.'); return; } // 继续移动子弹 requestAnimationFrame(moveBullet); } requestAnimationFrame(moveBullet); }
额外测试建议
暂时关闭被动伤害逻辑,单独测试子弹碰撞功能,确认只有子弹实际击中玩家时才会触发decreasePlayerHealth。如果子弹有超时销毁逻辑,要确保超时分支不会调用掉血函数。
内容的提问来源于stack exchange,提问作者Lachie Dwyer
相关产品推荐
相关产品推荐

