Controlling Players and Characters(23)

Controlling Players and Characters(23)

 

Creating a Spell Controller

Controlling spells is a matter of tracking the meshes and animations that represent
the spell and then processing the spell’s effects on their intended targets. Because
the spell’s effects are really related to the characters, it’s best to let the engine that
controls the characters handle the spell effects and leave the spell animation up to
a spell controller class object.

You want to create a spell controller class that maintains a list of currently cast spells
and displays them onscreen. When a spell is complete, this controller class calls an outside
function to process the spell’s effects. This spell controller class, cSpellController,
uses supportive structures that make tracking the spell meshes and animation
easier. These structures are sMeshAnim and sSpellTracker.

 

Meshes with sMeshAnim

Reviewing the sSpell spell structure, you can see that meshes are referenced by
number rather than by name. That mesh reference number is actually the index to
an array of meshes. You store this array of meshes in a collection of sMeshAnim
structures:

typedef  struct  sMeshAnim
{
    
char         filename[MAX_PATH];      // filename of mesh/anim
     long         count;                   // number of characters using mesh
    cMesh       mesh;
    cAnimation  anim;    

    sMeshAnim() { count = 0; }
} *sCharMeshListPtr;

For each mesh in use in your engine, you have a matching sMeshAnim structure.
Each structure instance stores the filename of the mesh to use, a cMesh and a
cAnimation object for the mesh, and a variable (Count) that keeps count of how many
instances of the mesh are currently in use.

For each spell that needs a mesh, the appropriate .X file is loaded into the mesh
and animation objects (both using the same filename and the animation using a
single animation set called anim).

Meshes are only loaded from disk whenever the spell controller requires them, and
because the structure maintains a count of the times the mesh is in use, the spell
controller can quickly determine whether the mesh is loaded.

As spells complete their animation cycle, the appropriate mesh count is reduced,
and when the number of spells that use the mesh is reduced to zero, the mesh and
animation objects are released (to save memory).

 

Tracking Spells Using sSpellTracker

Whereas the sMeshAnim structure maintains the meshes used by spells, the actual
list of active spells is maintained by the sSpellTracker structure. The sSpellTracker
structure is allocated and inserted into a linked list of the same structures any time
a spell is cast:

#define  NUM_SPELL_DEF   64

enum  SpellEfects
{
    ALTER_HEALTH = 0, ALTER_MANA, CURE_AILMENT, CAUSE_AILMENT, RAISE_DEAD, INSTANT_KILL, DISPEL_MAGIC, TELEPORT
};

enum  SpellTargets
{
    TARGET_SINGLE = 0, TARGET_SELF, TARGET_AREA
};

enum  AnimPositions
{
    POSITION_NONE = 0, POSITION_CASTER, POSITION_TOTARGET, POSITION_TOCASTER, POSITION_TARGET, POSITION_SCALE
};

/************************************************************************************************/

typedef 
struct  sSpellTracker
{
    
long         spell_index;

    sCharacter* caster;
    
long         affect_type;

    
long  cur_anim;               // animation: 0-2
     float  source_x, source_y, source_z;
    
float  target_x, target_y, target_z;

    
float  x_pos, y_pos, z_pos;   // current coordinate
     float  x_add, y_add, z_add;   // movement values
     float  dist_to_target;       

    union
    {
        
float    speed;          
        
long     holding_time;   
    };

    cObject 
object ;              // graphics object

    sSpellTracker*  prev;
    sSpellTracker*  next;

    
/////////////////////////////////////////////////////////////////////////// //

    sSpellTracker()
    {
        caster = NULL;
        prev = next = NULL;
    }

    ~sSpellTracker()
    {
        delete next;
    }
} *sSpellTrackerPtr;

For each spell cast, a sSpellTracker structure is used to contain the information to track
the mesh, animation, movement, timing, and which character cast the spell. The
structure starts off with the spell number (spell_index), which relates directly to the MSL.

To later help determine the effects of a spell, a pointer to a character (caster) is
maintained as well as the type of characters the spell can affect (PCs, NPCs, or
MCs). You can define each type of character as follows:

#define CHAR_PC 0
#define CHAR_NPC 1
#define CHAR_MONSTER 2

Notice that a spell has no target character defined, but a trio of target coordinates.
In fact, a spell has a trio of source coordinates. Remember that a spell mesh can
stay in place over the caster or victim, move between the two, or stretch between
them. Setting the source and target coordinates ensures that the tracker knows how
to position the mesh in use.

Speaking of the mesh in use, curr_anim is used to track which of the three
meshes to use. As you may recall, a mesh movement takes place in three steps, and
once the current animation passes the third step, the spell takes effect.

To track the motion of the spell meshes (if they are indeed moving), you use a set of
values (x_add, y_add, and z_add) that tells the spell controller which direction to move the
mesh at each update. As for the current position of the mesh in use, the variables
x_pos, x_pos, and z_pos contain the current coordinates at which to render the mesh.

The speed in which a mesh moves is contained in speed, and the total distance the
mesh can move is contained in dist_to_target. If a mesh stays in place, the holding_time variable
does a countdown of the number of milliseconds until the cycle is complete.

Rounding off sSpellTracker, object is the graphics object you use to render the
meshes, and prev and next maintain the linked list of structures.


你可能感兴趣的:(Controlling Players and Characters(23))