Creating Combat Sequences(3)
Global Data
The application class uses three global variables to contain the data about the character
and spell meshes, and the character animation information:
#define PER_SPELL_WIDTH 200
#define PER_SPELL_HEIGHT 20
#define CLIENT_WIDTH 640
#define CLIENT_HEIGHT 480
#define TARGET_VERTEX_FVF D3DFVF_XYZ | D3DFVF_DIFFUSE
typedef struct sTargetVertex
{
float x, y, z;
D3DCOLOR diffuse;
} *sTargetVertexPtr;
const sTargetVertex g_target_verts[6] =
{
{ -20.0f, 40.0f, 0.0f, 0xFFFF4444 },
{ 20.0f, 40.0f, 0.0f, 0xFFFF4444 },
{ 0.0f, 20.0f, 0.0f, 0xFFFF4444 },
{ 0.0f, -20.0f, 0.0f, 0xFFFF4444 },
{ 20.0f, -40.0f, 0.0f, 0xFFFF4444 },
{ -20.0f, -40.0f, 0.0f, 0xFFFF4444 }
};
const char * g_char_mesh_names[] =
{
{ "..\\Data\\Warrior.x" }, // Mesh # 0
{ "..\\Data\\Yodan.x" } // Mesh # 1
};
const sCharAnimInfo g_char_anim_infos[] =
{
{ "Idle", true },
{ "Walk", true },
{ "Swing", false },
{ "Spell", false },
{ "Swing", false },
{ "Hurt", false },
{ "Die", false },
{ "Idle", true }
};
const char * g_spell_mesh_names[] =
{
{ "..\\Data\\fireball.x" },
{ "..\\Data\\Explosion.x" },
{ "..\\Data\\Groundball.x" },
{ "..\\Data\\ice.x" },
{ "..\\Data\\bomb.x" },
{ "..\\Data\\heal.x" },
{ "..\\Data\\force.x" }
};
cApp::Init
Init, the first overloaded function in the application class, initializes the graphics
and input systems, loads all graphics, fonts, items, and other data needed for the
program:
{
create_display(g_hwnd, CLIENT_WIDTH, CLIENT_HEIGHT, 16, true , true );
set_perspective(D3DX_PI/4, 1.3333f, 1.0f, 10000.0f);
create_font(&m_font, "Arial", 16, true , false );
m_input.create(g_hwnd, get_window_inst());
m_keyboard.create_keyboard(&m_input);
m_mouse.create_mouse(&m_input, true );
create_vertex_buffer(&m_target_vb, 6, sizeof (sTargetVertex), TARGET_VERTEX_FVF);
fill_in_vertex_buffer(m_target_vb, 0, 6, g_target_verts);
load_texture_from_file(&m_button, "..\\Data\\Buttons.bmp", 0, D3DFMT_UNKNOWN);
m_terrain_mesh.load("..\\Data\\Battle.x", "..\\Data\\");
m_terrain_obj.create(&m_terrain_mesh);
// create character stats and spell options text window
m_char_stats.create(m_font);
m_char_stats.move(508, 400, 128, 48, -1, -1, COLOR_DARK_BLUE, COLOR_ARGENTINE);
m_spell_options.create(m_font);
m_spell_options.move(4, 4, 632, 328, -1, -1, COLOR_DARK_BLUE, COLOR_ARGENTINE);
// load in master item list
FILE* fp = fopen("..\\Data\\Default.mil", "rb");
if (fp)
{
fread(m_mil, 1, sizeof (m_mil), fp);
fclose(fp);
}
m_char_controller.init(m_font, "..\\Data\\Default.mcl",
m_mil, m_spell_controller.get_spell_list(),
array_num(g_char_mesh_names), g_char_mesh_names,
"..\\Data\\", "..\\Data\\",
array_num(g_char_anim_infos), g_char_anim_infos);
m_spell_controller.init("..\\Data\\Default.msl",
array_num(g_spell_mesh_names), g_spell_mesh_names,
"..\\Data\\");
m_char_controller.attach(&m_spell_controller);
m_spell_controller.attach(&m_char_controller);
// add player
m_char_controller.add_char(0, 0, CHAR_PC, CHAR_STAND, 200.0f, 0.0f, 0.0f, 4.71f);
// hardcoded - add monster
m_char_controller.add_char(1, 1, CHAR_MONSTER, CHAR_STAND, -200.0f, 0.0f, 0.0f, 1.57f);
m_char_controller.add_char(2, 1, CHAR_MONSTER, CHAR_STAND, -100.0f, 0.0f, -200.0f, 1.57f);
m_char_controller.add_char(3, 1, CHAR_MONSTER, CHAR_STAND, 0.0f, 0.0f, 100.0f, 1.57f);
// give an axe to one of the monsters
m_char_controller.equip(m_char_controller.get_char(1), 8, WEAPON, true );
return true ;
}
As is typical in a graphics project, the graphics system is initialized and an Arial font
is created. Next comes initialization of the input system and devices.
As I mentioned, you need to target a character in order to attack or cast a spell
on the character. A pair of red, spinning triangles contained within a triangle list
vertex buffer with six vertices represents the target (as illustrated in Figure 18.5).
At this point in the Init function, create the vertex buffer that contains the two triangles
that represent the target.
Once the target vertex buffer is created, the various graphics need to be loaded
from disk. First, you load the button graphics used to select an action. You can see
the button graphics image in Figure 18.6. The images used to draw the charge
timer are included with the button graphics image. Next, you load the arena mesh
and object.
In order to display the player character’s status (including health and mana points), you create a text window below the character. Create a second window to contain the names of all known spells from which players can select spells as needed. As you can see in following snap this second window covers the top of the display.
Next, you need to load the master item list and initialize the character and spell
controller classes.
To finish the Init function, you position a few characters (players and monsters)
within the arena. (I was a little lazy here; hard-coding the characters encountered
and their positions in the arena should be a bit randomized, but I’ll leave that up
to you.) To add and position characters in the battle, use the character controller’s
add_char function.
Notice that a total of four characters are added to the fray. To make things a little
harder for the player, I went ahead and equipped the second character (a monster)
with an ax weapon. To equip characters with a weapon, you use the character controller’s
equip function, as I did.