简体   繁体   中英

Detecting the collision of 2 divs with JavaScript

I'm making a simple Space Invaders Clone in Web and ran into an issue. The code works well so far with the exception of the collision system. I need to destroy an enemy every time that the player's bullet hits it. In order to make it, I'm grabbing the x and y coordinates of both the enemies' div and the bullet's div. The issue appears on the values comparison: apparently getBoundingClientRect() grabs the x and y coordinates from within the element excluding its real size. Hence, according to my code, only when the bullet is perfectly inside the enemy that things would trigger. Is there a better way of doing it? How so?

Thanks in advance.

 const shoot = (x) => { //Creates bullet const main = document.getElementById("main"); const div_bullet = document.createElement("div"); //Appends child main.appendChild(div_bullet); //Sets position div_bullet.style.top = "340px"; div_bullet.style.left = x + "px"; //Gives it a class div_bullet.classList.add("div_bullet"); div_bullet.setAttribute("id", "bullet"); //Deletes bullet setTimeout(() => { div_bullet.remove(); }, 1000); }; const load_game = () => { //Adding movement to the spaceship const space_ship = document.getElementById("space_ship"); let x = 375; window.addEventListener("keydown", (e) => { switch (e.key) { case "ArrowLeft": if (x <= 15) break; x = x - 10; space_ship.style.left = x + "px"; break; case "ArrowRight": if (x >= 725) break; x = x + 10; space_ship.style.left = x + "px"; break; case "ArrowUp": if (document.getElementsByClassName("div_bullet").length === 0) shoot(x + 20); break; default: break; } }); }; const collision_system = () => { setInterval(() => { //Checks if any enemy was hit const e1 = document.getElementById("e1"); const e2 = document.getElementById("e2"); const e3 = document.getElementById("e3"); const e4 = document.getElementById("e4"); const e5 = document.getElementById("e5"); const enemies_position = [{ x: e1.getBoundingClientRect().x, y: e1.getBoundingClientRect().y }, { x: e2.getBoundingClientRect().x, y: e2.getBoundingClientRect().y }, { x: e3.getBoundingClientRect().x, y: e3.getBoundingClientRect().y }, { x: e4.getBoundingClientRect().x, y: e4.getBoundingClientRect().y }, { x: e5.getBoundingClientRect().x, y: e5.getBoundingClientRect().y }, ]; if (document.getElementById("bullet")) { const x_bullet = document .getElementById("bullet") .getBoundingClientRect().x; const y_bullet = document .getElementById("bullet") .getBoundingClientRect().y; console.log( "X: " + enemies_position[0].x + "Y: " + enemies_position[0].y ); console.log("X bullet: " + x_bullet + "Y bullet : " + y_bullet); for (let i = 0; i < 5; i++) { if ( enemies_position[i].x === x_bullet && enemies_position[i].y === y_bullet ) alert("Shoot!"); } } }, 10); }; document.addEventListener("DOMContentLoaded", () => { load_game(); collision_system(); });
 * { padding: 0px; margin: 0px; } body { background-color: black; width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; } .main { width: 800px; height: 500px; border: 2px white solid; border-radius: 10px; } @keyframes enemies_move { from { left: 80px; } to { left: -80px; } } .enemies { margin-top: 20px; position: fixed; width: 800px; height: 50px; display: flex; justify-content: space-evenly; } .enemies div { position: relative; width: 50px; height: 50px; background-color: orange; animation: enemies_move 4s alternate infinite; } .barriers { width: 800px; height: 20px; position: fixed; top: 460px; display: flex; justify-content: space-evenly; } .barriers div { width: 100px; height: 20px; background-color: white; } .space_ship { width: 50px; height: 50px; border: 2px white solid; position: relative; top: 440px; left: 375px; } @keyframes shoot_bullet { from { top: 340px; } to { top: -50px; } } .div_bullet { left: 17px; width: 15px; height: 40px; background-color: white; position: relative; animation: shoot_bullet 1s; }
 <div id="main" class="main"> <div class="enemies"> <div id="e1"></div> <div id="e2"></div> <div id="e3"></div> <div id="e4"></div> <div id="e5"></div> </div> <div class="barriers"> <div></div> <div></div> <div></div> <div></div> </div> <div id="space_ship" class="space_ship"></div> </div>

The problem in your code is that you are using only the x and y of the bullet and enemy to check for collisions. You need to use the width and height of both items to check if they collide.

The checks needed to see if two rects collide is

function rectCollision(rectA, rectB) {
  return (
    rectA.x < rectB.x + rectB.width &&
    rectA.x + rectA.width > rectB.x &&
    rectA.y < rectB.y + rectB.height &&
    rectA.height + rectA.y > rectB.y
  );
}

And using this in your code makes it work

 const shoot = (x) => { //Creates bullet const main = document.getElementById("main"); const div_bullet = document.createElement("div"); //Appends child main.appendChild(div_bullet); //Sets position div_bullet.style.top = "340px"; div_bullet.style.left = x + "px"; //Gives it a class div_bullet.classList.add("div_bullet"); div_bullet.setAttribute("id", "bullet"); //Deletes bullet setTimeout(() => { div_bullet.remove(); }, 1000); }; const load_game = () => { //Adding movement to the spaceship const space_ship = document.getElementById("space_ship"); let x = 375; window.addEventListener("keydown", (e) => { switch (e.key) { case "ArrowLeft": if (x <= 15) break; x = x - 10; space_ship.style.left = x + "px"; break; case "ArrowRight": if (x >= 725) break; x = x + 10; space_ship.style.left = x + "px"; break; case "ArrowUp": if (document.getElementsByClassName("div_bullet").length === 0) shoot(x + 20); break; default: break; } }); }; const collision_system = () => { setInterval(() => { //Checks if any enemy was hit const e1 = document.getElementById("e1"); const e2 = document.getElementById("e2"); const e3 = document.getElementById("e3"); const e4 = document.getElementById("e4"); const e5 = document.getElementById("e5"); const enemies_position = [ e1.getBoundingClientRect(), e2.getBoundingClientRect(), e3.getBoundingClientRect(), e4.getBoundingClientRect(), e5.getBoundingClientRect(), ]; if (document.getElementById("bullet")) { const bullet = document .getElementById("bullet") .getBoundingClientRect(); console.log( "X: " + enemies_position[0].x + "Y: " + enemies_position[0].y ); console.log("X bullet: " + bullet.x + "Y bullet : " + bullet.y); for (let i = 0; i < 5; i++) { if ( rectCollision(enemies_position[i], bullet) ) alert("Shoot!"); } } }, 10); }; function rectCollision(rectA, rectB) { return (rectA.x < rectB.x + rectB.width && rectA.x + rectA.width > rectB.x && rectA.y < rectB.y + rectB.height && rectA.height + rectA.y > rectB.y) } document.addEventListener("DOMContentLoaded", () => { load_game(); collision_system(); });
 * { padding: 0px; margin: 0px; } body { background-color: black; width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; } .main { width: 800px; height: 500px; border: 2px white solid; border-radius: 10px; } @keyframes enemies_move { from { left: 80px; } to { left: -80px; } } .enemies { margin-top: 20px; position: fixed; width: 800px; height: 50px; display: flex; justify-content: space-evenly; } .enemies div { position: relative; width: 50px; height: 50px; background-color: orange; animation: enemies_move 4s alternate infinite; } .barriers { width: 800px; height: 20px; position: fixed; top: 460px; display: flex; justify-content: space-evenly; } .barriers div { width: 100px; height: 20px; background-color: white; } .space_ship { width: 50px; height: 50px; border: 2px white solid; position: relative; top: 440px; left: 375px; } @keyframes shoot_bullet { from { top: 340px; } to { top: -50px; } } .div_bullet { left: 17px; width: 15px; height: 40px; background-color: white; position: relative; animation: shoot_bullet 1s; }
 <div id="main" class="main"> <div class="enemies"> <div id="e1"></div> <div id="e2"></div> <div id="e3"></div> <div id="e4"></div> <div id="e5"></div> </div> <div class="barriers"> <div></div> <div></div> <div></div> <div></div> </div> <div id="space_ship" class="space_ship"></div> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM