views:

100

answers:

4

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..

A: 

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 */);
Mahir
I don't want to simply test if they are colliding. I want to learn how to do it manually, because I'm gonna need to find information like the collision angle which is not returned by the function you mentioned, as far as I know.but.. in your code, are you talking about change all the pixels location in the bitmap using a rotation matrix? is that it?
joxnas
The collision angle? Could you elaborate (i.e. the normal to the tangent of the place they collided). The way to do it manually is to loop through each pixel of one bitmap and see if it is touching the pixel of another bitmap. Then if any pixel is touching another pixel of the other the bitmaps are overlapping somewhere. Now you should use some heuristic to limit the pixels you test because that method is extremely, extremely inefficient.
Mahir
The coordinate transform was given in the case that your bitmap is rotated.Ex: Your bmd is a 20x20 pixel square with its top left corner located at (0,0). You rotate it 45 degrees clockwise to make it a diamond (again the top left corner is at (0,0)). If you'd like to see if the Stage location (0, 25) is touching the bmd, (which it is), then you cannot hitTest with (0, 25) because the hitTest measures locations relative to the bmd. You need to transform that location to (25/sqrt(2), 25/sqrt(2)) which is what the code in my example is meant for.
Mahir
What I have:2 movie clips that have speedX and speedYWhat I want: A timer/frame event(<<<this I can do) where I check if they are coliding, and what is the collision angle.How I think I will do it: actionscript3 has hitTestObject. I can see if mc1 and mc2 outer boxes are colliding with this test. If yes, then I need to transform them into pixels and see if they have at least 2 non-transparent pixels in the same coordinates(but I will only test this in the intersection rectangle betwen the two movieclips outerboxes).If this happens, they are coliding, and I can find out the angle of collision
joxnas
The problem is not the algorithm or the maths. It's to know what each thing does, and what are the limtiations. What happens when I draw the MovieClip1 into the BitMap1, and then I draw MovieClip2 in BitMap2? The coordenates of things.. how this methods work. This is what I need to find out..
joxnas
A: 

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)).

Juan Pablo Califano
I recall Grant Skinner's method only working correctly if both objects are direct children of the stage.
Cameron
A: 

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

Sly_cardinal
A: 

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.

joxnas