Internet / Software Applications

Macromedia Flash MX 2004 ActionScript Programming Tutorial

Using the hitTest Method of the MovieClip Object

So far, our game is neat to look at, but it isn’t exactly a game—the user can’t do anything to stop the asteroids from coming at the ship. Furthermore, nothing happens when an asteroid appears to hit the ship. We’re going to take of the latter problem first, creating an explosion when an asteroid hits the windshield of the ship. To do this, we’re going to use another method of the MovieClip object—the hitTest method.

The hitTest method is both powerful and flexible, handling all the sophisticated means of detecting a collision for you. It detects a collision between movie clips in one of three ways:

  1. By detecting an intersection of two specified movie clips using the syntax: firstMovieClip.hitTest(secondMovieClip);
  2. By detecting an intersection of the bounding boxes of movie clips using the second clip’s x and y coordinates, with this syntax: firstMovieClip.hitTest(secondMovieClip._x, secondMovieClip._y, true);
  3. By detecting an intersection of the shapes of the movie clips, with this syntax: firstMovieClip.hitTest(secondMovieClip._x, secondMovieClip._y, false);

The hitTest method has three arguments. If you only specify one, Flash assumes it’s the name of the second movie clip. If you specify all three arguments, Flash uses the second or third method described above for detecting a collision. The third argument is shapeFlag, which tells Flash whether to use the clips’ bounding boxes or shapes to detect a collision. When set to true, it uses the bounding boxes. When set to false, it uses the shapes, which may be smaller than the bounding boxes, and which are closer to what the user sees on-screen.

However, there are problems with all these methods. With the first, Flash doesn’t always detect a collision, even when the clips appear to overlap; other times, especially in our case, the collision happens almost immediately, since the top of the ship is near the top of the stage. Like the first, the second method can cause the collision to happen too early, because even though the bounding boxes have overlapped, the shapes of the objects may not yet have met, so it won’t appear to the user that the two objects have collided. With the third, the collision can happen too late, after the objects have completely intersected.

None of these methods worked very well for our asteroids, which are animations whose positions on the stage are fairly limited. In many cases, it’s more effective to “cheat” by creating a new movie clip in the position where you want the collision detected, and use this with the hitTest method:

  1. First, we converted our ship graphic to a movie clip and added the “Explode” timeline effect to it:

The new movie clip is named “ship_clip” and the instance of it on the stage is called “ship_mc”. The Explode 3 layer contains the ship graphic in the first frame, and the Explode effect in Frames 2 through 21. While you can certainly create better explosion effects for a ship in Flash, using the Explode timeline effect was a quick and easy means of “shattering” the ship for our purposes here.

We also added an Actions layer to the movie clip, which stopped the timeline in Frame 1, where the ship graphic appears. This prevents the timeline from moving and the ship from exploding until something else happens.

Finally, we added layer between the two called “Hitspot”. This is where we’re going to add the smaller movie clip we’ll use for detecting the collision with an asteroid.

  1. After you’ve doctored your ship to create the movie clip shown above, add a “Hitspot” layer, if you haven’t already. Then create a new movie clip called “hit_clip”. The movie clip should consist of a transparent shape covering the area where a collision should be detected. Ours looks like this:

We simply drew a wide rectangle that covers the lower portion of the ship’s windshield. We converted the rectangle to a graphic symbol, the only thing contained in the hit_clip movie clip. We positioned the hit_clip movie clip over the ship’s windshield, just along the bottom, and named the instance “hit_mc”. In the Property Inspector, we made the instance transparent, rather than making the rectangle transparent, so we’re able to see the rectangle in case we need to edit it later.

  1. Exit Edit mode. The hit_mc movie clip is now located on the Hitspot layer inside the ship_mc movie clip on the main timeline.
  2. The hitTest method can be added to either of the movie clips being tested—in our case, the asteroid movie clip or the hit movie clip. Because we’re duplicating asteroids, it’s better to add the hit test to the asteroid_mc movie clip, since the collision detection code will then be duplicated for each asteroid. This keeps our coding to a minimum. Select the asteroid_mc movie clip on the stage and, in the Actions panel, add the following code (changing the names of the movie clip instances to match yours, if necessary):

onClipEvent(enterFrame) {

if(this.hitTest(_root.ship_mc.hit_mc)) {

_root.ship_mc.gotoAndPlay(2);

}

}

We used the onClipEvent(enterFrame) event to execute the action each time the movie clip timeline enters a new frame. If we’d used a different event, like the load event, the collision detection would only happen once, in the first frame, and it’s unlikely a collision would happen then. We want to test each frame as the asteroid approaches the ship.

The hit test itself is contained in a simple if statement. If the asteroid (this) “hits” the hit_mc movie clip (_root.ship_mc.hit_mc), then Flash should go to and play Frame 2 of the ship_mc movie clip. Frame 2 is the beginning of the Explode effect.

  1. Save and test the movie. Press the play button and watch the first asteroid collide with the ship, shattering it to pieces. You may need to tweak your asteroid animation to make sure it meets the hit location, or you can tweak the size of your hit location movie clip.
  2. Once the asteroid hits the ship, we need a mechanism to stop more asteroids from coming. The simplest way to change the movie’s state to “game over” is to add a second frame to our main timeline. Below, we’ve added simple static text to Frame 2 that says “Game Over”:

  1. Add a stop action to both Frame 1 and Frame 2 of the main timeline to keep the timeline from progressing past either frame until an event causes it to do so.

  1. Next, we’re going to create a function on the main timeline to remove the existing movie clips when the ship explodes. Remember that earlier we included a loop in the makeAsteroid() function that removes all 10 asteroids. But if the ship explodes before all 10 asteroids are created, the num_clips variable won’t yet be 10, and so the loop will never execute. We’ll remove what asteroids have been created using a new “stopAsteroids” function:

function stopAsteroids() {

clearInterval(asteroidInterval);

do {

//remove the current asteroid movie clip

_root[“asteroid_mc” + num_clips].removeMovieClip();

//decrement the movie clip counter

num_clips–;

} while (num_clips >= 0);

}

  1. Now open up the ship_mc movie clip instance and add a keyframe to the last frame of the Actions layer. There, insert the following code:

_root.stopAsteroids();

_root.play();

The first line calls the stopAsteroids() function on the main timeline, which removes the asteroid movie clips. The second line starts the main timeline playing again, which will send the movie to Frame 2, where it stops to display “Game Over”.