首页 > 解决方案 > 如何检查一个div是否每秒与另一个div重叠?

问题描述

我正在制作一个关于移动玩家躲避子弹的快速游戏,但我遇到了如何检测是否有任何子弹与玩家碰撞的问题。在游戏引擎中,通常只存在用于两个对象碰撞的事件侦听器,因为我还没有找到类似 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, downcss 属性来移动我的子弹,它会检测到还是我需要使用其他东西?

标签: javascriptforeachcollisionevent-listeneroverlapping

解决方案


您无法访问forEach,因为document.getElementsByClassName它不返回 an Array- 它返回的 aNodeList行为有点像 an Array,但在其他方面有所不同 - 因为它的原型没有forEach方法。

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

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

就碰撞而言,我建议您使用getBoundingClientRect(我经常将其拼写混淆为getClientBoundingRect,现在我提醒自己B先于C:D)。这将返回一个 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>


推荐阅读