Collision detection methods, hitTest and hitTestObject alternatives
Flash has never had a perfect solution to detect collisions. HitTest from ActionScript 2 has been replaced by two separate methods in ActionScript 3: hitTestObject and hitTestPoint. They are very similar to their old brother... they are still not perfect. Fortunately there are few alternative collision detection methods available, I'm going to test them here in this article.
Let's start from beginnig and see what the ActionScript 3 native hitTestObject offers.
hitTestObject
In below implementation I have two objects on the stage, polygon and circle (named polygon_mc and circle_mc). I'm going to use hitTestObject to detect collisions:
1 |
package |
And this is how it works:
As you can see Flash uses the bounding boxes of objects - it takes the highest and lowest possible points, the leftmost and rightmost points and draws a rectangle around them. Above example draws the boxes to illustrate, where Flash detects collision.
HitTestPoint
Now I changed the code a bit to detect collision between objects on the stage and a point. The biggest advantage of using this detection method is that it also checks the empty space withinn the objects boundaries. Just remember set last parameter shapeFlag as true: (shapeFlag:Boolean (default = false) — Whether to check against the actual pixels of the object (true) or the bounding box (false)).
So what's the problem with hitTestPoint? First, it tests point and object not two objects. Secondly it "doesn't see" boundaries only for vector objects, not for bitmaps. To demonstrate that, I'm going to modify our code a little to convert our vector objects to bitmaps using BitmapData (transparent bitmaps). I also added yellow box as a background to the stage to make sure bitmaps are transparent.
1 |
package |
First move mouse over the objects on the left to see that Flash "doesn't see" the boundary boxes anymore around the objects. Now, move the mouse over the pair of the objects on the right hand side to see that the same hitTestPoint method doesn't skip the boundary box around the objects anymore. Flash detects if there is any information within a point in the bounding box, no matter whether this is within the alpha channel or actual color.
Ok, Now when we know that methods given by Flash are not perfect,let's look for some alternatives?
Grant Skinner's Shape based collision detection
Very popular and well known to AS2 developers collision detection method, created by Grant Skinner is available at this address: http://www.gskinner.com/blog/archives/2005/08/flash_8_shape_b.html. This simple but effective script was ported to AS3 and is available here: http://labs.boulevart.be/index.php/2007/06/08/skinner-collision-detection-in-as3/
Let's see how is Grant Skinner algorithm working. I modified our last code by adding a line to instantiate the Collision class:
1 |
var myCollision:Collision = new Collision();
|
I also added new object to the stage, small square to follow the mouse pointer and gave it an instance name "pointer_mc". To detect collisions we call isColliding method of the Collision object:
1 |
public function checkIfHitTest(e:Event):void |
And this is the result (again objects on the right are bitmaps with transparent boundary boxes):
Well, works great for either vector or bitmap objects. But it unfortunately has major disadvantage, it won't work if you do any transformations on the target objects (like rotating, resizing). I modified my first project with circle moving with the cursor by adding Collision method and I also rotated the polygon object...
If you are curious how this 90 lines long piece of code work, have a look on my article here: Lab: Autopsy of Skinner's collision detection in AS3
Corey O'Neil's Collision Detection Kit...
I think this one is currently the most popular... You can download it from here: http://code.google.com/p/collisiondetectionkit/downloads/list. It's very easy to implement, very efficient and works great. The documentation with simple examples is available here: http://www.coreyoneil.com/Flash/CDK/documentation/
I have modified my code from the first project again. After importing the class:
import com.coreyoneil.collision.CollisionList;
and defining variable:
var myCollisionList:CollisionList;
I added our two objects. First when instantiating the collision object (let's call it target object) and next one using addItem method. I could add actually more objects using addItem and check them all against the object passed when instantiating the class. By the way another class Collision group allows to check group against group...
myCollisionList = new CollisionList(circle_mc);
myCollisionList.addItem(polygon_mc)
var collisions:Array = myCollisionList.checkCollisions();
if(collisions.length > 0)
{
If return array that is being held by collision array is non - zero, it means the collision was detected. And actually this array now holds references to all objects that collides with our target object. You can easly access it like below:
// tracing the name of the colliding object collisions[i].object1:
trace(collisions[i].object1.name);
And here is the our project compiled:
This class works very well and what is most important, it is resistant to any transformations on the MovieClips, they can be resized, rotated etc.


Comments
No w sumie tak. Tylko w box2d nie ogarniam jak zrobić animację np dla nóg postaci itp. Testowałem też WCK, ale jest podobnie, jak dodaję goToAndStop to przestaje reagować ;/
Hej, szczerze to bym wybrał jakiś silnik z fizyką, który by wszystko zrobił za mnie, Nape lub Box2d. Nie tylko detekcja kolizji juz jest zalatwiona ale sa dostepne edtory leveli gdzie mozna sobie rysowac poziom ziemii.
trace(collision s.object1.name);
i'm having problems with this.
because i have multiple gremlins added to the stage that may collide with the character, when collision occur i need to find out which gremlin it was.
but i can only show collisions[0].object1.name if i put [1] or [2] it doesnt exist.
[0] contains most of the time the name of the instance that has collided (which is good) but sometimes it contains the name of the character itself ! which is not very useful !
what am i doing wrong ?
help please
collisions.object1.name;
Can anybody help?