Creating a
Trigger Class
Adhering to object-oriented
programming techniques, create a class that will handle
a list of triggers and determine which (if any) has been touched by a character.
The
class uses a structure to store the information of each trigger—the coordinates,
type,
and so on. Each trigger is also assigned an identification number that it uses
to refer
back to itself. The entire list is maintained as a linked list of structure.
The cTrigger class can load and
save a trigger file, which makes editing lists of triggers
easier. This file is text-based, making it easier to read and edit. Each trigger
in the map uses a single line of text written in this order: an identification
number,
the type of trigger (0=sphere, 1=box, 2=cylinder, 3=triangle), and the default
enabled
status (if the trigger is enabled when loaded). A value of 0 means that the
trigger
is disabled, and a value of 1 means that the trigger is enabled.
Depending on the type of
trigger you are defining, the trigger must include a few
more values. Spheres require the X-, Y-, and Z-coordinates and the radius, as
shown
in the following:
ID 0 ENABLED X
Y Z RADIUS
Boxes have the coordinates of
the opposing corners:
ID 1 ENABLED X1
Y1 Z1 X2 Y2 Z2
You define cylinders by the
lower-center coordinates plus the radius and height:
ID 2 ENABLED X
Y Z RADIUS HEIGHT
Finally, you define triangles
by the X- and Z-coordinates of the three corners, in a
clockwise order, as seen from above the triangle on the Y-axis (much as a
polygon
face is defined in Chapter 6, “Drawing with DirectX Graphics”). The Y-coordinate
for
all three points of the triangle and the height of the trigger round out this
definition:
ID 3 ENABLED X1
Z1 X2 Z2 X3 Z3 Y HEIGHT
I’ll get back to the trigger
data file in a moment. For now, take a look at the class
definition of the trigger class. The class starts
out with an enum list that defines each type of trigger shape that you can use:
enum
TriggerTypes { TRIGGER_SPHERE = 0, TRIGGER_BOX, TRIGGER_CYLINDER,
TRIGGER_TRIANGLE };
Each trigger you define
requires a structure that contains the information pertinent
to the trigger—the trigger’s location, enabled state, and unique identification
number. Each type of trigger uses a set of coordinates to define its location on
the
map, as well as additional data to define the trigger’s radius, opposing corner
coordinates,
and so on. The structure that contains the information about each trigger
created is as follows:
typedef struct sTrigger
{
long type; // TRIGGER_SPHERE, TRIGGER_BOX, etc.
long id;
bool enabled;
float x1, y1, z1;
float x2, y2, z2;
float x3, z3;
float radius;
sTrigger* prev;
sTrigger* next;
///////////////////////////////////////////////////////////
sTrigger() { prev = next = NULL; }
~sTrigger() { delete next; next = NULL; }
} *sTriggerPtr;
Notice that the sTrigger
structure maintains a set of linked list pointers, as well as a
constructor and a destructor that clear the linked list pointers and free the
linked
list, respectively.
In order to utilize the
sTrigger structure, you use the trigger class, which manages
the linked list of triggers and enables you to save and load lists of those
triggers.
Take a look at the trigger class declaration:
typedef class cTrigger
{
private:
long m_num_triggers;
sTrigger* m_root_trigger;
////////////////////////////////////////////////////////////////////////////
public:
cTrigger()
{
m_num_triggers = 0;
m_root_trigger = NULL;
}
~cTrigger()
{
free();
}
void free()
{
delete m_root_trigger;
m_root_trigger = NULL;
m_num_triggers = 0;
}
long get_num_triggers()
{
return m_num_triggers;
}
sTrigger* get_root_trigger()
{
return m_root_trigger;
}
void enable(long id)
{
set_enable_state(id, true);
}
void disable(long id)
{
set_enable_state(id, false);
}
void add_sphere(long id, bool enabled,
float x_pos, float y_pos, float z_pos,
float radius)
{
sTrigger* trigger = add_trigger(TRIGGER_SPHERE, id, enabled);
trigger->x1 = x_pos;
trigger->y1 = y_pos;
trigger->z1 = z_pos;
trigger->radius = radius * radius;
}
void add_box(long id, bool enabled,
float x_min, float y_min, float z_min,
float x_max, float y_max, float z_max)
{
sTrigger* trigger = add_trigger(TRIGGER_BOX, id, enabled);
// setup trigger data (fix for min/max radius)
trigger->x1 = min(x_min, x_max);
trigger->y1 = min(y_min, y_max);
trigger->z1 = min(z_min, z_max);
trigger->x2 = max(x_min, x_max);
trigger->y2 = max(y_min, y_max);
trigger->z2 = max(z_min, z_max);
}
void add_cylinder(long id, bool enabled,
float x_pos, float y_pos, float z_pos,
float radius, float height)
{
sTrigger* trigger = add_trigger(TRIGGER_CYLINDER, id, enabled);
trigger->x1 = x_pos;
trigger->y1 = y_pos;
trigger->z1 = z_pos;
trigger->radius = radius * radius;
trigger->y2 = height;
}
void add_triangle(long id, bool enabled,
float x1, float z1,
float x2, float z2,
float x3, float z3,
float y_pos, float height)
{
sTrigger* trigger = add_trigger(TRIGGER_TRIANGLE, id, enabled);
trigger->x1 = x1;
trigger->z1 = z1;
trigger->x2 = x2;
trigger->z2 = z2;
trigger->x3 = x3;
trigger->z3 = z3;
trigger->y1 = y_pos;
trigger->y2 = height;
}
////////////////////////////////////////////////////////////////////////////
private:
sTrigger* add_trigger(long type, long id, bool enabled)
{
// allocate a new trigger structure and link in
sTrigger* trigger = new sTrigger;
trigger->prev = NULL;
trigger->next = m_root_trigger;
if(m_root_trigger)
m_root_trigger->prev = trigger;
m_root_trigger = trigger;
trigger->type = type;
trigger->id = id;
trigger->enabled = enabled;
m_num_triggers++;
return trigger;
}
////////////////////////////////////////////////////////////////////////////
public:
bool load(const char* filename);
bool save(const char* filename);
void remove(long id);
long get_trigger(float x_pos, float y_pos, float z_pos);
bool get_enable_state(long id);
private:
void set_enable_state(long id, bool state);
} *cTriggerPtr;
Most of the functions deal with
only a linked list of sTrigger structures—add a structure,
remove a structure, find a structure and modify it, and so on. For a closer
look at what’s going on, take a minute or two to review the following sections,
which provide the code for each function.