如何每秒检查一个 div 是否与另一个 div 重叠?

How to check if a div overlaps with another div every second?

我正在制作一个关于移动玩家以躲避子弹的快速游戏,但我在如何检测是否有子弹与玩家发生碰撞方面遇到了问题。在游戏引擎中,通常只存在用于两个对象碰撞的事件监听器,因为我还没有为 webb 开发找到类似的东西,我想我可以使用无限循环来检查每颗子弹是否与玩家发生碰撞。

我无法执行 while (true) 循环,因为它会崩溃。我试图在每颗子弹的生成函数中设置一个间隔,但我不知道如何在子弹消失后清除间隔。而且我还尝试只创建一个间隔,该间隔会在当前循环遍历现有项目符号并检查项目符号是否发生碰撞,但由于某种原因我收到此错误:Uncaught TypeError: bullets.forEach is not a function 这里是代码:


function checkOverlap(){
    let bullets = document.getElementsByClassName("bullet");
    if (bullets.length > 0){
        bullets.forEach(bullet => {
            let overlap = !(bullet.right < player.left || 
                    bullet.left > player.right || 
                    bullet.bottom < player.top || 
                    bullet.top > player.bottom)
            if (overlap){
                console.log("overlap");
            }
        });
    }
}
setInterval(checkOverlap, 1000);

我也想知道是否可以通过这种方式检测重叠。由于我使用 transitionleft, top, right, down css 属性来移动我的子弹,它会检测到还是我需要使用其他东西?

您无法访问 forEach,因为 document.getElementsByClassName 不是 return 一个 Array - 它 return 是一个 NodeList有点像 Array,但在其他方面有所不同 - 一方面,它的原型没有 forEach 方法。

您可以通过执行以下操作轻松转换为 Array

let bullets = [ ...document.getElementsByClassName('bullet') ];

就碰撞而言,我建议您使用 getBoundingClientRect(我经常将其拼写与 getClientBoundingRect 混淆,现在我提醒自己 B 先于 C : D).这 return 是 html 元素的绝对几何形状,将所有因素都考虑在内:

let doCollide = (player, bullet) => {
  let playerBound = player.getBoundingClientRect();
  let bulletBound = bullet.getBoundingClientRect();

  // (px, py) and (bx, by) represent the center of the player and bullet
  let px = playerBound.left + playerBound.width * 0.5;
  let py = playerBound.top + playerBound.height * 0.5;
  let bx = bulletBound.left + bulletBound.width * 0.5;
  let by = bulletBound.top + bulletBound.height * 0.5;

  let wOff = (playerBound.width + bulletBound.width) * 0.5;
  let hOff = (playerBound.height + bulletBound.height) * 0.5;

  // Collision occurs when bullet and player are separated on neither x nor y axes
  return Math.abs(px - bx) < wOff && Math.abs(py - by) < hOff;
}

let player = document.getElementsByClassName('player')[0];
let bullet = document.getElementsByClassName('bullet')[0];

let testFn = () => {

  player.style.left = `${Math.floor(Math.random() * 300)}px`;
  player.style.top = `${Math.floor(Math.random() * 150)}px`;
  bullet.style.left = `${Math.floor(Math.random() * 300)}px`;
  bullet.style.top = `${Math.floor(Math.random() * 150)}px`;
  
  if (doCollide(player, bullet)) {
    player.classList.add('coll');
    bullet.classList.add('coll');
  } else {
    player.classList.remove('coll');
    bullet.classList.remove('coll');
  }
  
};

setInterval(testFn, 1500);
testFn();
html, body { position: relative; width: 100%; height: 100%; overflow: hidden; padding: 0; margin: 0; }

.player, .bullet { position: absolute; }
.player { width: 150px; height: 150px; box-shadow: inset 0 0 0 4px rgba(0, 150, 0, 1); }
.bullet { width: 60px; height: 90px; box-shadow: inset 0 0 0 4px rgba(0, 210, 0, 1); }

.player.coll { box-shadow: inset 0 0 0 4px rgba(200, 0, 0, 1); }
.bullet.coll { box-shadow: inset 0 0 0 4px rgba(255, 0, 0, 1); }
<div class="player"></div>
<div class="bullet"></div>