Michał Malik
Sep 21 · 5 min read

In this multipart tutorial, I would like to walk the reader through the process of developing a simple HTML5 platform game. The game is written with TypeScript and uses PixiJS v5 as rendering engine.

This course is split into following parts:

For convenience each part corresponds to a branch in github repository: https://github.com/MMMalik/platform-game-tutorial

The final result can be accessed under the following url: https://mmmalik.github.io/platform-game-tutorial/

I expect the reader to be familiar with TypeScript and have some basic experience with PixiJS.

As a disclaimer, I would like to note that game development is not my main area of expertise. I am merely having fun developing games and learning about game development. If you find some of the ideas I share here as incomplete or simply wrong, I will be glad to know.


In the previous parts, we have created game assets, setup game components and introduced state management.

In this part we will develop collision detection, an essential part of most games. Since our game objects can be approximated with rectangles (bounding boxes) of edges parallel to the Cartesian coordinate axes (they are axis-aligned), therefore we can use AABB (axis-aligned bounding box) checks. This technique boils down to the following statement: There is a collision whenever two axis-aligned rectangles intersect. Such check is easy to implement:

However, in case of character-and-platform collisions, we need something a bit more elaborate. The above check will simply tell us if two rectangles collide but we need to know in advance if such collision will occur and we need to adjust character’s velocity accordingly. For instance, if our character is 1 px away from a platform tile horizontally, while current horizontal velocity is 2 px per frame, the character would simply end up inside the platform. Therefore, we need to know if the collision will occur and how far one object will penetrate the other one. This will let us adjust character’s velocity accordingly.

Below is an example implementation of functions which can help us calculate required penetrations on the following axes: horizontal, vertical, and both diagonals. Please note that these checks are direction-dependent. For instance, if character’s vX is negative (character runs left), and a collision is detected, willCollideH function will give us a positive number equalling the predicted penetration. On the other hand, if character’s vX is positive (character runs right), this function gives us a negative penetration if a collision is detected. We can use the penetration to adjust character’s velocity.

Helper functions used to calculate penetration of AABB collisions

Let’s use the above methods to calculate collisions in our game:

Within calculateCharacterCollisions function we first calculate character’s bounding box. It has not been stated previously explicitly, but character’s coordinates (x and y) are set to be in the middle of its bounding box. The reason behind it is that we need to be able to properly leverage sprite’s scale to flip the texture when character changes moving direction (from right to left or vice versa). Platform tiles, on the other hand, have coordinates set to left upper corner which is default for a PixiJS sprite.

Then, we set CharacterCollisionRect to establish constant size of the character’s bounding box. Please keep in mind that character’s frame size equals 50 x 37 px (width x height), including a significant margin around the actual character’s image. If we used those dimensions directly, our character would give an impression of being immersed in the platform vertically and never being able to touch an edge of a platform horizontally:

Bounding box equalling size of the texture

Instead, we can make the bounding box a bit narrower but higher, say 30 x 50 px. As a result, the character nicely touches the ground and is able to touch the platform walls.

Bounding box of a more natural size

Once the bounding box of character is calculated, we can proceed with calculating possible collisions with platform with the help of collisionsWithPlatform function. First, let’s map all platform tiles to possible collisions. Once this is done, we check if there are any non-zero penetrations horizontally and vertically. If there are any, the function will return respective values.

However, if there are no such penetrations detected, we have to check diagonals as well. Imagine a scenario in which a character is falling and bottom right corner of its bounding box touches top left corner of a platform tile’s bounding box. No vertical or horizontal collision would be detected and we would observe an anomal behavior:

Lack of diagonal checks might cause anomalies

Regardless of the origin of collision (horizontal, vertical, or diagonal), if any upcoming collision is detected, we can use the calculated penetration to adjust character’s vX and vY. For instance, if character collides with a given tile vertically, we need to add the value of penetration to gravity.

This ends the part 3 of this tutorial. So far in the series we have established how to:

  • use free game assets in our game by leveraging free Piskel app to create spritesheets and how to use free Tiled app to create platforms.
  • create game components and manage game state
  • detect upcoming collisions to allow character’s smooth moves on the platform

The gif below shows a small demo of what we have achieved so far:

State of the game so far

Stay tuned for more!

JavaScript in Plain English

Learn the web's most important programming language.

Michał Malik

Written by

Web developer, former organic synthetic chemist, craft beer enthusiast.

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade