Skip to main content

Hold It Now, Hit It

Last time, I added coarse "box" collision to the game. Box collision is fast, but it's not accurate enough for a shoot-em-up. What I need is pixel perfect collision. This works using "collision maps" for the two objects. A collision map is basically the same as a sprite image (which is sometimes called a pixel map), but instead of storing a colour value for each pixel, I store a true or false value - true if the pixel is set, false if not. When it comes to checking for collision, I walk across the two collision maps and check for any pixel where both maps are set to true. If that happens then the two objects are colliding.


In the following image, you can see the difference between the two types of collision:



If we were to just consider box collision, then it looks like the bullet has hit the player object - you will have noticed that in the last step where the collision felt really unfair. But if we compare the actual pixels of the two images for the two objects then we can see that there is no collision. From a conceptual point of view this is pretty straight-forward, but one extra thing that you'll see in shoot-em-ups is that the image you see on screen is not the image that is used for the collision map. The maps used for collision are usually much smaller than the sprites themselves, and this is what makes it possible for a skilled player to slip through holes that seem far too small to fit through.

In the case of our player, the collision map is just the size of their ship's cockpit - this is a pretty common trick in shoot-em-ups. The bullet collision map is also slightly smaller than the sprite that it represents. Here's another image to show the difference between what you see and what the game uses for collision tests:


Onto The Code

So how does this work in code? I only needed to add write two new chunks of code: one function to generate collision maps from the source images, and then an update to the isColliding() routine.

First up, here's the generation code. This code takes a source image and draws it to a temporary Canvas object. From there I can grab the pixels (in Red, Green, Blue, Alpha format) that make up the sprite. This happens on line 8, where the pixel data is grabbed into a linear array of bytes. The first four bytes are the RGBA values of the first pixel, then the next four bytes for the next pixel, etc.. I step through this array, one pixel at a time, and check the alpha value. If the pixel is transparent then I consider that to be a false value in the collision map, otherwise it's a true value. It follows that the collision map is defined by any part of the source image that is completely transparent. Finally, I return an object which contains the width, height and collision map data.

Secondly, here are the changes to the isColliding0 function:


You'll see a couple of loops in there where I walk across the collision maps of one of the objects. For each bit of the mask I then figure out the overlapping part of the second object's collision map. Finally, if both parts of both maps are true then it means that collision has happened.

Plumbing

There are a couple of other small bits of plumbing required to get this all working, the first one being the creation of the collision maps in init():

..and then I need to store those maps in the objects, so I added a new argument to the base object constructor:

Wrapping Up

I talked about the need for pixel perfect collision, why the collision maps are not what they seem, and then implemented some collision routines that are based on sprite images. This creates a flexible and accurate collision system that can be used for all object types.

The code is in BitBucket and the playable online version is here.

Next Time..

What's next? There are a couple of options.. but I think I'll go for adding font and text routines so that I can start displaying information on the screen. If you have any ideas about what you'd like to see next, please get in touch through the comments.

Comments

Popular posts from this blog

Set The Controls For The Heart Of The Sun

When we last met, I had just started work on a level editor. I'd got as far as adding the ability to select an object and move it around, and then I added an undo/redo system using the command pattern. That was a good start, but dragging items around the level is only fun for so long. What I really want to be doing is.. ..editing the properties of the bullet spawners! And I want to be doing this in realtime as the game plays so that I can immediately see what effect my changes have made to the gameplay of the level.

World In Motion

In the last post I touched on how easy it is to score in this game - you can just camp out on the score bullet spawner and watch the points rack up. I'm going to add a little delay to the score bullets so that they start out in a deactivated and uncollectable state, and then change to active and collectable after a short time - say, half a second. To make it clear what state they are in I'm going to add code to let me change the look of Objects and allow them to be animated.

The Long And Winding Road

I started this blog back in November of last year. My aim was to document the development of a Bullet Hell shoot-em-up, written in JavaScript. Here we are, six months later, and lots has happened. With 20 posts already written, I thought that now would be a good time to take stock of what I've already done, and to look to the future and see what's to come.