Using the
Character Definitions
The character definitions are
templates by nature, so you really need to load up the
definitions and work with them on a per-instance basis. This means that you need
to come up with a controller that loads the definitions and tracks each instance
of
a character in your game. What you need is a character controller class.
Creating a
Character Controller Class
Now that you’ve seen what is
involved in controlling and defining your game’s
characters, you can focus on constructing a controller class that takes care of
everything
for you, including adding, removing, updating, and rendering the characters,
as well as handling the spell effects from the spell controller previously
developed.
Because so much is involved in
tracking characters, the job is split into a few structures
and a single class. Much like spells, a mesh list is required to hold the list
of
used meshes. This time however, the looping information of the animations is not
contained in the character definitions; another structure is needed to contain
the
character animations that need to be looped.
When working in artificial
intelligence, you create a single structure to store the
coordinates of route points. Finally, another structure maintains a linked list
of
characters in use. Now, examine each structure just mentioned and the
information
they contain.
Meshes with
sMeshAnim
For the character controller,
you
also have to provide a list of meshes that are used to render the characters.
The
sMeshAnim structure contains the mesh and animation objects and filenames.
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;
Animation
Loops and sCharAnimInfo
The animations used by the
characters are set in their ways; either they can or
cannot loop. Certain actions, such as standing, require a character’s mesh to
constantly
repeat, giving the appearance of constant motion, whereas other animations
such as swinging the sword only need be performed once.
By storing a list of the
animations that need be looped, the character controller can
pass the information on to the Graphics Core so that it can handle the hard work
for you. You store this animation loop information in the sCharAnimInfo
structure,
as follows:
typedef struct
sCharAnimInfo
{
char name[32]; // name of animation
bool is_loop;
} *sCharAnimInfoPtr;
To use the structure, you must
store the name of the animation (matching the animation
set name in the .X file) and a flag that tells whether to loop the associated
animation.
Moving with
sRoutePoint
As previously discussed, you
use the sRoutePoint structure to store the coordinates of
a route point that characters move toward in their never-ending movement
through the levels.
typedef struct
{
float XPos, YPos, ZPos; // Target position
} sRoutePoint;
Tracking
Characters with sCharacter
Things are about to become more
complicated because tracking each character
involves quite a bit of data. In fact, so much data is involved in tracking
characters
(within an sCharacter structure) that you need to see it in pieces:
typedef struct sCharacter
{
long def;
long id;
long type; // PC, NPC, or MONSTER
long ai; // STAND, WANDER, etc
bool update_enable;
sCharDef char_def;
cCharIcs* char_ics;
char script_filename[MAX_PATH];
long health_points; // current health points
long mana_points; // current mana points
long ailments;
float charge;
long action; // current action
float pos_x, pos_y, pos_z; // current coordinates
float direction; // angle character is facing
long last_anim;
long last_anim_time;
bool is_lock;
long action_timer;
sCharacter* attacker;
sCharacter* victim;
long spell_index;
long target_type;
float target_x, target_y, target_z;
long item_index; // item to use when ready
sCharItem* char_item;
float distance; // follow/evade distance
sCharacter* target_char; // character to follow
float min_x, min_y, min_z; // min bounding coordinates
float max_x, max_y, max_z; // max bounding coordinates
long num_points; // number of points in route
long cur_point; // current route point
sRoutePoint* route; // route points
char msg[128];
long msg_timer;
D3DCOLOR msg_color;
cObject object;
cMesh weapon_mesh;
cObject weapon_object;
sCharacter* prev;
sCharacter* next;
////////////////////////////////////////////////////////////////////////////
sCharacter()
{
def = 0;
id = -1;
type = CHAR_PC;
update_enable = false;
ailments = 0;
charge = 0.0f;
ZeroMemory(&char_def, sizeof(char_def));
char_ics = NULL;
script_filename[0] = 0;
action = CHAR_IDLE;
last_anim = -1;
is_lock = false;
action_timer = 0;
attacker = NULL;
victim = NULL;
item_index = 0;
char_item = NULL;
distance = 0.0f;
target_char = NULL;
min_x = min_y = min_z = max_x = max_y = max_z = 0;
num_points = 0;
route = NULL;
msg[0] = '\0';
msg_timer = 0;
prev = next = NULL;
}
~sCharacter()
{
delete char_ics;
delete[] route;
delete next;
}
} *sCharacterPtr;