8bitrocket.com
19Apr/070

Advanced Flash 8 Game Programming : Pixel level collision detection

I had to take a little break after finishing Retroblaster to unwind before I started making games again. I plan to re-write my game loop and much of my game code in this public forum for a couple reasons. One is the selfish need of a cathartic outlet, and the other is to help aide other fledgling Flash game programmers. You will be learning as I learn. I will post my examples here, complete with code explanations and .fla files to download. The first lesson will be in collision detection. If you have tried the many popular methods of collision detection (hitTest, circle to circle, hitTest with a shape flag, etc) you will find none of them as accurate as pixel level detection. The downside is that pixel level detection will probably slow down a game with many objects all interacting at once. I have not done any frame rate tests, but a future post will compare the methods and see.

The bitmapData object, introduced in Flash 8, makes this possible. There are other methods to do pixel level collision detection, but they are either very math intensive (matrix math scares me), or use something like Grant Skinner Does here.

My version will be much easier for novices to understand. Basically it will be done in these steps

1. Create 2 sprites using a sprite map and the bitmapData object.
2. Attach those sprites to movieClips
3. Provide a reference to the attached sprite
4. While the user moves one of the clips with the keyboard, first check for a basic hitTest collision.
5. After a basic collision is detected, then and only then, do a pixel level hitTest with the bitMapdata.hitTest() function.

That's it. The code is below. I have added comments where needed. After the code there is a link to the example swf page and a .fla to download and try for yourself. I am using as sprite map from Ari Feldman's Sprite Lib GPL . Ari made this library and lets anyone use it for free as long as the abide by the GPL license.

 

[cc lang="javascript" width="550"]//hitpixels.fla
//Jeff Fulton 2007
//www.8bitrocket.com
//pixel level collision detection with bitmap data object

import flash.display.*;
import flash.geom.*;

//1. load in spriteMap from library
var spriteMapBitmap:BitmapData = BitmapData.loadBitmap("spriteMap");
var mc:MovieClip = this.createEmptyMovieClip("mc", this.getNextHighestDepth());
//mc.attachBitmap(spriteMapBitmap, this.getNextHighestDepth());

//2. copy pixels from spriteMap to mc1
var sprite1:BitmapData=new BitmapData(32,32,true,0x00000000);
sprite1.copyPixels(spriteMapBitmap, new Rectangle(495, 33, 32, 32), new Point(0, 0));
this.createEmptyMovieClip("sprite1_mc",this.getNextHighestDepth());
sprite1_mc.attachBitmap(sprite1,sprite1_mc.getNextHighestDepth);
sprite1_mc._x=100;
sprite1_mc._y=100;

//2. copy pixels from spriteMap to mc2
var sprite2:BitmapData=new BitmapData(32,32,true,0x00000000);
sprite2.copyPixels(spriteMapBitmap, new Rectangle(33, 33, 32, 32), new Point(0, 0));
this.createEmptyMovieClip("sprite2_mc",this.getNextHighestDepth());
var sprite2_bitmap:BitmapData=sprite2_mc.attachBitmap(sprite2,sprite2_mc.getNextHighestDepth);
sprite2_mc._x=200;
sprite2_mc._y=200;

this.onEnterFrame=function() {

if (Key.isDown(Key.UP)) {
sprite1_mc._y ;
}
if (Key.isDown(Key.DOWN)) {
sprite1_mc._y++;
}
if (Key.isDown(Key.LEFT)) {
sprite1_mc._x ;
}
if (Key.isDown(Key.RIGHT)) {
sprite1_mc._x++;
}

if (sprite1_mc.hitTest(sprite2_mc)) {
normal_txt.text="true";
//trace("basic hit detected");
//test for pixel level hit
var myPoint:Point = new Point (sprite2_mc._x, sprite2_mc._y);
if (sprite1.hitTest (new Point (sprite1_mc._x , sprite1_mc._y), 255, sprite2, myPoint, 255)){
bitmap_txt.text="true";
//trace("bitMap hit detected");
}else{
bitmap_txt.text="false";
}
}else{
normal_txt.text="false";
bitmap_txt.text="false";

}

}
[/cc]

hitpixels.swf - demo of using bitmapData to do pixel level collision detection(2007).

Use the arrow keys to move the tank to the orange splotch sprite.

When the tank enters the 32x32 area for the splotch, the normal hit becomes true.

The bitmap hit will become true only if the tank collides with a non-trnasprant pixel in the splotch.

download the fla file

Ari Feldman's Sprite Lib used via GPL

1. When you attach a bitmapData object to a movieClip, a reference to the bitmapData object is passed, not the actual object. For hit testing purposes, you must use the original bitmapData object.
2. Here I have just used an object named sprite1, copied pixels from a png (with transparency) from the library to it, and have attached it to a movieClip.
3. if (sprite1.hitTest (new Point (sprite1_mc._x , sprite1_mc._y), 255, sprite2, myPoint, 255) is the function invoked. You must specify a point in both movieClip holders for the sprites tested, and the value (255) for the transparency threshold of each bitmap object.. This number represents the alpha threshold for the transparent areas. You can increase the :"sensitivity" of the collision test by lowering the number below 255. 255 means that ALL transparent areas, no matter the actual alpha value will be ignored in the hitTest. This gives you the best overall pixel level control.
4. To make a real game with this code (where multiple enemy sprites are needed) you would need to make sure to store a reference to to actual bitmapData object that makes up each enemy sprite and replace that with the sprite2 value as you loop through all of the enemy sprites.

The next lesson will be a simple way to add cached animation from the sprite map to this engine and you will see how a game will start to take shape.

 

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.

This site is protected by Comment SPAM Wiper.