On a previous unrelated blog post, someone posted a comment that had to do with using the hitTestPoint() method with transparent images. I was about to respond by saying I don’t have any experience playing with hitTestPoint, I’m not sure why that question was posted to my unrelated post, and I don’t have an answer. While I was formulating my response in my head, I read up a bit on hitTestPoint (in the DisplayObject class) and hitTest (in BitmapData). And before I got done figuring out how to phrase “I don’t know, go ask someone else,” I thought that maybe I actually did know and figured it would be interesting to investigate a solution.
So here’s my take on DisplayObject.hitTestPoint() and BitmapData.hitTest(). At the end of the post is an example that does some hit testing on two images, one is saved as a transparent PNG and one as a SWF.
hitTestPoint
DisplayObject.hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false)
This method returns true if the point is over a transparent area of a bitmap image. Using the shapeFlag boolean makes it so the method returns false over an area of a vector image that has no shape. This is not the same thing as a transparent pixel of a bitmap image. It might be a little confusing in the documentation, but I think it makes sense (maybe it needs a sentence or two of clarification). Basically in a vector image you have no data in transparent areas. In a bitmap image there is a pixel there, and that pixel has an alpha value of 0. But that’s actually different than not having anything taking up that x,y coordinate. So the term “shapeFlag” does in fact only refer to shapes in vector images. Thank god they didn’t call it “transparentFlag” or something like that since that would make it even more confusing. It’s not about transparent pixels versus opaque pixels. It’s about “is there something there or not,” and a transparent pixel is still a pixel.
hitTest
BitmapData.hitTest(firstPoint:Point, firstAlphaThreshold:uint,
secondObject:Object, secondBitmapDataPoint:Point = null,
secondAlphaThreshold:uint = 1):Boolean
This function is confusing as hell, and I strongly suggest Adobe write some further documentation with a few examples on how to use this. This is a powerful function because you can test for a hit between a BitmapData object and multiple other types of objects (a Point, Rectangle, or another BitmapData). But it’s hard to figure out how to use it. Like, wtf does the first parameter mean (firstPoint)? I think it’s only used if you’re testing between one BitmapData and a second BitmapData. I was interested in testing a BitmapData against a point, so I just passed a point of 0,0 and it seemed to work right.
But anyway, griping about documentation aside, these two methods are different. If you’re interested in testing for a hit on a bitmap image and you don’t want to count the transparent areas, then you must use BitmapData.hitTest. You cannot use DisplayObject.hitTestPoint because that will return true for transparent pixels.
So I’ve made a simple utility class that solves this problem. I called it HitTester and what it does is it first checks for a hit using DisplayObject.hitTestPoint. If that returns true it means we’re at least within the bounding box of the image. Then it checks using BitmapData.hitTest. To do this it creates a temporary BitmapData object for the Image and runs the hitTest method.
To use the class you do something like this:
HitTester.realHitTest(image1, new Point(event.stageX, event.stageY));
The example below shows using the DisplayObject.hitTestPoint versus using my HitTester utility class. Move your mouse over the images and you can see the hit test results. Both images are basically the same, but I saved the left one as a transparent PNG and the right one is a SWF. You’ll see that the normal hitTest Point method works to accurately test for opaque areas of the SWF, but not for the PNG. The HitTest class basically just makes the hit testing of the PNG work like it does for the SWF.