Collision detection

Collisions are an inevitable fact of life in an animated world. So far, the movies we created do not know how to detect when two objects have collided or what to do when they do. This section focuses on the first issue: collision detection. Responding properly to collisions will be treated in detail in Chapter 11.

In general, collision detection can be a tricky problem, but if the objects to be tested are rectangular in shape, there is a very simple built-in method: hitTestObject().

Using the hitTestObject() method

The hitTestObject() method determines whether two display objects (such as sprites or movie clips) are in collision:

object1.hitTestObject(object2);

The outcome is a Boolean: it returns true if they do and false it they don't. So you'd typically use it as a condition in an if statement, writing code to handle the collision if it returns true.

What hitTestObject() actually does is to check whether the bounding boxes of the two display objects overlap or not. If the objects are rectangular in shape, obviously their bounding boxes coincide with their visible area, and hitTestObject() works like a dream. However, if one or both of the objects is any other shape (for example, a circle), that wouldn't be true, and hitTestObject() might return true, even in some cases when the objects are not actually touching.

Using the hitTestPoint() method

The hitTestPoint() method checks whether a given point is touching a display object. It takes two mandatory parameters and one optional parameter and returns a Boolean:

object.hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false);

The first two parameters specify the coordinates of the point to be tested against the object. The shapeFlag option tells Flash whether to test against the visible area of the object (if set to true) or against its bounding box (if false, the default).

With shapeFlag=true, this method is especially handy if one of the objects is quite small (think projectile), even if the other object has a complicated shape (think spaceship): boom!

Distance-based collision detection

This method involves checking the distance between two objects explicitly and is simplest to formulate for circular objects. We have already used a variant of this method when checking for collisions of a bouncing ball with the ground or walls. Basically, you work out, using simple geometry, the minimum distance the objects can be before they touch. Let's assume we have a circular ball with the registration point located at its center. Then the minimum distance the ball can be from a wall is equal to its radius. For example, to check if a ball hits a wall on the right side, the test would look like the following, where _wallx is the location of the wall and _radius is the radius of the ball:

if (ball.x >= _wallx - _radius){
        code to handle collision
}

If you're testing whether two circles (of radiuses r1 and r2) are colliding, you need to check if the distance between their centers is less than or equal to r1 + r2. Why the sum of their radiuses? Because that's always how far their centers are whenever there're touching. Okay, but how do we calculate the distance between the centers of the circles? This boils down to a common problem in elementary geometry—the formula for the distance between two points. Lucky for us, a Greek guy called Pythagoras worked that out a long time ago. It's called Pythagoras's Theorem. We'll take a closer look at that theorem in the next chapter. For now, here is the formula:

dist = Math.sqrt((x2 – x1)* (x2 – x1) + (y2 – y1)* (y2 – y1));

This gives the distance between two points with coordinates (x1, y1) and (x2, y2). So you take the difference between the x-coordinates and square it, do the same with the y-coordinates, add the results, and then take the square root.

Now if you're talking about two circles, (x1, y1) and (x2, y2) will be the coordinates of their centers, and are in fact equal to their x and y properties if their registration points are in the center. So, here is our condition for detecting collisions between two circles:

if (dist  <= (r1 + r2)){
       code to handle collision
}

Before you rush off to code this up, you can simplify things a bit. That Math.sqrt() is not entirely necessary, and could eat up lots of CPU time in a timer or enterframe loop. And things would get much worse if multiple objects were involved. The trick is to check for the square of dist instead:

rSquare = (r1 + r2)*(r1 + r2);

distSquare = (x2 – x1)* (x2 – x1) + (y2 – y1)* (y2 – y1);
if (distSquare  <= rSquare){
        code to handle collision
}

Note that if you only have two objects, or if all the objects have the same radius, the square (r1 + r2)*(r1 + r2) needs to be evaluated only once, outside of the time-stepping loop.

The formula for distSquare can easily be generalized to 3D:

distSquare = (x2 – x1)* (x2 – x1) + (y2 – y1)* (y2 – y1) + (z2 – z1)* (z2 – z1);

The formula for rSquare remains the same in 3D, of course.

When multiple objects are involved, you still need to check every pair of objects using the same formula.

The file CollidingBalls.as modifies BouncingBalls.as to implement this collision-detection method. Take a look at the code and have a play with the swf, but don't worry too much about the physics to deal with the collisions for now. We shall handle that in Chapter 11.

Advanced collision detection

You are now well equipped to detect collisions between to rectangular objects ((using HitTestObject), a point or small object and another object of arbitrary shape (using HitTestPoint with the shapeFlag option set to true), and two circular or spherical objects (using Pythagoras's Theorem). But what about more complex shapes?

Several clever techniques exist for testing for collisions between irregular objects. One of them is by looking at individual pixels of BitmapData objects. We refer the interested reader to Chapter 1 of Keith Peters's Advanced ActionScript 3.0 Animation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.98.249