The cSpriteLoop and cSpriteDirectional sprites are arrays of other sprites. As they inherit from cSpriteComposite they have an add method that adds new sprites into the array. You can feed cSpriteComposite::add method either a cSprite * pointer as an argument or simply an integer resource ID number as an argument ? in the latter case the add(resourceID) method constructs a new cSpriteIcon(resourceID) and then adds that sprite.
People often want to use sequences of bitmaps for their sprites. Suppose you have three successive bitmaps for a walking man and that you've saved them as resources with IDs of the form IDB_MAN1. To simplify things the Pop Framework lets you pass in a resource ID as the argument to add. A cCritter constructor could make and use such a sprite like this.
cSpriteLoop pmanwalk = new cSpriteLoop(); pmanwalk->add(IDB_MAN1); pmanwalk->add(IDB_MAN2); pmanwalk->add(IDB_MAN3); setSprite(pmanwalk);
The cSpriteLoop ::animate method ages a time counter and adjusts the active sprite accordingly. The effect is that cSpriteLoop flips from one image to the next. The default wait between images is a fifth of a second, or 0.2. You can change this wait time with the cSpriteLoop::setFlipwait(Real flipwait) method.
Note that the flipping is based on the real time elapsed and not on the number of updates you've done. This keeps our program appearance from being dependent on the speed of the processor. You never want to do anything on basis of cycle-counts. Always use the time.
The cSpriteDirectional is initialized much like the cSpriteLoop. We create a new cSpriteDirectional object and then use its add method, passing either cSprite* pointers or bitmap resource ID numbers to the add.
The way the cSpriteDirectional picks which sprite to show is to look at the direction the critter that owns the sprite is pointing in. It distinguishes as many directions as the number of sprites that you added.
The cSpriteDirectional ::animate adjusts the active sprite according to the current critterdirection. It uses the animate method to select one among several directional bitmaps, as shown in Figure 9.4.
Use of the cSpriteDirectional gets around the fact that we can't rotate bitmaps on the fly in Windows graphics; a cSpriteDirectional can store various differently rotated versions of a bitmap. This is not an issue in OpenGL graphics, however the use of bitmaps does tend to slow OpenGL down more than is comfortable.
If you're ambitious, you can make a cSpriteDirectional whose members are cSpriteLoop animations. If you do this, don't forget that you need to create fresh sprite objects for each critter. It's fine to reuse the same resource ID, but you have to wrap them up in fresh sprites. To avoid having to write out the same code more than once, you should create and install the sprite inside your critter constructor. If you happen to have two different critters that will use the same complicated sprite, you might save code writing by making a new cSprite child class whose constructor carries out the complicated initialization.
As was mentioned above, the cGraphicsMFC and cGraphicsOpenGL allocate the cSpriteIcon resources in a memory-efficient way. Note also that they automatically rescale the size of your cSpriteIcon bitmaps when you resize the window.