11.1 The critter Collide method
The cCritter
class has a virtual BOOL collide(cCritter *pcritter)
method. This method does the following: (a) check if pcritter is touching the caller, and if not, return FALSE, and (b) if pcritter is touching the caller, then execute a collision with pcritter, possibly changing the health, position, and velocity of both pcritter and the caller, and when you're done return TRUE.
There are three points to get straight right way.
First of all, our collide
might better be called ifTouchingDoACollision. But that seems a bit too unwieldy.
Second, to avoid wasting time, and to keep our physics symmetric, we only want to call collide
once for each pair <pcritteri, pcritterj>. That is, we intend for the collide code of a call pcritteri->collide(pcritterj) to have a physically symmetric effect affect on pcritteri and pcritterj.
Third, as a result of the second consideration, given a pair <pcritteri, pcritterj> we're going to need some logical way of deciding whether to call pcritteri->collide(pcritterj) or to call pcritterj->collide(pcritteri).
The standard cCritter::collide
method implements (a) the law of conservation of momentum, (b) the law of conservation of energy, and (c) the law that two objects can't be in the same place at the same time. The standard collision method is also based on the assumption that the critter behaves like a sphere. We'll say more about the physics later in this chapter.
We override the collide
method for cCritterWall, as the narrow rectangular walls are not at all like disks. And other child critters may override collide
by adding on additional refinements; bullets, for instance, may damage the other object and explode. A typical collide
override like this can have the following form.
BOOL cCritterChild::collide(cCritter *pcritter)
{
BOOL collided = cCritter::collide(pcritter);
if (collided)
//Do something additional to this caller and/or to the pcritter
return collided;
}
So a typical override of collide
might call the base class version of collide
to handle the physics, and then do something extra if a collision took place. When we're done we return the BOOL
that tells whether or not a collision took place.
Here are some examples of how collide
gets overridden. First let's look at what we do with the cCritterArmedPlayer
that we commonly use for the game player. In some games, such as our Spacewar game, we want to penalize the player critter each time that it bumps into an enemy critter, such as an asteroid. To enable this, the framework gives the cCritterArmedPlayer
a BOOL _sensitive
flag and codes the collide
like this.
BOOL cCritterArmedPlayer::collide(cCritter *pcritter)
{
BOOL collided = cCritter::collide(pcritter);
if (collided && _sensitive &&
!pcritter->IsKindOf(RUNTIME_CLASS(cCritterWall)))
damage(1);
return collided;
}
Let's look at a different way of extending collide, which is used by the basket in the Ballworld game. We want the basket to be like a black hole - things that fall into it disappear. Here we have the collide
code and simply check if the argument pcritter is entirely inside the radius of the caller critter, as tested by a contains
method.
BOOL cCritterBasket::collide(cCritter *pcritter)
{
if (contains(pcritter))
//disk of pcritter is wholly inside my disk
{
pcritter->die();
return TRUE;
}
else
return FALSE;
}
The cCritterBullet
overrides collide
to handle target critters in one way and other kinds of critters in the base class way. The method depends on the fact that we give our cCritterBullet
class a BOOL isTarget(cCritter *pcritter)
method which decides if a given pcritter
is something that the bullet is willing to damage. We won't print the code for BOOL cCritterBullet::collide(cCritter *pcritter)
here, but the basic idea is the following.
If pcritter
is one of your target critters and you're touching it, damage pcritter
and die.
If pcritter
is a target and you're not touching it, do nothing.
If pcritter
isn't a target critter, collide with it normally.
As mentioned above, a cCritterWall
overrides collide
in a completely different fashion to reflect the fact that a wall isn't shaped like a sphere.
Clearly we're going to need a way to figure out which critter controls a given collision! We'll get to this soon. But first let's look at the broader issue of which pairs of critters we're going to test for collision at all.
|