This post began as a response to twitter user @umibose - thanks for the question!
The Starling framework handles touch/mouse events well, but out of the box it only knows whether a the event overlaps with a given displayObject. If you’ve given that object a partially transparent texture, usually you want to ignore touch events that hit the transparent part, but Starling has no way to do this. (This is because Starling has already sent the texture off to the GPU, and doesn’t retain a copy it can check the transparency of). The straightforward solution is to extend Starling’s Image class to make it save a copy of the texture, and change the hit-test logic to know about transparency, but this means storing all the textures in ActionScript memory, which can add up fast. In this post I’ll go into a simple way to get what we want with a greatly reduced memory cost.
First, we extend the starling.display.Image class so as to retain a copy of the texture that was passed in:
package { |
The next task is to add the logic to check this cached texture before generating touch events. Starling makes this quite easy by exposing a hitTest() method for just this purpose. This method returns null to mean that no hit took place, and the target of the touch event otherwise. So we simply check if the alpha value of the pixel where the event took place is above some predefined threshold:
public var alphaCutoff:int = 20; |
Now we have the functionality we want, but at the cost of storing all the textures in ActionScript memory, which could get expensive fast. But when you think about it, it’s usually not important to have pixel-perfect hit tests - especially for touch, where hit areas must be large to begin with. So we often don’t need to keep the texture at full size - we might as well scale it down before storing. (You can often scale a texture down like this by a factor of 10:1 without any noticeable difference in the hit testing.)
And since this is Flash, the scaling operation can easily be done in a line or two of code, by invoking the renderer with the bitmapData.draw()
method. With this optimization in place, our finished class looks like this:
package { |
A simple test project using this SmartImage class can be found here: Starling hitTest project
(The project contains a FLA file in CS6 format. To use with FlashBuilder just add the logic from Document.as to a fresh project.)