Thursday, May 3, 2012
TMoD episode 4: Space Shield
When researching different disasters the idea of a solar flare was high on the list. The big problem was finding a classic-style arcade game that would work with the theme. Thinking about how to stop a solar flare lead to the obvious placement of satellites, even though realistically you would need way too many. Placing satellites immediately got me thinking of the space junk problem that we are having. This immediately got me thinking about the road-crossing games I played on my cousins Atari 2600 so the game was set.
One of the big issues with the game was the collision detection. Unfortunately, Flash does not have per-pixel collision detection (at least not built in to Flash Player 10, I haven't researched Stage 3D or Starling enough to know if Flash Player 11 does). The object detection is bounding box based. Point based detection does support a per pixel option so I set off on my task to write a simple per-pixel collision detection routine. I originally opted for a simple brute force approach. Flash let's you find the bounding box of a clip relative to a container, so getting the bounding boxes of the two colliding objects then finding the intersection of the two objects is easy. My thought was then to look though the points in the intersection rectangle to see if they both flag collisions at the same points and are therefore overlapping.
In my tests this worked great. The problem is that my tests used vector shapes. When bitmap images were used, anything within the bitmap bounding box was flagged even if it was transparent. There is really no excuse for this other than lazy or incompetent programming at Adobe. This meant that I would have to look at the bitmap data myself. Sadly, this is not a very efficient thing to do.
To get the pixel information, I need to draw into a bitmap data object. This first requires getting a copy of the transformation matrix used to draw the display object. Thankfully this is easily accessible. Next, a translation is applied to only draw the intersection portion of the image. The drawing is done. Repeat for the second object in a second BitmapData object and then compare the pixels in the two bitmapData objects. As this is done using a getPixel function call repeatedly, I honestly can't see this as being very efficient. Then I remembered an article I read about using color filters. This got me thinking about how I could get rid of one of the bitmapData objects and combine the two images into one.
First, you set the bitmapData background color to black. The draw function supports color filters making it possible to max out or clear a color channel. By maxing the red and green channels while dropping the blue channel of the first image then dropping the red channel of the second image while maxing out the green and blue channels of the second image while drawing it over the first image using the ADD filter you will end up with white pixels where the two images overlap. There is actually a built in routine for finding a bounding box containing a particular color so finding the overlapping pixels is easy.
This is not the best way of doing the collision detection, but it works. There are some edge cases where it won't work, but that isn't a problem in this game. It is sad that such a straightforward thing requires so much work.