How to Implement Collision Detection in JavaScript

Sahil Bhosale Feb 02, 2024
How to Implement Collision Detection in JavaScript

In JavaScript, a collision occurs when two or more HTML elements collide. By default, when using a move event listener on an HTML element, it will not hit any other element on the screen.

It will pass through the other elements in the DOM. So, to detect collision in JavaScript, we manually have to do it using the x and y coordinates of the elements.

In this article, we will take two div elements (two squares) inside our webpage, and we will see how to implement collision detection when one of the squares collides with the other.

Implement Collision Detection in JavaScript

We will implement the collision detection purely in JavaScript, and we will not be using any other third-party library. First, we will write our HTML, then we will move on to the CSS part, and at the end, we will write the JavaScript code.

Inside the HTML, we will add two div elements with classes square_1 and square_2. square_2 will be at a fixed location while square_1 will be moving anywhere on the screen.

<body>
    <div class="square_1"></div>
    <div class="square_2"></div>
</body>

We will add basic styles like width and height to the squares as 160px inside the CSS and change the position of both the squares as absolute. It will allow us to move the squares anywhere on the screen.

We will give a background color of red to square_1 and yellow to square_2.

Since we want square_2 to be fixed at a particular location on the screen, we will add a left and top property and give it a value 400px. We will also add a font-size property to square_1 because we will be showing a text on it after colliding with the other one.

Finally, we will set the z-index of the first square to 1 because we want it to stay on top of the other while moving it. If we don’t set this property, it will go underneath the second square.

.square_2{
    width: 160px;
    height: 160px;
    position: absolute;
    left: 400px;
    top: 400px;
    background-color:rgb(255, 233, 36);
}

.square_1{
    position: absolute;
    width: 160px;
    height: 160px;
    background-color:rgb(255, 80, 80);
    font-size: 1.5em;
    z-index: 1;
}

Output:

Output Without Move Event Listener

We cannot move the red square as we have not added the move event listener.

We first have to access the two squares we added inside our HTML to our JavaScript code. For this, we will be using the getElementsByClassName() function to get the two div elements and pass the class name as a parameter to this function.

Since this function returns an array, we will be indexing to grab the first element. Then we will store the two square div inside the square_1 and square_2 variables.

Now that we have access to both the square elements, we will first get the width and height of both these elements. We have a JavaScript function called getComputedStyle(), which takes an element as a parameter.

So, we will pass the square_1 and square_2 variables as parameters to this function. And then, using dot notation, we will access the elements’ CSS properties.

Notice that we are also using the split() function. This is because the getComputedStyle() function returns a value with its unit.

For example, we have set the width to both elements as 160px. So the value return by the getComputedStyle() function will be 160px in the form of a string.

We don’t want the px part, so we use split() and pass px inside it. This function will return an array of two elements, the first element will be 160, and the second will be blank.

We need the value itself, so we will use [0] to access it.

var square_1 = document.getElementsByClassName('square_1')[0];
var square_2 = document.getElementsByClassName('square_2')[0];

var square_1_width =
    Number((getComputedStyle(square_1).width).split('px')[0]) / 2;
var square_2_width =
    Number((getComputedStyle(square_2).width).split('px')[0]) / 2;

var square_1_height =
    Number((getComputedStyle(square_1).height).split('px')[0]) / 2;
var square_2_height =
    Number((getComputedStyle(square_2).height).split('px')[0]) / 2;

Since the value returned will be a string, we will convert it into a number and divide it by 2 since we want its half value, i.e., 80. In the end, we are storing the values into the variables, as shown above.

Now, we will add a mousemove event listener on square_1 using the addEventListener() function. As shown below, this function takes an event and a callback function as parameters.

We will pass the event e to the callback function to track the mouse position on the screen.

As soon as we hover the mouse cursor over square_1 and move the mouse, we want the mouse’s left and top positions to be assigned to our square’s left and top position so that it can move wherever we move the mouse cursor.

square_1.addEventListener('mousemove', (e) => {
  square_1.style.left = (e.clientX - square_1_width) + 'px';
  square_1.style.top = (e.clientY - square_1_height) + 'px';

  checkCollision();
});

Output:

Added Mousemove Event Listener Collision

The e.clientX and e.clientY give the mouse movement’s top-right and bottom-right positions.

However, we want the cursor to show at the square’s center, so we subtract the width and height of the square using square_1_width and square_1_height with the half-width and height stored in them.

This will make the mouse cursor point to the center of the square when we drag it, as shown below.

Before running the code, ensure that you comment out the checkCollision() function, as we have not defined it yet inside our code.

Now, let’s create the checkCollision() function to detect collision. Here, we will first get both the squares’ left and top positions using the getComputedStyle() function.

Finally, we will typecast the string value into a number and store it in a variable.

We will store the left and top position of square_1 inside the x_pos_sq_1 and y_pos_sq_1 variables and square_2 inside the x_pos_sq_2 and y_pos_sq_2 variables.

Now, we will check whether our first square (red) is crossing any of the four sides of the second square (yellow) or not. We will add one condition for every side of the second square (yellow) for checking.

Note that both squares’ x and y positions are currently at the center of the squares.

function checkCollision() {
  let x_pos_sq_1 = Number((getComputedStyle(square_1).left).split('px')[0]);
  let y_pos_sq_1 = Number((getComputedStyle(square_1).top).split('px')[0]);

  let x_pos_sq_2 = Number((getComputedStyle(square_2).left).split('px')[0]);
  let y_pos_sq_2 = Number((getComputedStyle(square_2).top).split('px')[0]);

  let leftPos = x_pos_sq_1 + square_1_width > x_pos_sq_2 - square_2_width;
  let rightPos = x_pos_sq_1 - square_1_width < x_pos_sq_2 + square_2_width;

  let topPos = y_pos_sq_1 + square_1_height > y_pos_sq_2 - square_2_height;
  let bottomPos = y_pos_sq_1 - square_1_height < y_pos_sq_2 + square_2_height;

  if (leftPos && rightPos && topPos && bottomPos) {
    square_1.innerHTML = 'Collision occured';
    square_2.style.border = '5px solid rgb(24, 251, 240)';
  } else {
    square_1.innerHTML = '';
    square_2.style.border = 'none';
  }
}

Output:

Collision With Blue Border on Yellow Square

To detect if the red square collides with the yellow square from the left side, we will check if the red square’s x position and width are greater than the yellow square’s x position minus its width. The red square has collided with the yellow square from the left side if it is larger.

It will return a boolean value that we will store inside the leftPos variable.

To detect if the red square collides with the yellow square from the right side, we will check if the red square’s x position minus its width is lesser than the yellow square’s x position and its width. The red square has collided with the yellow square from the right side if it is lesser.

It will return a boolean value that we will store inside the rightPos variable.

The top position is similar to the left position; the only difference is that instead of the x-axis and width, we deal with the y-axis and height. This will return a boolean value which we will store inside the topPos variable.

The bottom position is similar to the right position, but we deal with the y-axis and height. This will also return a boolean value which we will store inside the bottomPos variable.

At the end of the checkCollision() function, we will check if the red square crosses the boundaries of the yellow square or not by adding an if condition with leftPos, rightPos, topPos, and bottomPos inside.

If all the variables generate a true value, the square_1 has collided with the square_2. As soon as this happens, we will give a blue border to our yellow square, and we will also add the text Collision occurred on the red square as shown above.

If we bring the red square outside the boundaries of the yellow square, then we will remove the border from the yellow square and remove the text from the red square.

Sahil Bhosale avatar Sahil Bhosale avatar

Sahil is a full-stack developer who loves to build software. He likes to share his knowledge by writing technical articles and helping clients by working with them as freelance software engineer and technical writer on Upwork.

LinkedIn