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 && 
    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 
        return TRUE; 
        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.

    Part I: Software Engineering and Computer Games
    Part II: Software Engineering and Computer Games Reference