<Marc Qualie/>

Pixel Perfect Collision Detection AS3

Hi guys! It's been a long time since I've posted on here, but I've been a very busy little worker bee! I will explain more about that in my next post, however. Right now I want to share some code that has been annoying me for the past 4 hours, as maybe it will help someone in the future. I'm currently working on an arcade racing game, just so I have something challenging to keep me out of trouble, but it's proving more difficult than I thought.

My basic problem was I needed to check if the car was currently hitting anything apart from the track, which in this case was the grass, but I also needed to know which part of the car was hitting the object. I started off looking through adobe live docs, as I have used something called hitTestPoint and hitTestObject before. Unfortunately, these are very limited due to the fact my track is a very complex and weird shape. hitTestPoint and hitTestObject only work on either a point, or the bounding box of the object. Somehow I managed to get hitTestObject working on curved lines in a previous project, but I think that may have been AS2. Luckily there is a bitmapData API which allows for deep integration into Bitmap Collision Detection. It all sounds fine and dandy, until you actually start using the code.

This is the basic Syntax for using the function:

hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean

I also found various examples of people using this technique around the Internet, but after an hour of trying I still couldn't get mine working in the game! Turns out, which Adobe fails to mention, that it seems specific on which way round you test the objects. In my example I was testing the front left wheel, against the grass that goes around the entire track.

My Code was:

var Map:GameMap = Main.instance.Scene.current.Map;
var Grass:Bitmap = Map.CollisionLayer;
var WheelPoint:Point = Wrap.localToGlobal(new Point(Wheel.x, Wheel.y));
var GrassPoint:Point = Map.localToGlobal(new Point(0, 0));
if (Wheel.bitmapData.hitTest(WheelPoint, 255, Grass.bitmapData, GrassPoint, 255)) {
   // Hit
} else {
  // No Hit
}

Looking at the documentation, and others' examples, the code above should have worked! I even tried replacing the Wheel variables with the Mouse Position. Also, when I traced the global values out, and drove the car to the top left of where the grass starts (Grass Point), the global values were Identical. The most annoying thing is, I was sure I had tried switching them around (I've learned from past experience programs can be very picky when it comes to the order in which objects are referenced), but I hadn't. Something in my head triggered me to flip the values round and there you have it, working, "Pixel Perfect Collision" using bitmapData.

Here is my final code if you're interested:

var Map:GameMap = Main.instance.Scene.current.Map;
var Grass:Bitmap = Map.CollisionLayer;
var WheelPoint:Point = Wrap.localToGlobal(new Point(Wheel.x, Wheel.y));
var GrassPoint:Point = Map.localToGlobal(new Point(0, 0));
if (Grass.bitmapData.hitTest(GrassPoint, 255, Wheel.bitmapData, WheelPoint, 255)) {
 // Hit
} else {
 // No Hit
}

There is still quite a bit of optimization to go now that I've figured out the basics, such as testing the entire object's bounding box first, rather than doing pixel precision detection on every frame. The game is still a work in progress, but I'm hoping to post an early version online for you guys to play with and give me feedback on by the end of the week.

If you have any questions about this post, or anything else, you can get in touch on Bluesky or browse my code on Github.