Wednesday, February 2, 2011

Simple AS3 Collision Detection Using the AS3 hitTestObject() Method

In this tutorial, we're going to learn how to create basic AS3 collision detection using the AS3 hitTestObject() method of the MovieClip class. Collision detection refers to the process of checking whether 2 or more objects are hitting each other - if parts or the whole of each object are occupying the same space on the stage (i.e. if they are overlapping). For this exercise, we'll put two square shaped MovieClip instances on the stage and make one of them draggable. When the user drags and then drops that instance, Flash will check whether the user moved it to a new location where it is now hitting the other instance.

Let's begin.

  1. Create a new Flash ActionScript 3 document.
  2. Draw a square shape on the stage and convert it into a Movie Clip symbol.
  3. Put a total of 2 instances of this Movie Clip symbol on the stage.
  4. In the Properties Inspector, give one of them an instance name of square1_mc, and give the other one an instance name of square2_mc.
  5. Create a new layer for the ActionScript.
  6. Bring up the Actions panel and add the following code:
square1_mc.addEventListener(MouseEvent.MOUSE_DOWN, drag);
stage.addEventListener(MouseEvent.MOUSE_UP, drop);

function drag(e:MouseEvent):void
{
 e.target.startDrag();
}

function drop(e:MouseEvent):void
{
 stopDrag();
 if (square1_mc.hitTestObject(square2_mc))
 {
  trace("Collision detected!");
 }
 else
 {
  trace("No collision.");
 }
}
When you test the movie, you should be able to drag and drop the square1_mc MovieClip instance. And when you drop it, Flash will check whether it's hitting the other MovieClip instance or not. If they are hitting, you will see a message in the Output window that says: Collision detected! If they are not hitting, the message you will see is: No collision.

Here's the same code for our simple AS3 collision detection using the AS3 hitTestObject() method, but with comments:
/*You can use the AS3 hitTestObject() method of the MovieClip class
to test whether 2 objects are hitting each other. Hitting refers
to whenever objects collide or overlap on the stage.

Example:
mc1.hitTestObject(mc2);

The example above tests whether mc1 and mc2 are overlapping.
This statement returns a boolean value - true if the objects
are hitting and false if they are not. You can use this method
in an if statement condition.

In this example, we should have 2 MovieClip instances on the stage -
square1_mc and square2_mc.
We are going to make the square1_mc MovieClip
draggable. And when the user drops it, Flash will
check whether square1_mc and square2_mc are hitting.*/

/*Add the MOUSE_DOWN event listener to the MovieClip
instance that we would like to make draggable.*/
square1_mc.addEventListener(MouseEvent.MOUSE_DOWN, drag);

/*Add the MOUSE_UP event listener to the stage.*/
stage.addEventListener(MouseEvent.MOUSE_UP, drop);

/*This event listener function will make the first
MovieClip instance draggable.*/
function drag(e:MouseEvent):void
{
 e.target.startDrag();
}

/*This event listener function disables the dragging.
It also checks whether the MovieClip instance being dragged
overlaps with the other MovieClip instance after
it was dropped.*/
function drop(e:MouseEvent):void
{
 /*Drops the MovieClip that's currently being dragged.*/
 stopDrag();
 
 /*This if statement uses the AS3 hitTestObject() method to check
 whether the first MovieClip instance is hitting the 
 second one.*/
 if (square1_mc.hitTestObject(square2_mc))
 {
  /*Flash outputs this message if they are 
  hitting each other.*/
  trace("Collision detected!");
 }
 else
 {
  /*Flash outputs this message if they are 
  NOT hitting each other.*/
  trace("No collision.");
 }
}
And that concludes this tutorial on creating simple AS3 collision detection using the AS3 hitTestObject() method.

14 comments:

  1. it helps me a lot.....thanks for such great tutorial

    ReplyDelete
  2. very good one,but can u tell me how to avoid object from overlapping on other object when collision occurs?

    ReplyDelete
    Replies
    1. Once you know the two objects have hit you can give one of the objects new coordinates based on the overlap.

      if (square1_mc.hitTestObject(square2_mc))
      {
      square1_mc.x = square2_mc.x + square2_mc.width;
      }

      that code will move square1 to the right of square2, you can then write an if statement that checks to see if the object should snap to the right or the left of the object it's overlapping, but that's the basic way of doing what you are asking.

      Delete
  3. thxs this helped me with my h/m

    ReplyDelete
  4. Very useful tutorial! should be great for game developing.

    But when I make the objects very freeform (squiggles), sometimes it outputs "Collision Detected" even when they are not QUITE overlapping, just close.

    ReplyDelete
    Replies
    1. Hi, Anon.

      That's because the hitTestObject() method looks at the movie clip's rectangular bounding area, instead of the actual shape. I've been meaning to figure out how to create collision detection for irregularly shaped objects, but haven't had the time. But you can try doing some research on the hitTestPoint() method. This one has a parameter that lets you say if you want to test with the actual shape inside the movie clip. However, this method tests only a single point against a movie clip. Whereas the hitTestObject() method tests one whole movie clip against another, but again, it does not have the shape flag parameter. It would have been great if they could have combined these two methods. :)

      Delete
  5. This helped me a bunch! :)

    What about when you have a "character" moving with arrows, and you have some sort of bomberman like map? How do I make it verify if collision is detected anytime he hits a wall? I tried giving every piece of the wall the same instance name so that whenever the character collided with that instance, the character would stop. But unfortunatelly it only detects collision on the last created object :(
    Help? lol

    ReplyDelete
  6. Wow! I got it!!
    Moving a character with arrows and making it stop as it hits a wall withought bugging:


    import flash.events.Event;

    stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_PressKeyToMove);

    function fl_PressKeyToMove(event:KeyboardEvent):void
    {
    switch (event.keyCode)
    {
    case Keyboard.UP:
    {
    char_mc.y -= 15;
    if (char_mc.hitTestObject(shelf_mc))
    {
    char_mc.y +=15 ;
    }
    break;
    }
    case Keyboard.DOWN:
    {
    char_mc.y += 15;
    if (char_mc.hitTestObject(shelf_mc))
    {
    char_mc.y -=15 ;
    }
    break;
    }
    case Keyboard.LEFT:
    {
    char_mc.x -= 15;
    if (char_mc.hitTestObject(shelf_mc))
    {
    char_mc.x +=15 ;
    }
    break;
    }
    case Keyboard.RIGHT:
    {
    char_mc.x += 15;
    if (char_mc.hitTestObject(shelf_mc))
    {
    char_mc.x -=15 ;
    }
    break;
    }
    }
    }

    ReplyDelete
  7. Movie clip's rectangular bounding area creating problem.... is there any solution for this?????
    hitTestPoint() method is also not working because it detect the collision only when the object's pivot point hits the pivot ponit of hitObject..
    Pls let me know if anyone has the solution for this....

    ReplyDelete
  8. thanks a lot, this made possible my flash rpg. :)

    ReplyDelete
  9. Thanks a lot!!! No words.. very very good...

    ReplyDelete
  10. AS3/CS6 (does not work): One of the reasons I believe hitTestObject does not work in Flash CS6/Flash Builder is because when one runs the 'app' for the first time objects are not 'activated'. EXAMPLE: a square drops from the top...when it collides with another square at the bottom and using hitTestObject..it should work...but it won't...why?, because the falling square is 'active' but mysteriously the bottom square is not...once we 'touch' that lower object...then it becomes 'active' : QUESTION IS: HOW DOES ONE MAKE OBJECTS 'VISIBLY ACTIVE' WHEN WE RUN OUR APP? - hitTestObject in my experience has not worked 99 percent of the time and the code will be correctly scripted.

    ReplyDelete
    Replies
    1. Is this specific example giving you problems in CS6?

      Delete