天行健 君子当自强而不息

Controlling Players and Characters(34)

Once it is determined what action each character wants to perform, that action
must be validated. Characters moving around can’t walk through other players
(except for PCs, who can walk through other PCs). Also, depending on your levels,
you use a function to determine character-to-map collisions. These two validation
functions are as follows:

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

bool cCharController::check_move(sCharacter* character, float* x_move, float* y_move, float* z_move)
{    
    
if(character == NULL)
        
return false;

    
float pos_x = character->pos_x + (*x_move);
    
float pos_y = character->pos_y + (*y_move);
    
float pos_z = character->pos_z + (*z_move);

    
float min_x, min_z, max_x, max_z;

    character->
object.get_bounds(&min_x, NULL, &min_z, &max_x, NULL, &max_z, NULL);
    
float radius1 = max(max_x - min_x, max_z - min_z) * 0.5;

    
// check movement against other characters
    for(sCharacter* char_ptr = m_root_char; char_ptr != NULL; char_ptr = char_ptr->next)
    {
        
// do not check against self or disabled characters
        if(character != char_ptr && char_ptr->update_enable)
        {
            
// do not check against other PC characters
            if(character->type == CHAR_PC && char_ptr->type == CHAR_PC)
                
break;

            
// get distance between characters
            float x_diff = fabs(pos_x - char_ptr->pos_x);
            
float y_diff = fabs(pos_y - char_ptr->pos_y);
            
float z_diff = fabs(pos_z - char_ptr->pos_z);

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

            char_ptr->
object.get_bounds(&min_x, NULL, &min_z, &max_x, NULL, &max_z, NULL);
            
float radius2 = max(max_x - min_x, max_z - min_z) * 0.5f;

            
// do not allow movement if intersecting
            if(dist <= (radius1 * radius1 + radius2 * radius2))
                
return false;
        }        
    }

    
// check custom collisions (map, etc)
    return validate_move(character, x_move, y_move, z_move);
}

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

virtual bool validate_move(sCharacter* character, float* x_move, float* y_move, float* z_move)
{
        
// validate for outside bounds checking against character movements.

        
return true;
}

Both of the preceding functions (check_move and validate_move) take a pointer to the
character being updated, as well as the character’s intended amount of movement
in each direction. Each function modifies these values appropriately. When the
character’s moves and actions have been validated, another function wraps up the
actions and actually updates the character positions and actions.


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

void cCharController::process_update(sCharacter* character, float x_move, float y_move, float z_move)
{
    
// move character
    character->pos_x += x_move;
    character->pos_y += y_move;
    character->pos_z += z_move;        

    
// move object and point in direction
    character->object.move(character->pos_x, character->pos_y, character->pos_z);
    character->
object.rotate(0.0f, character->direction, 0.0f);

    
// set new animation
    if(character->last_anim != character->action)
    {
        character->last_anim = character->action;

        
if(m_num_char_anim != 0 && m_char_anim)
        {
            character->last_anim_time = timeGetTime() / 30;

            character->
object.set_anim_set(
                &m_mesh_anim[character->char_def.mesh_index].anim,
                m_char_anim[character->action].name,
                character->last_anim_time);
        }
    }
}

Whenever characters start battling it out, some are sure to die. The controller can
quickly handle dying NPCs and monsters by removing their respective structures
from the list. As for PCs though, death can mean the end of the game, so it’s up to
the main application to handle them. That’s the reasoning behind pc_death, which
takes a single argument, the pointer to the dying PC:

virtual void pc_death(sCharacter* character)
{
}

Speaking of characters dying, any time a monster dies, it has a chance of dropping
an item, as well as all the money it is carrying. Because your main application handles
all items in the maps, it’s your job to determine when a monster drops an item
or gold and to add the appropriate item to the map’s list of items. Overriding the
following two functions will help you out anytime a monster drops something by
giving you the exact coordinates where the monster perished, the item dropped,
and the amount of money dropped.

virtual bool drop_money(float pos_x, float pos_y, float pos_z, long quantity)
{
  return true;
}

virtual bool drop_item(float pos_x, float pos_y, float pos_z, long item_index)
{
  return true;
}


posted on 2007-12-04 16:47 lovedday 阅读(203) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论