2D Collision Detection

I wanted to make a game that would operate and feel like Super Mario World out of JavaScript. The physics and movement of the characters on the screen in these games are simple and elegant. The most basic way to approach this type of 2d collision detec…


This content originally appeared on Level Up Coding - Medium and was authored by Austin Rhoads

I wanted to make a game that would operate and feel like Super Mario World out of JavaScript. The physics and movement of the characters on the screen in these games are simple and elegant. The most basic way to approach this type of 2d collision detection is to utilize a concept known as Axis-aligned bounding box.

Axis-aligned bounding box, or AABB, detects if two non-rotational polygons are overlapping each other. Typically AABB algorithms run something like this:

We have two polygons, each with an X (left), and a Y (top) position, as well as width and height properties.

We then compare X and Y positions along with width and height to see if they are overlapping.

We test four conditional statements, if all are true then we know we are overlapping. Lets break each conditional on it’s own.

line 2 — A’s left side is to the left of B’s right side.

line 3 — A’s right side is to the right of B’s left side.

line 4 — A’s top is above B’s bottom.

line 5 — A’s bottom is lower than B’s top.

Let’s plug in the real values for Mario and his coin, represented by the yellow and red polygons. The X and Y positions of each polygon comes from the distance in pixels from the left and top edges of the viewport.

This algorithm has a robust range of applications. It can be used to detect if your player is over a collectible item, touching a bad guy, at the door at the end of the game or just standing on a solid object.

Game Components

My project was a simple tile-based 2d platform game consisting of the player object, a 32 by 32 pixel red square named “Cubio”, three types of “baddies” and the tile map of the game’s world.

Tiles

The entire map is made up of just four tiles types. 80 by 80 pixels in dimension, each has it’s own numerical value and specified sets of rules that determine how the player interacts with them upon collision.

0: sky

The player moves freely through this tile.

1: earth

If the player lands on top of the tile, the player’s vertical movement stops and it rests on top of the tile, otherwise it can go through this tile in every other direction.

2: crate

If the player collides with any side of this tile it’s position stays outside of this tile.

3: sky_island

If the player lands on top of the tile, the player’s vertical movement stops and it rests on top of the tile, otherwise it can go through this tile in every other direction.

Map

Without going into too much detail here the tile map is represented by an array of tile types in their assigned column and row, such that the array:

…appears as:

Interaction and Behavior

Whether its the sky or earth, my player is always colliding with at least one tile in every single frame so there is no need to run the aabb() function. My collision_detection() function first locates the position of each corner of the player. Then, it retrieves the type of tile that corner is colliding with. Then it passes in the tile’s type and the corner’s x and y position into the collide() function.

The collide() function uses a switch statement to select the appropriate block of code to run depending on the tile type. As you can see type “0” (sky) has no effect and type “2” (crate) collides with all four sides. In case your are wondering why I’ve defined these points twice in collision_detection(), it’s because each time I call collide() it has the potential to move the player. So every point has to be redefined each time after I call collide().

In these different tile collide functions you can see the older position of the player is compared to the tile as well. This allows you to establish the direction the player is going.

The function needs to know what direction the player is going in order to have the correct response. Otherwise if the player collided with the bottom of the crate tile, it’s top is now above the crate’s bottom. Then when we run collide() the collide_top() fires first and places the player on top of the tile. To the user it would appear as if the player went straight through the bottom of the crate and landed on top. This negative effect is known as “tunneling”. Therefore, establishing player direction gives us a better representation of what’s happening.

You can see how that when writing a baddy_collision_detection() function it would be very similar to this only we can modify collide_top() to kill the baddy and all other collides to kill the player on contact.

function baddyCollideTopMortal(player, bad){
    if (player.getBottom() > bad.getTop() && player.getOldBottom() <= bad.getTop()){

player.setBottom(bad.getTop() - 0.01);

player.y_velocity = -27;
player.jumping = false;
let dead_index = currentGame.alive_baddies.indexOf(bad);
currentGame.alive_baddies.splice(dead_index, 1);
return true;
} return false;
}

function baddyCollideLeft(player, bad){

if (player.getRight() > bad.getLeft() && player.getOldRight() <= bad.getLeft()){
player.setRight(bad.getLeft() - 1);
player.x_velocity = 0;
player_dead = true;
return true;
} return false;

}

Efficiency with AABB, Coins, and Baddies

Once all of you tiles, coins and baddies are interacting with you player correctly you’ll notice that running a collision test on every coin and every baddy at every cycle of you engine loop is very costly and unnecessary.

This is where you separate the process of test for collision into two phases, broad and narrow.

Broad

In the broad phase, create an array of near entities(coins, baddies). Iterate through the full list of entities, checking the object’s x position to see if it’s close to the player and then pushing that entity into a near list. This is a lot less costly than running the entire collision test on each entity.

Narrow

Once a much smaller list of near objects is created we then iterate over each testing for collision with the aabb() function and/or run appropriate blocks of code.

Collision detection is the mechanism that brings your game to life. Each step is easy to understand and can be re-imagined many different ways, but once implemented is powerful. Happy coding!


2D Collision Detection was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Austin Rhoads


Print Share Comment Cite Upload Translate Updates
APA

Austin Rhoads | Sciencx (2021-09-03T14:03:33+00:00) 2D Collision Detection. Retrieved from https://www.scien.cx/2021/09/03/2d-collision-detection/

MLA
" » 2D Collision Detection." Austin Rhoads | Sciencx - Friday September 3, 2021, https://www.scien.cx/2021/09/03/2d-collision-detection/
HARVARD
Austin Rhoads | Sciencx Friday September 3, 2021 » 2D Collision Detection., viewed ,<https://www.scien.cx/2021/09/03/2d-collision-detection/>
VANCOUVER
Austin Rhoads | Sciencx - » 2D Collision Detection. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/09/03/2d-collision-detection/
CHICAGO
" » 2D Collision Detection." Austin Rhoads | Sciencx - Accessed . https://www.scien.cx/2021/09/03/2d-collision-detection/
IEEE
" » 2D Collision Detection." Austin Rhoads | Sciencx [Online]. Available: https://www.scien.cx/2021/09/03/2d-collision-detection/. [Accessed: ]
rf:citation
» 2D Collision Detection | Austin Rhoads | Sciencx | https://www.scien.cx/2021/09/03/2d-collision-detection/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.