Actionscript 3 pixel perfect collision. How to? (learning purposes)

I know that there are people out there creating classes for this (ie http://coreyoneil.com/portfolio/index.php?project=5). But I want to learn how to do it myself so I can create everything I need the way I need.

I've read about BitMap and BitMapData. I should be able to .draw the MovieClips onto a BitMap so I could then cycle the pixels looking for the collisions. However, It's weird and confusing dealing with the offsets.. And it seams like the MyBitMap.rect has always x = 0 and y = 0... and I can't seam to find the original position of the things...

I'm thinking of doing a hitTestObject first, then if this was positive, I would investigate the intersection betwen the movieclips rectangles for the pixel collisions. But then there is also another problem (the rotation of movieclips)...

...I need some enlightment here on how to do it. Please, any help would be appreciated..

Answers


If you're using BitmapData objects with transparency you can use BitmapData.hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean.

You'll have to change from global coords to the local BitmapData coords which will require a bit of math if it is rotated. That's easily achieved (look up affine transform for more info on wiki):

var coordTransform:Matrix = new Matrix();

coordTransform.rotate(rotationRadians);
coordTransform.translate(x, y);

coordTransform.transformPoint(/* your point */);

A classic reference for pixel perfect collision detection in flash is this Grant Skinner's article. It's AS2, but the logic is the same for AS3 (there are ports available if you google a bit).

If I recall correctly, this particular implementation worked as long as both tested objects had the same parent, but that can be fixed.

About BitmapData x and y values, I understand it could be confusing; however, the way it works makes sense to me. A BitmapData is just what the name implies: pixel data. It's not a display object, and cannot be in the display list; so having x or y different than 0 doesn't really make sense, if you think about it. The easiest way to deal with this is probably storing the (x,y) offset of the source object (the display object you have drawn from) and translate it to the global coordinate space so you can compare any objects, no matter what's their position in the display list (using something like var globalPoint:Point = source.parent.localToGlobal(new Point(source.x,source.y)).


I've previously used Troy Gilbert's pixel perfect collision detection class (adapted from Andre Michelle, Grant Skinner and Boulevart) which works really well (handles rotation, different parents, etc.):

http://troygilbert.com/2007/06/pixel-perfect-collision-detection-in-actionscript3/ http://troygilbert.com/2009/08/pixel-perfect-collision-detection-revisited/

and from there he has also linked to this project (which I've not used, but looks really impressive):

http://www.coreyoneil.com/portfolio/index.php?project=5


I managed to do it after all, and I already wrote my class for collision detections,/collisions angle and other extras.

The most confusing process is maybe to align the bitmaps correctly for comparing. When whe draw() a movieclip into a a BitmapData, if we addChild() the corresponding Bitmap we can see that part of it is not visible. it appears to be drawn from the center to right and down only, leaving the top and left parts away from beeing drawn. The solution is giving a transform matrix in the second argument of the draw method that aligns the bitmap and makes it all be drawn.

this is an example of a function in my class to create a bitmap for comparing:

    static public function createAlignedBitmap(mc: MovieClip, mc_rect: Rectangle): BitmapData{
                var mc_offset: Matrix;
                var mc_bmd: BitmapData;

                mc_offset = mc.transform.matrix;
                mc_offset.tx = mc.x - mc_rect.x;
                mc_offset.ty = mc.y - mc_rect.y;
                mc_bmd = new BitmapData(mc_rect.width, mc_rect.height, true, 0);
                mc_bmd.draw(mc, mc_offset);

                return mc_bmd;
}

in order to use it, if you are on the timeline, you do:

className.createAlignedBitmap(myMovieClip, myMovieClip.getBounds(this))

Notice the use of getBounds which return the rectangle in which the movie clip is embedded. This allows the calculation of the offset matrix.

This method is quite similar to the on shown here http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/

By the ways, if this is an interesting matter for you, check my other question which I'll post in a few moments.


Need Your Help

Move files to folders with partial names

batch-file dos

I have about 250 files that I need to move to a specific folder. The problem is that folder only have the partial name of the files.

Loading individual columns of csv

mysql load-data-infile

I am using load data infile, what would I have to do to import only a certaing element in CSV file to a certain column in our table