8.5 The full ''cCritter'' prototype

Here's a full listing of the cCritter prototype from a recent critter.h header file. For the most current listing, you can examine the file itself inside Visual Studio.

////////////////////////////////////////////////////////////////////// 
// Critter.h: interface for the cCritter class. 
// 
////////////////////////////////////////////////////////////////////// 
#ifndef CRITTER_H 
#define CRITTER_H 
#include "randomizer.h" 
#include "realbox.h" 
#include "realpixelconverter.h" 
#include "vectortransformation.h" 
#include <mmsystem.h> //For PlaySound flags 
class cGraphics; 
#define USEBOUNCINESS /* Compile switch used in critter.cpp, 
critterwall.cpp, realbox.cpp. */ 

    /* We don't need to include the headers for the following classes 
    as we only mention them as pointers. In general, we only include a 
    header in a header if we absolutely have to. Here we can get by 
    with forward class declarations that simply say such and such a 
    class exists. Of course we will need to include the headers in 
    the critter.cpp which is where we actually use the properties of 
    these classes. */ 
class cBiota; //For the *_pownerbiota member. 
class cSprite; //For the *_psprite member. 
class cListener; //For *_plistener member. 
class cForce; //For _forcearray member. 
class cDistanceAndDirection; 
    // Return type of the distanceAndDirection function. 
class CPopView; //Used as an argument to sniff. 
class cGame; //For the return type of the pgame() method. 
class cGraphics; //For the draw method. 

class cCritter : public CObject 
{ 
DECLARE_SERIAL(cCritter); /* An MFC macro used to enable 
    CRuntimeClass reflection of class type, dynamic creation, 
    and serialization. */ 
public: 
// Statics ======================================== 
//Constant Statics ================================ 
    //The MF_ statics are mutation flags used in the mutate methods. 
    static const int MF_NUDGE; 
    static const int MF_POSITION; 
    static const int MF_VELOCITY; 
    static const int MF_ALL; //MF_POSITION | MF_VELOCITY 
    /* Wrapflag values specify possible behaviors when critter hits 
        edge of world. */ 
    static const int BOUNCE; 
    static const int WRAP; 
    static const int CLAMP; 
    /* special high density used for player or other immovable critter. */ 
    static const Real INFINITEDENSITY; 
//Variable Statics ================================ 
    //These might (rarely) be reset by a cGame constructor. 
//Motion Statics ================================ 
    static Real MINSPEED; //Used in randomizing critter _speed. 
    static Real MAXSPEED; /* Used in randomizing, and to clamp _speed 
        in move(dt). */ 
    static Real MINTWITCHTHRESHOLDSPEED; 
        //Default for _mintwitchthresholdspeed 
    static Real NEAREDGEPERCENT; // Default arg for moveToMoveboxEdge. 
    static BOOL STARTWRAPFLAG; 
    static Real DENSITY; //Default density. 
//State Statics =============================== 
    static Real MUTATIONSTRENGTH; //Default argument to mutate method. 
    static Real MINRADIUS; //Used in randomizing 
    static Real MAXRADIUS; 
    static Real BULLETRADIUS; /* Gets set to cGame::BULLETRADIUS in 
        cGame constructor. */ 
    static Real PLAYERRADIUS; 
    static Real LISTENERACCELERATION; 
        //Default for _listeneracceleration 
    static int STARTHEALTH; //Default is 1. 
    static Real SAFEWAIT; /* Time in seconds of invulnerability, use 
        at start up and after damage, gives critters breathing room so 
        they don't get damaged twice in a row, like by the same bullet 
        volley. */ 
    static Real FIXEDLIFETIME; /* Default lifetime for critters with 
        _usefixedlifetime TRUE. */ 
protected: 
//================================================= 
//State Fields. =================================== 
//================================================= 
    Real _age; /* Measure in seconds of time simulated, start at 0.0 
        when constructed. */ 
    BOOL _usefixedlifetime; 
        //If TRUE, then die when _age > _fixedlifetime. 
    Real _fixedlifetime; 
        //Max lifetime in seconds, applies only if _usefixedlifetime. 
    int _health; /* Lose by being hit and taking damage(). Usually die 
        when _health is 0. */ 
    BOOL _shieldflag; //Immunity to damage() calls. 
    UINT _personality; /* Random bits to sometimes use for making 
        critters have different behaviors, as when using evasion 
        forces. */ 
    Real _mutationstrength; /* Number between 0.0 and 1.0 controlling 
        how different a spawned copy will be. */ 
    cCritter *_ptarget;/* In case you are following or dragging or 
        watching or aimed at someone else, use this field to track 
        them. _ptarget is one of the only fields that is NOT 
        serialized. We use the _targetindex with the _pownerbiota to 
        copy or serialize _ptarget. */ 
//================================================ 
//Game Fields =================================== 
//================================================ 
    cBiota *_pownerbiota; /* Used in makeServiceRequest and in other 
        places. It allows the critter to be aware of all the other 
        critters. Gets set by the cCritter(cGame *pownergame) 
        constructor. _pownerbiota is NOT serialized. */ 
    int _score; //Usually gain by eating or shooting others. 
    int _value; //Value to another critter shooting or eating this one. 
    int _newlevelscorestep; 
        //Step size between score levels that are rewarded. 
    int _newlevelreward; //Health reward for new score level. 
//================================================ 
//Motion Fields. ================================== 
//================================================ 
//Position Fields ================================= 
    cVector _position; 
    cRealBox _movebox; //Keep critter inside _movebox. 
    cRealBox _dragbox; /* Usually same as _movebox, but in 
        cGamePickNPop, it's bigger, so can drag a critter outside of 
        its _movebox. */ 
    int _wrapflag; //BOUNCE, WRAP, or CLAMP when you bump a wall. 
    int _outcode; /* Flag info about which wall, if any, the last 
        move bumped. */ 
//Velocity Fields ================================ 
    BOOL _fixedflag; //Refuse to move. 
    cVector _velocity; 
    Real _speed; 
    cVector _tangent; /* We always keep _velocity = _speed * _tangent. 
        It's useful to have _tangent around even when _speed goes to 0 
        and _velocity is zero, this way we know what direction to 
        start back up in. */ 
    cVector _normal; /* We maintain a _normal and _binormal vector to 
        fully express themotion of the critter through 3D space. */ 
    cVector _binormal; //Always cVector::ZAXIS in 2D worlds. 
    Real _maxspeed; //Clamp _speed below this in move(). 
    Real _maxspeedstandard;/* In case _maxspeed might be temporarily 
        increased, for instance if the critter is allowed to move 
        extra fast while fleeing or chasing another. */ 
//Acceleration Mass, and Force Fields ============================== 
    cVector _acceleration; /* _acceleration gets reset during every 
        cycle, using the _forcearray and possibly the _plistener to 
        change it. */ 
    Real _mass; /* Use fixMass() helper to maintain _mass = _density * 
        radius()^3. */ 
    Real _density; /* Default is 1. We often assign the cCritterPlayer 
        a very large _density so that it can whack others around. */ 
    CTypedPtrArray<CObArray, cForce*> _forcearray; 
        //We serialize this array 
//Listener Fields. ================================ 
    cListener *_plistener; //Never NULL. We serialize the plistener. 
    Real _listeneracceleration; /* This is the acceleration used by 
        listeners such as cListenerCar and cListenerSpaceship that 
        "drive" the critter around. Like the critter's engine 
        strength. */ 
//Collision Fields ================================ 
    Real _collidepriority; 
    /* These are default cCritter _collidepriority values, in 
        increasing size for increasingly high priority, where in a 
        pair of critters, the higher priority critter is the caller of 
        the collide method, and the lower priority critter is the 
        argument to the collide call. */ 
    Real _absorberflag; /* Don't change your own velocity after a 
        collision. This siphons energy out of the system, cooling 
        down the motions by absorbing it. */ 
    Real _bounciness; /* ranges from 0.0 to 1.0. Determines how 
        elastically you bounce off of walls    or off of other 
        critters.  1.0 is perfect bounce, 0.9 is pretty reasonable, 
        0.0 don't bounce at all. */ 
    Real _mintwitchthresholdspeed; /* If we have 
        _attitudetomotionlock, and we have some critters barely 
        bouncing on a "floor" it looks bad if they keep twitching 
        their orientation up and down. Don't change the _attitude 
        to match the motion if the speed is less than 
        _mintwitchtriggerspeed. */ 
//============================================== 
//Attitude and Display Fields ============================ 
//============================================== 
    cSprite *_psprite; //Never NULL. We serialize the _psprite. 
    BOOL _attitudetomotionlock; /* Shall I lock together the display 
        sprite and the motion? By default the player has 
        _attitudetomotionlock FALSE and all other critters have it 
        TRUE. */ 
    cMatrix _attitude; /* The attitude expresses the way that the 
        critter is situated for rendering. When _attitudetomotionlock 
        is TRUE, _attitude has the columns _tangent, _normal, 
        _binormal, _position. If _attitudetomotionlock is FALSE, 
        _attitude can be instead controlled by _spin or by the 
        _plistener actions. */ 
    cSpin _spin; /* A cSpin holds the spinangle in radians per 
        second and the spinaxis which is the axis to spin around 
        (z by default). Presently used only when _attitudetomotionlock 
        is OFF. */ 
    Real _defaultprismdz; /* We copy this into the psprite's _prismdz 
        field in setSprite. If we are in 3D and if the sprite is, for 
        instance, a polygon that makes use of the _prismdz field, then 
        _prismdz will determine the z-thickness of the sprite. */ 
//============================================= 
//Bookkeeping Fields =============================== 
//============================================= 
//Serialized Bookkeeping Fields =============================== 
    Real _lasthit_age; /* Age at last hit (or age at birth), use to 
        time invulnerability. */ 
    BOOL _oldrecentlydamaged; /* Used in update() in connection with 
        sprite display lists. */ 
    cVector _oldposition; 
        //This is used by the cCritterWall::collide method. 
    cVector _oldtangent; 
        //This is used by the cCritter::fixNormalAndBinormal method. 
    cVector _wrapposition1, _wrapposition2, _wrapposition3; 
        //Use for showing wrap in 2D 
    int _targetindex; /* _targetindex is a dummy used to copy and 
        serialize the _ptarget pointer reference. */ 
//Nonserialized Bookkeeping Fields ============================ 
    int _metrickey; /* Index into the _pownerbiota cBiota's _metric, 
        can be used to look up metric values. _metrickey is NOT 
        serialized. Uspd if #define USEMETRIC*/ 
public: 
//================================================== 
//Constructor and destructor and helpers ========================== 
//================================================= 
    cCritter(cGame *pownergame = NULL); /* Initializes fields, adds 
        to pownergame if not null. With the NULL default for the 
        pownergame argument, this constructor doubles as a no-argument 
        constructor. */ 
    virtual void copy(cCritter *pcritter); /* Helper function for copy 
        constructor, and for clone method. */ 
    cCritter(cCritter *pcritter); //copy constructor 
    cCritter* clone(); /* Returns a pointer to a cCritter of the same 
        child class type, with the same info in it. */ 
    virtual ~cCritter(); /* deletes pointer members and calls 
        cBiota::removeReferencesTo(this). The destructor is virtual 
        so that child critter destructors can do extra cleanup before 
        the baseclass destructor. */ 
    void removeReferencesTo(cCritter *pdeadcritter); /* Don't let 
        pdeadcritter be the _ptarget or the pnode() of any 
        cForceObject in the _forcearray. */ 
//============================================= 
//Mutators ================================ 
//============================================= 
//State Field Mutators ============================== 
    void setValue(int value){_value = value;} 
        /* The velocity, direction, and speed mutators always keep 
            _velocity = _speed * _tangent. */ 
    void setShield(BOOL shield){_shieldflag = shield;} 
    void setUseFixedLifetime(BOOL yesno){_usefixedlifetime = yesno;} 
    void setFixedLifetime(Real lifetime){_fixedlifetime = lifetime;} 
    void setMutationStrength(Real mutationstrength){_mutationstrength 
        = mutationstrength;} 
    virtual void setTarget(cCritter *pcritter){_ptarget = pcritter;} 
        /* Comes in handy sometimes, though more often I'll use a 
        cForceObject. */ 
    void setMetricKey(int i){_metrickey = i;} 
    virtual void reset(); //can override to do special things. 
    virtual void setAge(Real age){_age = age; _lasthit_age = _age ? 
        cCritter::SAFEWAIT;} //overridden by cCritterArmedRobot. 
//Game Field Mutators =================================== 
    void setOwner(cBiota* pownerbiota){_pownerbiota = pownerbiota;} 
        //Used in Add and CBiota::Serialize 
    virtual void addScore(int scorechange); 
    void setHealth(int health){_health = health; 
        if(_health<0)_health=0;} /* We can add health points at 
        certain score levels. */ 
    void setNewlevelreward(int healthgain){_newlevelreward = 
        healthgain;} 
    void setNewlevelscorestep(int pointspread){_newlevelscorestep = 
        pointspread;} 
//=============================================== 
//Motion Field Mutators ============================== 
//=============================================== 
//Position Field Mutators ============================= 
    int setMoveBox(const cRealBox &box); 
    void setDragBox(const cRealBox &box){_dragbox = box;} 
    virtual void setWrapflag(int wrapflag); 
        //We have a kludge override for cCritterWall 
    virtual int moveTo(const cVector &newposition, BOOL 
        treatascontinuousmotion = FALSE); /* Do the move, 
        and then clamp against _movebox, return outcode of 
        clamp. */ 
    virtual int moveToZ(Real z){return moveTo(cVector(_position.x(), 
        _position.y(), z));} /* I use moveToZ in 
        cGamePickNPop::seedCritters. */ 
    virtual int moveToProportional(const cVector &newposition, 
        Real proportion, BOOL treatascontinuousmotion = FALSE); 
        /* Proportion between 0.0 and 1.0 is how much of the way 
        you want to move towards newposition. */ 
    virtual int dragTo(const cVector &newposition, Real dt); 
        /* Move and clamp against _dragbox, return outcode. In 
        addition, use dt to set critter velocity to match the drag 
        velocity. I make it virtual so cCritterWall can override to 
        NOT change the velocity. */ 
    void moveToMoveboxEdge(Real percent = cCritter::NEAREDGEPERCENT); 
        /* Useful in some games, to start a critter near the _movebox 
            edge. */ 
//Velocity Field Mutators ============================ 
    void setFixedflag(BOOL flag){_fixedflag = flag;} 
    void setVelocity(const cVector &velocity); 
    void addVelocity(const cVector velocitychange) 
        {setVelocity(_velocity + velocitychange);} 
    void setTangent(const cVector &direction); 
    void rotate(const cSpin &spin); /* cSpin is a way to express 
        general 3D angles. */ 
    void yaw(Real turnangle); //Rotate around _binormal. 
    void roll(Real turnangle); //Rotate around _tangent 
    void pitch(Real turnangle); //Rotate around _normal 
    void orthonormalize(); /* Make sure _tangent, _normal, _binormal 
        are orthogonal units. */ 
    void setSpeed(Real speed); 
    void setMaxspeed(Real maxspeed) 
        {_maxspeed = _maxspeedstandard = maxspeed;} 
    void setTempMaxspeed(Real maxspeed){_maxspeed = maxspeed;} 
    void restoreMaxspeed(){_maxspeed = _maxspeedstandard;} 
//Acceleration, Mass and Force Field Mutators ====================== 
    void setAcceleration(const cVector &acceleration) 
        {_acceleration = acceleration;} 
    void addAcceleration(const cVector &acceleration) 
        {_acceleration += acceleration;} 
    void setDensity(Real density){_density = density; fixMass();} 
    void fixMass(); //Keep _mass = _density * _radius()^3. 
    void addForce(cForce *pforce); 
    void clearForcearray(); 
    void copyForcearray(cCritter *pcritter); /* This helper method 
        will empty the existing force array and copy all of the forces 
        in the pcritter force array. */ 
    virtual void copyPhysicsForces(cCritter *pcritter); /* A more 
        modest kind of force copying. Here we don't wipeout the 
        existing forces in the caller, and we only copy the "physics" 
        forces like cForceGravity and cForceDrag from pcritter. Use 
        the BOOL cForce::isGlobalPhysicsForce() to tell us which ones. 
        We need this method so that bullets can copy the physics of 
        their shooters but not their behavioral forces. */ 
//Listener Field Mutators ================================== 
    void setListener(cListener *plistener); 
    void setListenerAcceleration(Real la){_listeneracceleration = la;} 
//Collision Field Mutators =================================== 
    void setMinTwitchThresholdSpeed(Real twitchspeed) 
        {_mintwitchthresholdspeed = twitchspeed;} 
    void setBounciness(Real bounciness) 
        {CLAMP(bounciness, 0.0, 1.0); _bounciness = bounciness;} 
    void setAbsorberflag(BOOL flag) 
        {_absorberflag = flag; 
        _absorberflag?_bounciness=0.0:_bounciness=1.0;} 
    void setCollidePriority(Real collidepriority); 
        //Rebuild the pgame()->_pcollider just in case. 
//=================================================== 
//Attitude and Display Field Mutators =============================== 
//=================================================== 
    void setSprite(cSprite *psprite); 
    void setSpin(cVector3 spinvector){_spin = cSpin(spinvector);} 
    void setAttitudeToMotionLock(int lockmode) 
        {_attitudetomotionlock = lockmode;} 
    void setSpin(Real spinangle, cVector3 spinaxis = cVector::ZAXIS) 
        {_spin = cSpin(spinangle, spinaxis);} 
    void rotateAttitude(Real angle); 
        //{_attitude *= cMatrix::rotation(angle);} 
    void rotateAttitude(cSpin &spin); 
        //{_attitude *= cMatrix::rotation(spin);} 
    void setAttitude(const cMatrix &attitude); /* This changes the 
        orientation aspect of _attitude, but NOT the _position 
        aspect, that is, it leaves the last column alone. */ 
    void resetAttitude(); /* Assume the identity orientation. */ 
    void setAttitudeTangent(const cVector &tangent); /* points 
        _attitude in tangent direction. If _attitudetomotionlock is 
        TRUE, we move _tangent to match. */ 
    void copyMotionMatrixToAttitudeMatrix(); 
    void copyAttitudeMatrixToMotionMatrix(); 
    BOOL lookAt(const cVector &targetpos); /* Aim attitudeTangent 
        at targetpos, and try and perverse attitudeNormal while 
        you're at it. Return FALSE if the targetpos is right on 
        top of you, preventing you from looking at it, else return 
        TRUE. */ 
    BOOL lookAtProportional(const cVector &targetpos, Real 
        proportion); /* Proportion is between 0.0 and 
        1.0 specifying how far towards targetpos you turn 
        to look. */ 
    int setRadius(Real radius); 
    void setPrismDz(Real prismdz); /* Sets _defaultprismdz and the 
        current _psprite->_prismdz. */ 
//=========================================== 
//Randomizing mutators =========================== 
//=========================================== 
    void randomizePosition( const cRealBox &startbox); 
    void randomizePosition(){randomizePosition(_movebox);} 
    void randomizeRadius(Real minradius, Real maxradius) 
        {setRadius(cRandomizer::pinstance()->randomReal(minradius, 
            maxradius));} 
    void randomizeVelocity(Real speed); 
    void randomizeVelocity(Real minspeed, Real maxspeed); 
    void randomizeVelocity(){randomizeVelocity(MINSPEED, _maxspeed);} 
    void randomizeSpin(Real minspeed, Real maxspeed); 
    virtual void mutate(int mutationflags, Real mutationstrength); 
        /* Mutate flagged position, velocity and sprite properties by 
        an amount specified in mutationstrength. */ 
    void mutate(int mutationflags) 
        {mutate(mutationflags, _mutationstrength);} /* Uses the member 
        _mutationstrength, which defaults to 0.6. */ 
    void randomize(int mutationflags){mutate(mutationflags, 1.0);} 
        //1.0 is maximum. 
//============================================== 
//Accessors ================================= 
//============================================== 
//State Field Accessors ============================== 
    Real mutationStrength()const{return _mutationstrength;} 
    int value()const{return _value;} 
    unsigned long personality()const{return _personality;} 
    BOOL shield()const{return _shieldflag;} 
    BOOL usefixedlifetime(){return _usefixedlifetime;} 
    Real fixedlifetime(){return _fixedlifetime;} 
    Real age()const{return _age;} 
    BOOL recentlyDamaged(){return (_age ? _lasthit_age) < SAFEWAIT;} 
//Game Field Accessors ================================= 
    cBiota* pownerbiota()const; 
    virtual cGame* pgame()const; /*Normally this will just return 
        _pownerbiota->pgame(), but in the case of a cCritterViewer 
        associated with a CPopView we use a different path to the 
        cGame.*/ 
    cCritter* ptarget()const{return _ptarget;} 
    cCritter* pplayer(); /* return pgame()->pplayer(), in other words 
        the player of the game that this critter belongs to. */ 
    int score()const{return _score;} 
    int health()const{return _health;} 
//=============================================== 
//Motion Field Accessors ============================== 
//=============================================== 
//Position Field Accessors ============================== 
    cVector position() const {return _position;} 
    cVector oldposition() const {return _oldposition;} 
    cPlane plane()const{return cPlane(_position, _binormal);} 
    int wrapflag()const {return _wrapflag;} 
    cRealBox moveBox()const{return _movebox;} 
    cRealBox dragBox()const{return _dragbox;} 
    cRealBox realBox(); //Smallest box holding the sprite. 
    virtual BOOL draggable(){return TRUE;} /* Used to see if a critter 
        is willing to be dragged in cGame::onLButtonDown. If you ever 
        want a non-draggable critter child class, override draggable 
        to return FALSE. */ 
    BOOL in3DWorld(); //Tells you if the owner game has a z-Thickness. 
//Velocity Field Accessors ================================== 
    BOOL fixedflag()const{return _fixedflag;} 
    cVector velocity() const {return _velocity;} 
    cVector tangent() const {return _tangent;} 
    cVector normal() const{return _normal;} 
    cVector binormal() const{return _binormal;} 
    Real speed()const {return _speed;} 
    Real maxspeed()const {return _maxspeed;} 
    Real maxspeedstandard()const {return _maxspeedstandard;} 
//Acceleration, Force and Mass Field Accessors ======================= 
    cVector acceleration() const {return _acceleration;} 
    Real density()const{return _density;} 
    CTypedPtrArray<CObArray, cForce*>* pforcearray() 
        {return &_forcearray;} 
//Listener Field Accessors ================================ 
    cListener* plistener()const{return _plistener;} 
    Real listeneracceleration()const{return _listeneracceleration;} 
//Collision Field Accessors ================================= 
    Real minTwitchThresholdSpeed(){return _mintwitchthresholdspeed;} 
    Real bounciness(){return _bounciness;} 
    BOOL absorberflag()const{return _absorberflag;} 
    Real mass()const{return _mass;} 
    Real collidePriority(){return _collidepriority;} 
//=============================================== 
//Attitude and Display Field Accessors =========================== 
//=============================================== 
    cSprite* psprite() const{return _psprite;} 
    Real radius() const; 
    cSpin spin()const{return _spin;} 
    cMatrix attitude(){return _attitude;} 
    cVector attitudeTangent()const {return _attitude.column(0);} 
    cVector attitudeNormal()const {return _attitude.column(1);} 
    cVector attitudeBinormal()const{return _attitude.column(2);} 
    BOOL attitudetomotionlock() const{return _attitudetomotionlock;} 
    Real defaultprismdz()const{return _defaultprismdz;} 
//================================================ 
//Bookkeeping Field Accessors ================================== 
//================================================ 
    int metrickey()const{return _metrickey;} 
//================================================ 
// Serialize methods ============================== 
//================================================ 
    virtual void Serialize(CArchive &ar); 
//================================================ 
// Helper methods ================================== 
//=============================================== 
//Service Request Methods ========================================== 
    /* The point of these is that if a critter is do something that 
        affects the set of critters as a whole, we want it to let the 
        cBiota* _pownerbiota do it, so that all critter changes are 
        coordinated. So critter just passes this request to its 
        _pownerbiota, and later _pownerbiota calls 
        cBiota::processServiceRequests. */ 
    void makeServiceRequest(CString request); 
    void add_me(cBiota *pownerbiota, BOOL immediateadd = FALSE); 
        /* Make a request to the pownerbiota to add yourself to its 
        array, normally this doesn't happen until pownerbiota makes a 
        periodic call to processServiceRequests, but you can force it 
        to be immediate with immediateadd. */ 
    void delete_me(){_health = 0; makeServiceRequest("delete_me");} 
    void spawn(){makeServiceRequest("spawn");} 
    void zap(){makeServiceRequest("zap");} 
    void replicate(){makeServiceRequest("replicate");} 
        //copy yourself to all the others. 
//Helper Methods for Move Methods ==================================== 
    virtual int clamp(); 
        //Clamp against _movebox. cCritterWall treats differently. 
    virtual int clamp(const cRealBox &border); //Clamp against border 
    virtual void addvelocityandcheckedges(Real dt); /* do _position += 
        dt*_velocity, and clamp, wrap, or bounce the new position off 
        the _movebox. Set _outcode to tell which edges. Called by 
        move(). Need the dt to figure out a velocity bounce. */ 
    void synchSpeedAndDirectionToVelocity(); /* Enforces 
        _speed*_tangent = _velocity and avoids having _speed less than 
        SMALL_REAL */ 
    void fixNormalAndBinormal(); /* This is easy in 2D, subtler in 3D. 
        Call this from inside move on every update. It also 
        orthonormolizes _tangent, _normal, and _binormal. */ 
//Helper method for pointer references. ============================== 
    virtual void fixPointerRefs(); /* This helper is for fixing things 
        like _ptarget after serialization, is also needed when we 
        delete a critter.*/ 
//================================================ 
//Distance, touch, sniff, collide methods ============================ 
//================================================ 
    /* The first three methods' code depends whether USEMETRIC is 
        #defined in metric.h */ 
    virtual cVector directionTo(cCritter *pcritter); 
        //Use cMetricCritter or compute direct 
    Real distanceTo(cCritter *pcritter); 
        //Uses cBiota's cMetricCritter or computes direct 
    Real distanceTo(const cLine &testline) 
        {return testline.distanceTo(_position);}//Direct 
    cDistanceAndDirection distanceAndDirectionTo(cCritter *pcritter); 
        //ditto 
    Real distanceTo(const cVector &vpoint); //Brute force. 
    virtual BOOL touch(const cVector &vpoint);//Brute force. 
    virtual BOOL touch(const cLine &sightline); /* In 3D, clicking the 
        screen really picks a line of sight rather than a particular 
        point in space. */ 
    virtual BOOL touch(cCritter *pcritter); /* TRUE if pcritter is 
        different from this and the distance between the centers is 
        less than the sum of the radii. Uses cBiota's cMetricCritter 
        or just does the brute force distance checks. */ 
    virtual BOOL contains(cCritter *pcritter); /* TRUE if the disk of 
        pcritter is inside the disk of the caller. */ 
    virtual COLORREF sniff(const cVector &snifflocation, CPopView 
        *pactiveview); /* Can be used in update to check the current 
        screen's pixel color at locations you're interested in. */ 
    virtual int collidesWith(cCritter *pcritterother); /* Returns 
        cCollider::DONTCOLLIDE, ::COLLIDEASCALLER, or ::COLLIDEASARG 
        to specify which of the pair, if either, gets to call for a 
        collision. Default just checks _fixedflag and 
        _collidepriority. */ 
    virtual BOOL collide(cCritter *pcritter); /* Does a physically 
        natural collision and possibly overrides to make the critters 
        react in some other way such as damage. */ 
//========================================== 
//Game methods ============================ 
//========================================== 
    virtual void die(){delete_me();} /* Can be overridden to add 
        dying behavior. But should eventually produce a call to 
        delete_me. */ 
    virtual void cCritter::dieOfOldAge(){delete_me();} /* dieOfOldAge 
        is called in the update method if(_usefixedlifetime && 
        _age > _fixedlifetime). We distinguish between die() and 
        dieOfOldAge() so die() can make a different sound for 
        instance. */ 
    virtual int damage(int hitstrength); /* Deducts hitstrength from 
        _health, calls die if this is below zero, returns _value as a 
        reward to the damager. */ 
//======================================== 
//Force and Listen methods ============================== 
//======================================== 
    virtual void feellistener(Real dt); /* Call _plistener->listen, 
        maybe more. */ 
    virtual void feelforce(); /* Do _acceleration = 
        (sum of _forcearray[i]->force(this))/mass(). feelforce is 
        virtual because you might possibly want to select which forces 
        you feel, depending on the situation, like whether you're 
        currently pursuing or fleeing. */ 
//================================================= 
//Drawing methods ==================================== 
//================================================= 
    void updateAttitude(Real dt, BOOL forceattitudeupdate = FALSE); 
        /* This keeps graphical attitude matrix of the critter in 
        synch with its motionmatrix. To prevent a too-busy look, we 
        normally don't do the update if the _speed is less than 
        _mintwitchthresholdspeed. But if we are controlling the 
        critter with arrow key calls to, e.g. the yaw, pitch and roll 
        methods, we do want to force the update of the appearance, and 
        then you set the forceattitudeupdate argument to TRUE. */ 
    virtual void draw(cGraphics *pgraphics, int drawflags=0); 
        /* Calls _psprite->draw. Has to be virtual because some child 
        critters draw stuff (like guns) on top of sprite. */ 
    virtual void drawHighlight(cGraphics *pgraphics, Real 
        highlightratio); /* Draw a highlighted XOR circle around the 
        sprite with a size = highlightratio * radius(). */ 
//============================================ 
//Sound methods ============================= 
//============================================ 
    static void playSound(CString wavfileresourcename, int soundflags 
        = SND_RESOURCE | SND_ASYNC); 
        /* By default interrupts any current sounds to play this 
            sound. wavfileresourcename has to be the resource name of 
            a *.wav file that you added as a resource to your build. */ 
    static void stopSound(); //Turns off any currently playing sounds. 
//=========================================== 
//Simulation methods ============================== 
//=========================================== 
    virtual void animate(Real dt); /* Calls _psprite->animate(dt, 
        this). Can override to setAimVector. */ 
    virtual void update(CPopView *pactiveview, Real dt); /* Call force 
        to set the _acceleration to zero or to the quantity determined 
        by _pforce. The pactiveview argument can be used to sniff 
        pixel colors. */ 
    int move(Real dt); /* You really should NOT change the delicately 
        constructed move method, which is why its not virtual. */ 
}; 
#endif //CRITTER_H 

cCritter initialization

To complete this detailed code section, here's how the cCritter fields get initialized by the default constructor. Remember that when we define children of the critter class, like, say, cCritterArmed, when the cCritterArmed constructor is called the base class cCritter constructor gets called first. In other words, the cCritter constructor is code that all of our critters will execute at start up. Child classes may override some of these initialization values; they may also initialize additional variables that the child class may have.

We go ahead and list the full code of a recent version of the cCritter constructor here just to give you an idea of all the member fields actually used. A C++ usage worth noting here is that when we write a C++ constructor, it's common to set the values of fields by using initializer lines of the form _variable(value), rather than having a line of the form _variable = value; inside the curly brackets of the constructor. It makes the code easier to overview, and it's useful to see the allocation calls using new isolated inside the constructor's curly brackets, so that then it's easier to remember what you have to undo in the destructor. (If you happen to have any data fields that were declared as const you are in fact required to use initializer lines to set their values.)

Also note that if the pownergame argument isn't supplied, it will get the default NULL value, and the code involving it will be skipped over in the constructor.

cCritter::cCritter(cGame *pownergame): 
    _pownerbiota(NULL), 
    _age(0.0), 
    _lasthit_age(- cCritter::SAFEWAIT), /* We do this so 
        that critters don't start out thinking they were 
        just hit. cCritter::SAFEWAIT is currently 0.3 
        seconds. */ 
    _oldrecentlydamaged(FALSE), //Can use to notice when you need to 
        change sprite. 
    _health(cCritter::STARTHEALTH), //Default 1. 
    _usefixedlifetime(FALSE), 
    _fixedlifetime(cCritter::FIXEDLIFETIME), 
    _shieldflag(FALSE), 
    _outcode(0), 
    _score(0), 
    _newlevelscorestep(0), 
    _newlevelreward(0), 
    _value(1), 
    _personality(cRandomizer::pinstance()->random()), 
        //Use our static randomizing method. 
    _movebox(cRealBox(4.0,3.0, 0.0)), 
        //Dummy defaults to be reset with setMoveBox 
    _dragbox(cRealBox(_movebox)), 
        //Dummy defaults to be reset with setDrag 
    _wrapflag(cCritter::STARTWRAPFLAG), //cCritter::BOUNCE 
    _defaultprismdz(cSprite::CRITTERPRISMDZ), 
    _density(cCritter::DENSITY), 
        //This standard value is currently 1.0. 
    _mass(1.0), //Dummy default is reset by fixMass. 
    _collidepriority(cCollider::CP_CRITTER), 
    _absorberflag(FALSE), 
    _fixedflag(FALSE), 
    _position(cVector::ZEROVECTOR), 
    _oldposition(cVector::ZEROVECTOR), 
    _wrapposition1(cVector::ZEROVECTOR), 
    _wrapposition2(cVector::ZEROVECTOR), 
    _wrapposition3(cVector::ZEROVECTOR), 
    _velocity(cVector::ZEROVECTOR), 
    _speed(0.0), //Must match _velocity.magnitude(). 
    _tangent(cVector(1.0, 0.0)), 
        //We always want some unit vector _tangent. 
    _oldtangent(cVector(1.0, 0.0)), 
    _normal(cVector(0.0, 1.0)), 
    _binormal(cVector(0.0, 0.0, 1.0)), 
    _attitudetomotionlock(TRUE), 
    _acceleration(cVector::ZEROVECTOR), 
    _listeneracceleration(cCritter::LISTENERACCELERATION), 
    _spin(), /* _spin is initialized to 0 spinangle around ZAXIS by 
        default constructor */ 
    _maxspeed(cCritter::MAXSPEED), //Default 3.0 
    _maxspeedstandard(cCritter::MAXSPEED), 
    _mintwitchthresholdspeed(cCritter::MINTWITCHTHRESHOLDSPEED), 
    _bounciness(1.0), 
    _mutationstrength(cCritter::MUTATIONSTRENGTH), 
        //Default 0.6 (out of 1.0 max) 
    _ptarget(NULL), 
    _metrickey(0) 
{ 
    _psprite = new cSprite(); /* Let's always have a valid sprite. 
        The default cSprite looks like a circle, by the way. */ 
    _plistener = new cListener(); /* For uniformity, always have a 
        valid listener as well. The default listener does nothing. 
        Don't call setListener(new cListener()) here as this call may 
        have side-effects I don't want yet. */ 
    _attitude.setLastColumn(_position); 
        /* The default _attitude constructor has set the matrix 
        to the identity matrix, and it's more accurate to the 
        make the fourth column match the position. */ 
    if (pownergame) 
        pownergame->add(this, TRUE); /* This call will set _movebox 
            and _dragbox to match pownergame->_border, and will set 
            _wrapflag to match pownergame->wrapflag). The TRUE flag 
            means to insert the critter into the game cBiota array 
            right away. */ 
} 


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