Controlling Players and Characters(41)

Controlling Players and Characters(41)

 

download source and solution

 

Demonstrating Characters with the Chars Demo

All your hard work is about to pay off with a demonstration of the character and
spell controllers seen in this chapter.

Upon executing the program, you see the scene shown in following snap.

Controlling Players and Characters(41)_第1张图片

In the Chars demo, you take control of the PC, using the arrow keys to turn and
move him. The controls are straightforward—use the space bar to interact with the
closest character (either to speak to an NPC or to attack a monster). Pressing the
number keys 1 through 3 casts a few spells at the closest monster.

Each character in the game demonstrates a single artificial intelligence. Speaking
to another character conveys which artificial intelligence a particular character uses
(except for monsters, which either stand still or follow the player character). It’s
best to quickly dispatch the monsters before they take your player character out.

Everything in the Chars demo has been explained in this chapter. A script class
determines which characters to place in the map during startup (as detailed in the
startup script) and what each character does or says when spoken to.

The demo’s action template, default.mla, contains a number of script actions that
directly modify a character’s type, artificial intelligence, position, and direction.
Adding characters to the world is as easy as using an add character script action,
and from there, you modify the character’s attributes accordingly.

As for the main application, the system core’s cApp class is being used to
control the flow of the demo; each frame update is regulated to 33-millisecond
lapses, giving a 30-frames-per-second update rate. At each and every frame, keyboard
input is read in and stored, waiting to be used during the PC update function.
A fixed camera renders out the action, with each character fully animated
inside a single level (both characters and the level represented by meshes).

The code to the demo is well commented, so enjoy exploring it, and find out how
quickly you can create characters running around in your game project. Be sure to
check out the scripts and script action template using the Mad Lib Script editor, as
well as the items and character definitions using the MIL and MCL Editors.

 

Main Routine Source:

WinMain.h:

#ifndef WIMMAIN_H
#define  WINMAIN_H

#include "core_framework.h"
#include "core_input.h"
#include "text_window.h"
#include "char_ics.h"
#include "char.h"
#include "script.h"
#include "spell.h"

class  cApp;

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

class  cGameCharController :  public  cCharController
{
private :
    cApp*   m_app;

private :    
    
virtual   void  pc_update(sCharacter* character,  long  elapsed,
                           
float * x_move,  float * y_move,  float * z_move);

    
virtual   bool  validate_move(sCharacter* character, 
                               
float * x_move,  float * y_move,  float * z_move);

public :
    
void  set_data(cApp* app)
    {
        m_app = app;
    }
};

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

class  cGameScript :  public  cScript
{
    friend cApp;

private :
    BOOL                    m_flags[256];

    cApp*                   m_app;

    cInputDevice*           m_keyboard;    
    cGameCharController*    m_gc_controller;
    
    
long                     m_num_route_points;
    sRoutePoint*            m_route;

    cTextWindow             m_text_window;

    ID3DXFont*              m_font;

    
///////////////////////////////////////////////////////////////////////////////// /
    
public :
    cGameScript()
    {
        m_app           = NULL;
        m_keyboard      = NULL;        
        m_gc_controller = NULL;
        m_route         = NULL;
        m_font          = NULL;

        ZeroMemory(m_flags, 
sizeof (m_flags));
    }

    ~cGameScript()
    {
        delete[] m_route;
    }

    
void  set_data(cApp* app, cInputDevice* keyboard, cGameCharController* gc_controller, ID3DXFont* font)
    {
        m_app           = app;
        m_keyboard      = keyboard;
        m_gc_controller = gc_controller;
        m_font          = font;

        m_text_window.create(m_font);
    }

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

private :
    
virtual   void  release()
    {
        delete[] m_route;
        m_route = NULL;

        m_num_route_points = 0;
    }

    
virtual  sScriptInfo* process(sScriptInfo* info)
    {
        
switch (info->action_index)
        {
        
case  0:   return  script_end(info);
        
case  1:   return  script_if_flag_then(info);
        
case  2:   return  script_else(info);
        
case  3:   return  script_endif(info);
        
case  4:   return  script_set_flag(info);
        
case  5:   return  script_show_msg(info);
        
case  6:   return  script_add_char(info);
        
case  7:   return  script_remove_char(info);
        
case  8:   return  script_show_char_msg(info);
        
case  9:   return  script_set_char_type(info);
        
case  10:  return  script_set_char_ai(info);
        
case  11:  return  script_set_char_distance(info);
        
case  12:  return  script_set_char_bound(info);
        
case  13:  return  script_set_target_char(info);
        
case  14:  return  script_set_no_target(info);
        
case  15:  return  script_create_route(info);
        
case  16:  return  script_add_point(info);
        
case  17:  return  script_assign_route(info);
        
case  18:  return  script_move_char(info);
        
case  19:  return  script_set_char_script(info);
        }

        
return  NULL;     // error executing
    }

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

private :

    sScriptInfo* script_end(sScriptInfo* info)
    {
        
return  NULL;     // force end of processing
    }

    sScriptInfo* script_else(sScriptInfo* info)
    {
        
return  info->next;
    }

    sScriptInfo* script_endif(sScriptInfo* info)
    {
        
return  info->next;
    }

    sScriptInfo* script_set_flag(sScriptInfo* info)
    {
        m_flags[info->entries[0].long_value % 256] = info->entries[1].bool_value;

        
return  info->next;
    }

    sScriptInfo* script_add_char(sScriptInfo* info)
    {
        m_gc_controller->add_char(info->entries[0].long_value,
                                  info->entries[1].long_value,
                                  info->entries[2].selection,
                                  info->entries[3].selection,
                                  info->entries[4].float_value,
                                  info->entries[5].float_value,
                                  info->entries[6].float_value,
                                  info->entries[7].float_value);

        
return  info->next;
    }

    sScriptInfo* script_remove_char(sScriptInfo* info)
    {
        m_gc_controller->remove(info->entries[0].long_value);

        
return  info->next;
    }

    sScriptInfo* script_set_char_type(sScriptInfo* info)
    {
        m_gc_controller->set_char_type(info->entries[0].long_value, info->entries[1].selection);

        
return  info->next;
    }

    sScriptInfo* script_set_char_ai(sScriptInfo* info)
    {
        m_gc_controller->set_char_ai(info->entries[0].long_value, info->entries[1].selection);

        
return  info->next;
    }

    sScriptInfo* script_set_char_distance(sScriptInfo* info)
    {
        m_gc_controller->set_char_distance(info->entries[0].long_value, info->entries[1].float_value);

        
return  info->next;
    }

    sScriptInfo* script_set_char_bound(sScriptInfo* info)
    {
        m_gc_controller->set_char_bound(info->entries[0].long_value,
                                        info->entries[1].float_value,
                                        info->entries[2].float_value,
                                        info->entries[3].float_value,
                                        info->entries[4].float_value,
                                        info->entries[5].float_value,
                                        info->entries[6].float_value);

        
return  info->next;
    }

    sScriptInfo* script_set_target_char(sScriptInfo* info)
    {
        m_gc_controller->set_target_char(info->entries[0].long_value, info->entries[1].long_value);

        
return  info->next;
    }

    sScriptInfo* script_set_no_target(sScriptInfo* info)
    {
        m_gc_controller->set_target_char(info->entries[0].long_value, -1);

        
return  info->next;
    }

    sScriptInfo* script_create_route(sScriptInfo* info)
    {
        delete[] m_route;
        m_route = NULL;

        m_num_route_points = 0;

        m_num_route_points = info->entries[0].long_value;
        m_route = 
new  sRoutePoint[m_num_route_points];

        
return  info->next;
    }

    sScriptInfo* script_add_point(sScriptInfo* info)
    {
        
long  route_index = info->entries[0].long_value;

        m_route[route_index].pos_x = info->entries[1].float_value;
        m_route[route_index].pos_y = info->entries[2].float_value;
        m_route[route_index].pos_z = info->entries[3].float_value;

        
return  info->next;
    }

    sScriptInfo* script_assign_route(sScriptInfo* info)
    {
        m_gc_controller->set_char_route(info->entries[0].long_value, m_num_route_points, m_route);

        
return  info->next;
    }

    sScriptInfo* script_move_char(sScriptInfo* info)
    {
        m_gc_controller->move_char(info->entries[0].long_value,
                                   info->entries[1].float_value,
                                   info->entries[2].float_value,
                                   info->entries[3].float_value);

        
return  info->next;
    }

    sScriptInfo* script_set_char_script(sScriptInfo* info)
    {
        m_gc_controller->set_char_script(info->entries[0].long_value, info->entries[1].text);

        
return  info->next;
    }
    
    
///////////////////////////////////////////////////////////////////////////////// /

private :
    sScriptInfo* script_if_flag_then(sScriptInfo* info);
    sScriptInfo* script_show_msg(sScriptInfo* info);
    sScriptInfo* script_show_char_msg(sScriptInfo* info);

    
void  render_scene_and_msg();
};

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

class  cApp :  public  cFramework
{
    friend 
class  cGameScript;
    friend 
class  cGameCharController;

private :
    cCamera             m_camera;

    cInput              m_input;
    cInputDevice        m_keyboard;
    cInputDevice        m_mouse;

    cMesh               m_terrain_mesh;
    cObject             m_terrain_object;

    cGameCharController m_gc_controller;
    cSpellController    m_spell_controller;

    cGameScript         m_game_script;

    sItem               m_mil[1024];

    ID3DXFont*          m_font;

public :
    
bool  init();
    
bool  frame();

    
long  get_input();

    
bool  check_intersect( float  x_start,  float  y_start,  float  z_start,
                         
float  x_end,    float  y_end,    float  z_end);
};


#endif
 

WinMain.cpp:

#include "core_common.h"
#include "core_graphics.h"
#include "char.h"
#include "script.h"
#include "text_window.h"
#include "tool.h"
#include "WinMain.h"

#define  PRESS_UP        1
#define  PRESS_RIGHT     2
#define  PRESS_DOWN      4
#define  PRESS_LEFT      8
#define  PRESS_SPACE     16
#define  PRESS_1         32
#define  PRESS_2         64
#define  PRESS_3         128

#define  CLIENT_WIDTH    800
#define  CLIENT_HEIGHT   600

cApp g_app;

// Global names of character meshes
PCSTR g_char_mesh_names[] = {
    "..\\Data\\Warrior.x",  
// Mesh # 0
    "..\\Data\\Yodan.x"      // Mesh # 1
};

sCharAnimInfo g_char_anim_infos[] = {
    { "Idle",  
true   },
    { "Walk",  
true   },
    { "Swing", 
false  },
    { "Spell", 
false  },
    { "Swing", 
false  },
    { "Hurt",  
false  },
    { "Die",   
false  },
    { "Idle",  
true   }
};

PCSTR g_spell_mesh_names[] = {
    "..\\Data\\Fireball.x",
    "..\\Data\\Explosion.x",
    "..\\Data\\Groundball.x",
    "..\\Data\\ice.x",
    "..\\Data\\bomb.x",
};

int  WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line,  int  cmd_show)
{        
    DWORD pos_x = (get_screen_width()  - CLIENT_WIDTH) / 2;
    DWORD pos_y = (get_screen_height() - CLIENT_HEIGHT) / 4;

    build_window(inst, "CharClass", "Characters Demo", 
                 WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
                 pos_x, pos_y, CLIENT_WIDTH, CLIENT_HEIGHT);
    
    g_app.run();

    
return  0;
}

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

void  cGameCharController::pc_update(sCharacter* character,  long  elapsed,
                                    
float * x_move,  float * y_move,  float * z_move)
{
    
if (character->id != CHAR_PC)
        
return ;

    
float  speed = elapsed/1000.0f * get_speed(character);

    
// rotate character

    
long  action = m_app->get_input();    

    
if (action & PRESS_RIGHT)
    {
        character->direction += (elapsed/1000.0f * 8);
        character->action = CHAR_MOVE;
    }

    
if (action & PRESS_LEFT)
    {
        character->direction -= (elapsed/1000.0f * 8);
        character->action = CHAR_MOVE;
    }

    
// walk forward
     if (action & PRESS_UP)
    {
        *x_move = sin(character->direction) * speed;
        *z_move = cos(character->direction) * speed;
        
        character->action = CHAR_MOVE;
    }

    sCharacter* char_ptr;
    
float  x_diff, y_diff, z_diff, dist;

    
// attack a nearby monster or process NPC script
     if (action & PRESS_SPACE)
    {
        
for (char_ptr = get_root_char(); char_ptr != NULL; char_ptr = char_ptr->next)
        {
            
// only check other characters
             if (char_ptr->id == character->id)
                
continue ;
            
            x_diff = fabs(char_ptr->pos_x - character->pos_x);
            y_diff = fabs(char_ptr->pos_y - character->pos_y);
            z_diff = fabs(char_ptr->pos_z - character->pos_z);

            dist = x_diff * x_diff + y_diff * y_diff + z_diff * z_diff;

            
// only check characters within 1000.0 units distance
             if (dist > 10000.0f)
                
continue ;
            
            
if (char_ptr->script_filename[0])
                m_app->m_game_script.execute(char_ptr->script_filename);
            
else
            {
                
// turn toward victim
                x_diff = char_ptr->pos_x - character->pos_x;
                z_diff = char_ptr->pos_z - character->pos_z;

                character->direction = atan2(x_diff, z_diff);

                character->victim  = char_ptr;
                char_ptr->attacker = character;

                m_app->m_gc_controller.set_char_action(character, CHAR_ATTACK, 0);
            }

            
break ;
        }
    }

    
long  spell_index = 0;

    
// cast spells
     if (action & PRESS_1 || action & PRESS_2 || action & PRESS_3)
    {
        
// get spell index to cast
         if (action & PRESS_1)    spell_index = 0;
        
if (action & PRESS_2)    spell_index = 1;
        
if (action & PRESS_3)    spell_index = 2;

        
float  spell_max_dist = m_app->m_spell_controller.get_spell(spell_index)->max_dist;

        
// search for closest monster
         for (char_ptr = get_root_char(); char_ptr != NULL; char_ptr = char_ptr->next)
        {
            
if (char_ptr->type == CHAR_MONSTER)
            {
                x_diff = fabs(char_ptr->pos_x - character->pos_x);
                y_diff = fabs(char_ptr->pos_y - character->pos_y);
                z_diff = fabs(char_ptr->pos_z - character->pos_z);

                dist = x_diff * x_diff + y_diff * y_diff + z_diff * z_diff;

                
if (dist <= (spell_max_dist * spell_max_dist))
                {
                    character->spell_index = spell_index;
                    character->target_type = CHAR_MONSTER;
                    character->target_x    = char_ptr->pos_x;
                    character->target_y    = char_ptr->pos_y;
                    character->target_z    = char_ptr->pos_z;

                    
// turn toward victim
                    x_diff = char_ptr->pos_x - character->pos_x;
                    z_diff = char_ptr->pos_z - character->pos_z;
                    character->direction = atan2(x_diff, z_diff);

                    m_app->m_gc_controller.set_char_action(character, CHAR_SPELL, 0);
                    
break ;
                }
            }
        }
    }
}

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

bool  cGameCharController::validate_move(sCharacter* character, 
                                        
float * x_move,  float * y_move,  float * z_move)
{
    
// check against terrain mesh for collision
    
    
return  ! m_app->check_intersect(character->pos_x, character->pos_y + 2.0f, character->pos_z,
        *x_move + character->pos_x, *y_move + character->pos_y + 2.0f, *z_move + character->pos_z);   
}

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

void  cGameScript::render_scene_and_msg()
{
    clear_display(0, 1.0);

    
if (begin_display_scene())
    {
        enable_zbuffer();            

        g_app.m_terrain_object.render();
        g_app.m_gc_controller.render(-1, NULL, 0);
        g_app.m_spell_controller.render(NULL, 0);

        m_text_window.render(NULL, 0);

        end_display_scene();
    }

    present_display();
}

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

sScriptInfo* cGameScript::script_if_flag_then(sScriptInfo* info)
{
    
bool  skip;

    
// see if a flag matches second entry
     if (m_flags[info->entries[0].long_value % 256] == info->entries[1].bool_value)
        skip = 
false ;
    
else
        skip = 
true ;

    
// At this point, Skip states if the script actions need to be skipped due to a conditional 
    // if..then statement.
    // 
    // Actions are further processed if skip = false, looking for an else to flip the skip mode, 
    // or an endif to end the conditional block.
    
    info = info->next;

    
while (info)
    {
        
if (info->action_index == 2)          // if else, flip skip mode.
            skip = !skip;   
        
else   if (info->action_index == 3)     // break on end if
             return  info->next;

        
// Process script function in conditional block, making sure to skip actions when condition not met.
         if (skip)
            info = info->next;
        
else
        {
            
if ((info = process(info)) == NULL)
                
return  NULL;
        }
    }

    
return  NULL;     // end of script reached
}

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

sScriptInfo* cGameScript::script_show_msg(sScriptInfo* info)
{
    m_text_window.set_text(info->entries[0].text, COLOR_WHITE);
    m_text_window.move(10, 10, CLIENT_WIDTH-20, 0, -1, -1, COLOR_BLACK, COLOR_ARGENTINE);

    render_scene_and_msg();

    
// wait for a key press

    m_keyboard->acquire();
    m_keyboard->m_locks[KEY_SPACE] = 
true ;
    m_keyboard->set_key_state(KEY_SPACE, 
false );
    
    
while (1)
    {
        m_keyboard->read();

        
if (m_keyboard->get_key_state(KEY_SPACE))
            
break ;
    }

    m_keyboard->m_locks[KEY_SPACE] = 
true ;
    m_keyboard->set_key_state(KEY_SPACE, 
false );

    
return  info->next;
}

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

sScriptInfo* cGameScript::script_show_char_msg(sScriptInfo* info)
{
    D3DXMATRIX mat_world, mat_view, mat_proj;

    D3DXMatrixIdentity(&mat_world);
    get_display_view_matrix(&mat_view);
    get_display_proj_matrix(&mat_proj);    

    D3DVIEWPORT9 viewport;
    get_display_viewport(&viewport);    

    
// get the character's coordinates

    
float  max_y;
    sCharacter* character = m_gc_controller->get_char(info->entries[1].long_value);

    character->
object .get_bounds(NULL, NULL, NULL, NULL, &max_y, NULL, NULL);

    
// project the 3D coordinates in 2D coordinates

    D3DXVECTOR3 target_vec;
    D3DXVECTOR3 source_vec(character->pos_x, character->pos_y + max_y, character->pos_z);

    D3DXVec3Project(&target_vec, &source_vec, &viewport, &mat_proj, &mat_view, &mat_world);

    m_text_window.set_text(info->entries[0].text, D3DCOLOR_RGBA(255, 255, 0, 255));
    m_text_window.move(10, 10, CLIENT_WIDTH-20, 0, target_vec.x, target_vec.y, 
                       D3DCOLOR_RGBA(0, 30, 60, 255), COLOR_ARGENTINE);

    
// display the window while waiting for a keypress

    m_keyboard->acquire();
    m_keyboard->m_locks[KEY_SPACE] = 
true ;
    m_keyboard->set_key_state(KEY_SPACE, 
false );
    
    
while (1)
    {
        m_keyboard->read();

        
if (m_keyboard->get_key_state(KEY_SPACE))
            
break ;

        render_scene_and_msg();
    }

    m_keyboard->m_locks[KEY_SPACE] = 
true ;
    m_keyboard->set_key_state(KEY_SPACE, 
false );   

    
return  info->next;
}

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

bool  cApp::init()
{
    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 );

    m_terrain_mesh.load("..\\Data\\World.x", "..\\Data\\");
    m_terrain_object.create(&m_terrain_mesh);

    
// load the master item list

    ZeroMemory(m_mil, 
sizeof (m_mil));

    FILE* fp;
    
if ((fp = fopen("..\\Data\\Default.mil", "rb")) == NULL)
        
return   false ;

    fread(m_mil, 1, 
sizeof (m_mil), fp);
    fclose(fp);

    m_spell_controller.init("..\\Data\\Default.msl",
                            array_num(g_spell_mesh_names), g_spell_mesh_names,
                            "..\\Data\\");

    m_gc_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.attach(&m_gc_controller);
    m_gc_controller.attach(&m_spell_controller);

    m_gc_controller.set_data(
this );

    
// add the character player
    m_gc_controller.add_char(0, 0, CHAR_PC, CHAR_STAND, 0.0f, 0.0f, 0.0f, 3.14f);

    
// process the startup script
    m_game_script.set_data( this , &m_keyboard, &m_gc_controller, m_font);
    m_game_script.execute("..\\Data\\Startup.mls");

    
return   true ;
}

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

bool  cApp::frame()
{
    
static  DWORD update_counter = timeGetTime();

    
// lock to 30fps
     if (timeGetTime() < update_counter + 33)
        
return   true ;

    update_counter = timeGetTime();

    m_keyboard.acquire();
    m_keyboard.read();

    
// exit if ESC pressed
     if (m_keyboard.get_key_state(KEY_ESC))
        
return   false ;

    m_gc_controller.update(33);
    m_spell_controller.update(33);

    m_camera.point(0.0f, 700.0f, -700.0f, 0.0f, 0.0f, 0.0f);
    set_display_camera(&m_camera);
    
    clear_display(0, 1.0f);

    
if (begin_display_scene())
    {
        enable_zbuffer();

        m_terrain_object.render();
        m_gc_controller.render(-1, NULL, 0);
        m_spell_controller.render(NULL, 0);

        
static  sCharacter* character = m_gc_controller.get_char(0);

        
char  stats[128];

        sprintf(stats, "HP: %ld / %ld\r\nMP: %ld / %ld",
                character->health_points, character->char_def.health_points,
                character->mana_points, character->char_def.mana_points);

        draw_font(m_font, stats, 2, 2, 0, 0, COLOR_WHITE, DT_LEFT);

        end_display_scene();
    }

    present_display();

    
return   true ;
}

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

long  cApp::get_input()
{
    
long  action = 0;

    
if (m_keyboard.get_key_state(KEY_UP) || m_keyboard.get_key_state(KEY_W))
        action |= PRESS_UP;

    
if (m_keyboard.get_key_state(KEY_RIGHT) || m_keyboard.get_key_state(KEY_D))
        action |= PRESS_RIGHT;

    
if (m_keyboard.get_key_state(KEY_DOWN) || m_keyboard.get_key_state(KEY_S))
        action |= PRESS_DOWN;

    
if (m_keyboard.get_key_state(KEY_LEFT) || m_keyboard.get_key_state(KEY_A))
        action |= PRESS_LEFT;

    
if (m_keyboard.get_key_state(KEY_SPACE))
    {
        action |= PRESS_SPACE;
        m_keyboard.m_locks[KEY_SPACE] = 
true ;
        m_keyboard.set_key_state(KEY_SPACE, 
false );
    }

    
if (m_keyboard.get_key_state(KEY_1))
    {
        action |= PRESS_1;
        m_keyboard.m_locks[KEY_1] = 
true ;
        m_keyboard.set_key_state(KEY_1, 
false );
    }

    
if (m_keyboard.get_key_state(KEY_2))
    {
        action |= PRESS_2;
        m_keyboard.m_locks[KEY_2] = 
true ;
        m_keyboard.set_key_state(KEY_2, 
false );
    }
    
    
if (m_keyboard.get_key_state(KEY_3))
    {
        action |= PRESS_3;
        m_keyboard.m_locks[KEY_3] = 
true ;
        m_keyboard.set_key_state(KEY_3, 
false );
    }

    
return  action;
}

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

bool  cApp::check_intersect( float  x_start,  float  y_start,  float  z_start,
                           
float  x_end,    float  y_end,    float  z_end)
{
    
for (sMeshInfo* mesh_info = m_terrain_mesh.get_root_mesh(); mesh_info != NULL; mesh_info = mesh_info->m_next)
    {
        
if (is_ray_intersect_mesh(mesh_info->m_d3d_mesh, x_start, y_start, z_start, x_end, y_end, z_end, NULL))        
            
return   true ;        
    }
    
    
return   false ;
}

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