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.

The Move

I'm going to get started on the level editor now. I'll start off simple with object selection and re-positioning using the mouse. Before I get to the editor code itself, there are a couple of things that I need to add first..

Heavy Loaded Head

Most games work best when you have more than one level, but ip until now that's all I've had - one level. Even worse, that level has been created directly from code written into the game itself - to change it I have to rewrite the code. What I need is data driven level loading - the levels should be defined by a data file. In this post I will be defining a level format and writing code to load it into the game. Let's start by talking about how the data will be laid out..