Controlling Players and Characters(30)
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:
{
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;