13.2 The ''cCritterArmed''

The cCritterArmed has the ability to shoot bullets; this is what its shoot method does.

To begin with, let's explain how the cCritterArmed::shoot gets called. The call is the responsibility of the cCritterArmed::update method, which checks if (a) the critter's _armed flag is on, meaning that it is allowed to shoot at all, and (b) the critter's _bshooting flag is on, meaning that it is supposed to shoot right now. When we use a cCritterArmed as a player, the _bshooting flag is something we normally turn on and off by pressing the space bar or the left mouse button. When we have a self-running 'robotic' cCritterArmedRobot child of the cCritterArmed class as a rival in our game, the _bshooting flag will often be continually on, with the _waitshoot time interval preventing the cCritterArmedRobot from shooting perpetually.

Here's a slightly simplified version of our cCritterArmed::update code.

void cCritterArmed::update(CPopView *pactiveview) 
{ 
//(1) Call base class update to apply force. 
    cCritter::update(pactiveview); 
//(2) Align gun with move direction if necessary. 
    if (_aimtoattitudelock) 
        setAimVector(attitudeTangent()); /* Keep the gun pointed in 
            the right direction. */ 
/* (3) Shoot if requested, and if enough time has elapsed since last 
shot. */ 
    if (_armed && _bshooting && (_age ? _ageshoot > _waitshoot)) 
    { 
        shoot(); 
        _ageshoot = _age; 
    } 
} 

To make the aim direction of the gun visible, we override and extend cCritterArmed::draw to draw a little line segment under cCritterArmed's sprite to represent the direction of the gun.

Now let's say something about what the cCritterArmed::shoot method does. We want to allow for different cCritterArmed child classes to use different kinds of bullets, so there is a CRuntimeClass *_pbulletclass variable to specify the kinds of bullets used. This means that we don't need to override the shoot method. Instead we just change the _pbulletclass. The CRuntimeClass *_pbulletclass variable is set by default in the constructor to RUNTIME_CLASS(cCritterBullet). You can find out more about the CRuntimeClass type in Chapter 22: Topics in C++. Basically it holds a string with a name of the class as well as an integer giving the size in bytes of the class instance objects.

The way _bulletclass gets used hinges on an interesting OOP feature, which allows us to create an instance of a class object from the name of the class. That is, there is a general CRuntimeClass::CreateObject method which will return an object of the type specified by the caller CRuntimeClass object.

The cCritterArmed::shoot() does the following.

  • If the shooter has more than _maxbullets active, delete the oldest one.

  • Create a pbullet with pbulletclass->CreateObject().

  • Call pbullet->initialize(this), with a pointer to the shooter as an argument.

The reason we need both the second and the third step is that the CRuntimeClass::CreateObject() doesn't take an argument; in effect it always calls a no-argument constructor. So we need the extra initialize call to feed in information from the shooter.



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