I've finally gotten around to updating my pixel-perfect collision detection post (which is by far the most popular post on this blog with 48+ comments and a double-digit percentage of all my pageviews). Of course, now that I've gotten around to updating it there's not much point, as others have improved upon and trumped what I had. So, I'll just provide a quick recap of their pursuits (and my version of them).
First, The Actionscript Man grabbed my version, Grant Skinner's (which mine was indirectly based on), digested them, then spit out a new one that eliminated some draw calls. He even made a nice little app that lets you toggle between the various versions and compare them. The only drawback of his version is that it assumes the two objects have the same parent.
Next, the venerable Tink posted his version that uses the same technique as The Actionscript Man but factors a more complicated parent-child relationship. Tink's still assumes that both objects are on the stage. His code also gets bitten by a bug I've run into related to localToGlobal and nested SWFs (though I still haven't explored it enough to write about it yet), as discussed in the comments. Tink added an "accuracy" parameter that basically scales the bitmap used for testing up and down. I've not found this makes enough of a performance difference to warrant the dramatic differences it can make in a pixel-perfect test.
So, I updated my version to include the rendering method Tink and The Actionscript Man used, and included the "common parent" math my original one had. The upside of my version is that it doesn't care whether your objects are on the stage or not, just that they share a common parent.
-
/** Get the collision rectangle between two display objects. **/
-
public static function getCollisionRect(target1:DisplayObject, target2:DisplayObject, commonParent:DisplayObjectContainer, pixelPrecise:Boolean = false, tolerance:int = 255):Rectangle
-
{
-
// get bounding boxes in common parent's coordinate space
-
var rect1:Rectangle = target1.getBounds(commonParent);
-
var rect2:Rectangle = target2.getBounds(commonParent);
-
-
// find the intersection of the two bounding boxes
-
var intersectionRect:Rectangle = rect1.intersection(rect2);
-
-
// if not pixel-precise, we're done
-
if (!pixelPrecise) return intersectionRect;
-
-
// size of rect needs to be integer size for bitmap data
-
intersectionRect.x = Math.floor(intersectionRect.x);
-
intersectionRect.y = Math.floor(intersectionRect.y);
-
intersectionRect.width = Math.ceil(intersectionRect.width);
-
intersectionRect.height = Math.ceil(intersectionRect.height);
-
-
// if the rect is empty, we're done
-
if (intersectionRect.isEmpty()) return intersectionRect;
-
-
// calculate the transform for the display object relative to the common parent
-
var parentXformInvert:Matrix = commonParent.transform.concatenatedMatrix.clone();
-
parentXformInvert.invert();
-
var target1Xform:Matrix = target1.transform.concatenatedMatrix.clone();
-
target1Xform.concat(parentXformInvert);
-
var target2Xform:Matrix = target2.transform.concatenatedMatrix.clone();
-
target2Xform.concat(parentXformInvert);
-
-
// translate the target into the rect's space
-
target1Xform.translate(-intersectionRect.x, -intersectionRect.y);
-
target2Xform.translate(-intersectionRect.x, -intersectionRect.y);
-
-
// combine the display objects
-
var bd:BitmapData = new BitmapData(intersectionRect.width, intersectionRect.height, false);
-
bd.draw(target1, target1Xform, new ColorTransform(1, 1, 1, 1, 255, -255, -255, tolerance), BlendMode.NORMAL);
-
bd.draw(target2, target2Xform, new ColorTransform(1, 1, 1, 1, 255, 255, 255, tolerance), BlendMode.DIFFERENCE);
-
-
// find overlap
-
var overlapRect:Rectangle = bd.getColorBoundsRect(0xffffffff, 0xff00ffff);
-
overlapRect.offset(intersectionRect.x, intersectionRect.y);
-
-
return overlapRect;
-
}
Finally, if you really want some sophisticated, fully-featured, pixel-perfect collision detection *and* handling, check out Corey O'Neil's Collision Detection Kit. I haven't used it yet, but it looks pretty comprehensive with good performance.