13.2 The cCritterArmedThe 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.
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. |