Skip to content
Advertisement

Detect collision (video game js)

I am building a video game where fireballs drop from the top screen. The spaceship, moved by controllers, must avoid those fireballs in order win. My issue is that I do not know how to detect when the spaceship collides into fireballs. However, I found this link: Detect if animated object touched another object in DOM. I analysed this code and it seems it only works for his issue particularly. Do you guys know how to do this?

Code for image spaceship and fireball:

<img src="Photo/fireball.png" id="fireball">
<img src="Photo/Spaceship1.png" id="icon-p">

Code for spaceship:

let rect = icon
let pos = {top: 1000, left: 570}
const keys = {}
window.addEventListener("keydown", function(e) {keys[e.keyCode] = true})
window.addEventListener("keyup", function(e) {keys[e.keyCode] = false})
const loop = function() {
if (keys[37] || keys[81]) {pos.left -= 10}
if (keys[39] || keys[68]) {pos.left += 10}
if (keys[38] || keys[90]) {pos.top -= 10}
if (keys[40] || keys[83]) {pos.top += 10}
var owidth = display.offsetWidth
var oheight = display.offsetHeight
var iwidth = rect.offsetWidth
var iheight = rect.offsetHeight
if (pos.left < 0) pos.left = -10
if (pos.top < 0) pos.top = -10
if (pos.left + iwidth >= owidth) pos.left = owidth-iwidth
if (pos.top + iheight >= oheight) pos.top= oheight-iheight
rect.setAttribute("data", owidth + ":" + oheight)
rect.style.left = pos.left + "px"; rect.style.top = pos.top + "px"}
let sens = setInterval(loop, 1000 / 60)

Code for fireball:

function fFireball(offset) {
return Math.floor(Math.random() * (window.innerWidth - offset))}
let fireballElement = document.querySelector("#fireball");
let fireball = {x: fFireball(fireballElement.offsetWidth), y: 0}
const fireLoop = function() {
fireball.y += 2
fireballElement.style.top = fireball.y + 'px'
if (fireball.y > window.innerHeight) {
fireball.x = fFireball(fireballElement.offsetWidth)
fireballElement.style.left = fireball.x + 'px'; fireball.y = 0}}
fireballElement.style.left = fireball.x + 'px'
let fireInterval = setInterval(fireLoop, 1000 / 100)

Thanks!

Advertisement

Answer

here I’ve integrated collision detection for your game. The most notable thing is in this function:

function checkCollision() {
  var elem = document.getElementById("icon");
  var elem2 = document.getElementById("fireball");
  if ( detectOverlap(elem, elem2) && elem2.getAttribute('hit')=='false' ){ 
    hits++; // detect hit and increase
    elem2.setAttribute('hit', true); // set attribute to not have flooding
    console.log( hits ); // console it just to see it
  }
  setTimeout( checkCollision, 20);
}

In lower window you can test demo that I’ve built for you without images but some random boxes as images 🙂

Good luck with game man, cool

//////////
"use strict"
//Stay on focus
function stayOnFocus() {
  setTimeout(function() {
    alert("Do not exit window or game progression will be lost!")
  }, 1000)
}

let hits = 0

//"A" keypress plays Music
document.addEventListener('keydown', function(e) {
  if (e.keyCode !== 173) {
    //document.getElementById('audio').play()
  }
})

//Input Validation
let icon = document.getElementById("icon")
let fireballElement = document.querySelector("#fireball")
var input = document.getElementById("input")
input.addEventListener("keydown", function(event) {
  if (event.keyCode === 13) {
    event.preventDefault();
    document.getElementById("begin-timer").click()
  }
})

//CountDown (3...2...1)
var count = 3

function countDown() {
  function preventCountFast() {
    document.getElementById("count").innerHTML = count
    if (count > 0) {
      count--
    } else {
      clearInterval(ncount);
      document.getElementById("count").style.display = "none"
    }
  }
  var ncount = setInterval(preventCountFast, 1000)
}

//Name displayed + space(switch between images) + parameter icon displayed
function Username(field) {
  field = input.value
  if (field == "") {
    alert("Complete blanks");
    return false
  }
  document.getElementById("askName").style.display = "none"
  setTimeout(function() {
    document.getElementById("name").innerHTML = "Player: " + field
    icon.style.display = 'block';
    fireballElement.style.display = "block"
    const images = ["https://placehold.it/30x30", "https://placehold.it/90x90",
      "https://placehold.it/120x40", "https://placehold.it/100x100"
    ]
    document.body.onkeyup = function(e) {
      if (e.keyCode === 32) {
        hits++;
        icon.src = images[hits % 5]
      }
    }
    checkCollision();
  }, 4000)
}

//Spaceship moves into space + prevent going out borders
let display = document.getElementById("body");
let rect = icon
let pos = {
  top: 1000,
  left: 570
}
const keys = {}
window.addEventListener("keydown", function(e) {
  keys[e.keyCode] = true
})
window.addEventListener("keyup", function(e) {
  keys[e.keyCode] = false
})
const loop = function() {
  if (keys[37] || keys[81]) {
    pos.left -= 10
  }
  if (keys[39] || keys[68]) {
    pos.left += 10
  }
  if (keys[38] || keys[90]) {
    pos.top -= 10
  }
  if (keys[40] || keys[83]) {
    pos.top += 10
  }
  var owidth = display.offsetWidth
  var oheight = display.offsetHeight
  var iwidth = rect.offsetWidth
  var iheight = rect.offsetHeight
  if (pos.left < 0) pos.left = -10
  if (pos.top < 0) pos.top = -10
  if (pos.left + iwidth >= owidth) pos.left = owidth - iwidth
  if (pos.top + iheight >= oheight) pos.top = oheight - iheight
  rect.setAttribute("data", owidth + ":" + oheight)
  rect.style.left = pos.left + "px";
  rect.style.top = pos.top + "px"
}
let sens = setInterval(loop, 1000 / 60)

//Parameter Sensibility
let param = document.getElementById("parameters")
let b2 = document.getElementById("body2")
document.getElementById("general").addEventListener("click", function() {
  param.style.display = "block";
  b2.style.display = "none"
})

function validateSens() {
  b2.style.display = "block";
  param.style.display = "none";
  clearInterval(sens)
  let sensibilty = parseFloat(document.getElementById("sensibilty").value)
  switch (sensibilty) {
    case 1:
      sens = setInterval(loop, 1000 / 40);
      break;
    case 2:
      sens = setInterval(loop, 1000 / 60);
      break;
    case 3:
      sens = setInterval(loop, 1000 / 80);
      break;
    default:
      alert("Sorry, a bug occured")
  }
}

//Fireball script
function fFireball(offset) {
  return Math.floor(Math.random() * (window.innerWidth - offset))
}
let fireball = {
  x: fFireball(fireballElement.offsetWidth),
  y: 0
}
const fireLoop = function() {
  fireball.y += 2;
  fireballElement.style.top = fireball.y + 'px'
  if (fireball.y > window.innerHeight) {
    fireball.x = fFireball(fireballElement.offsetWidth)
    fireballElement.style.left = fireball.x + 'px';
    fireball.y = 0;
    fireballElement.setAttribute('hit', false );
  }
}
fireballElement.style.left = fireball.x + 'px'
let fireInterval = setInterval(fireLoop, 1000 / 100)


function checkCollision() {
  var elem = document.getElementById("icon");
  var elem2 = document.getElementById("fireball");
  if (detectOverlap(elem, elem2) && elem2.getAttribute('hit')=='false' ){ 
    hits++; // detect hit
    elem2.setAttribute('hit', true);
    aler("hi")
  }
  setTimeout( checkCollision, 20);
}

// detect fn


var detectOverlap = (function() {
  function getPositions(elem) {
    var pos = elem.getBoundingClientRect();
    return [
      [pos.left, pos.right],
      [pos.top, pos.bottom]
    ];
  }

  function comparePositions(p1, p2) {
    var r1, r2;
    r1 = p1[0] < p2[0] ? p1 : p2;
    r2 = p1[0] < p2[0] ? p2 : p1;
    return r1[1] > r2[0] || r1[0] === r2[0];
  }

  return function(a, b) {
    var pos1 = getPositions(a),
      pos2 = getPositions(b);
    return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
  };
})();
body {
  user-select: none;
  margin: 0px;
  height: 100vh;
  padding: 0;
  width: 100%;
  background-image: url(Photo/bg.jpg);
  background-repeat: no-repeat;
  background-attachment: fixed;
  animation: intro-fade 3s;
  background-size: cover;
  overflow: hidden;
}

#askName {
  display: block;
  z-index: 1;
  margin-left: auto;
  margin-top: 12%;
  margin-right: auto;
  width: 400px;
  text-align: center;
  background-color: #737373;
  opacity: 0.8;
  border-radius: 15px;
  padding: 40px 50px 40px 50px;
}

#askName:hover {
  opacity: 0.9
}

#askName>label {
  text-align: center;
  font-size: 150%;
  font-weight: lighter;
  text-align: center;
}

#askName>input {
  display: block;
  font-size: 100%;
  margin: 30px auto 20px auto;
  border: none;
  border-radius: 10px;
  padding: 10px 20px 10px 20px;
}

#askName>button {
  background-color: #e6e6e6;
  cursor: pointer;
  padding: 10px 20px 10px 20px;
  border: none;
  border-radius: 10px;
}

#count {
  margin-top: 13%;
  animation: count-down 16s;
  font-weight: lighter;
  font-family: cursive;
  text-align: center;
  color: black;
  font-size: 200px;
}

h6 {
  margin-right: 20px;
  padding-top: 5px;
  font-weight: normal;
  font-family: sans-serif;
  margin-top: 0px;
  color: white;
  text-align: center;
  font-size: 190%;
  cursor: default;
}

h6:hover {
  font-size: 210%
}

#icon {
  position: absolute;
  top: 0;
  left: 0;
  cursor: none;
  width: 9%;
}

#general {
  position: absolute;
  cursor: pointer;
  min-width: 4%;
  top: 10px;
  width: 4%;
  right: 10px;
}

#general:hover {
  transform: rotate(-100deg)
}

#parameters {
  text-align: center;
  display: none;
  animation: intro-fade 3s;
  height: auto;
  border: none;
  background-color: #d9d9d9;
  color: black;
  position: absolute;
  padding: 0px 60px 20px 60px;
  left: 50%;
  width: auto;
  min-width: 200px;
  top: 50%;
  transform: translate(-50%, -50%);
  border-radius: 13px;
}

h3 {
  color: black;
  font-weight: normal;
  font-size: 150%;
}

#sensibilty {
  display: block;
  margin-right: auto;
  margin-left: auto;
}

#validateSens {
  margin-top: 20px;
  border: none;
  padding: 10px;
  border-radius: 5px;
  cursor: pointer;
}

@keyframes intro-fade {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}

@keyframes count-down {
  from {
    transform: scale(0)
  }
  to {
    transform: scale(1)
  }
}
<body id="body" onload="stayOnFocus()">

  <img src="https://placehold.it/350x350" id="general">

  <section id="parameters">
    <h3> Choose your sensibility </h3>
    <input type="range" id="sensibilty" min="1" max="3" value="2">
    <button id="validateSens" onclick="validateSens()"> Submit </button>
  </section>

  <main id="body2">
    <form id="askName" title="Write your name"> <label> Enter your username: </label>
      <input id="input" type="text" maxlength="10" autofocus>
      <button type="button" onclick="countDown(); return Username()" id="begin-timer"> Submit </button>
    </form>

    <h6 id="name"></h6>
    <h2 id="count"></h2>

    <img src="https://placehold.it/50x52" id="fireball" style="display:none; width:3%; position:absolute; cursor:none">
    <img src="https://placehold.it/80x40" id="icon" style="display:none">
  </main>
Advertisement