青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當自強而不息

Putting Together a Full Game(14)

 

Controlling Characters

The characters are the heart and soul of your game.

You derive the character controller in order to
control the player of the game and to collision-check a character's movements
against the maps. For The Tower, you can use a derived character controller,
to manage all your game's characters. The first step to
using the character controller in a game is to derive your own class from cCharController:

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

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

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

private:
    
virtual void drop_money(float x_pos, float y_pos, float z_pos, long quantity);
    
virtual bool gain_exp(sCharacter* character, long amount);
    
virtual bool pc_teleport(sCharacter* character, const sSpell* spell);

    
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);
    
virtual void play_action_sound(const sCharacter* character);
};

The cGameChars class comes with only one public function, attach_app. You use the cGameChars
function to set the application class pointer in the cGameChars class instance. In addition,
the cGameChars class overrides only the functions used to move the player and to validate
all character movements. The remaining functions come into play when the player
gains experience points from combat or teleports the character with a spell, when
the character controller plays a sound, when a monster drops some money, or
when a monster drops an item after being killed.

Because the derived character controller class requires access to the application
class, you must precede all calls to the cGameChars class with a call to the attach_app function.
The attach_app function takes one argument—the pointer to the application class.

The other functions, such as gain_exp, drop_money, tell the game engine
that a monster was killed and that the game needs to reward the player with experience,
money from a dying monster. These rewards are pushed
aside until combat ends, at which point, the application class's end_of_combat function
processes them.

void cGameChars::drop_money(float x_pos, float y_pos, float z_pos, long quantity)
{
    m_app->m_combat_money += quantity;
}

bool cGameChars::gain_exp(sCharacter* character, long amount)
{
    m_app->m_combat_exp += amount;

    
return false;   // do not display message
}

bool cGameChars::pc_teleport(sCharacter* character, const sSpell* spell)
{
    
// teleport player to town
    m_app->teleport_player(1, 100.0f, 0.0f, -170.0f);

    
return true;
}

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

bool cGameChars::validate_move(sCharacter* character, float* x_move, float* y_move, float* z_move)
{
    
float pos_x = character->pos_x;
    
float pos_y = character->pos_y;
    
float pos_z = character->pos_z;

    
// check against terrain mesh for collision
    if(m_app->check_intersect(pos_x, pos_y + 8.0f, pos_z,
                              pos_x + *x_move, pos_y + 8.0f + *y_move, pos_z + *z_move,
                              NULL))
        
return false;

    
// get new height
    float height = m_app->get_height_below(pos_x + *x_move, pos_y + 32.0f, pos_z + *z_move);
    *y_move = height - pos_y;

    
// check against barriers and clear movement if any
    if(m_app->m_barrier.get_barrier(pos_x + *x_move, pos_y + *y_move, pos_z + *z_move))
        (*x_move) = (*y_move) = (*z_move) = 0.0f;

    
return true;
}

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

void cGameChars::play_action_sound(const sCharacter* character)
{
    
long sound = 0;

    
// play sound based on character type and action
    switch(character->action)
    {
    
case CHAR_ATTACK:
        m_app->play_sound(character->id == ID_PLAYER ? SOUND_CHAR_ATTACK : SOUND_MONSTER_ATTACK);
        
break;

    
case CHAR_SPELL:
        
if(character->spell_index == SPELL_FIREBALL)
            sound = SOUND_FIREBALL;
        
else if(character->spell_index == SPELL_ICE)
            sound = SOUND_ICE;
        
else if(character->spell_index == SPELL_HEAL)
            sound = SOUND_HEAL;
        
else if(character->spell_index == SPELL_TELEPORT)
            sound = SOUND_TELEPORT;
        
else if(character->spell_index == SPELL_GROUNDBALL)
            sound = SOUND_GROUNDBALL;
        
else if(character->spell_index == SPELL_CONCUSSION)
            sound = SOUND_CONCUSSION;
        
else if(character->spell_index == SPELL_EVIL_FORCE)
            sound = SOUND_EVIL_FORCE;

        m_app->play_sound(sound);
        
break;

    
case CHAR_HURT:
        m_app->play_sound(character->id == ID_PLAYER ? SOUND_CHAR_HURT : SOUND_MONSTER_HURT);
        
break;

    
case CHAR_DIE:
        m_app->play_sound(character->id == ID_PLAYER ? SOUND_CHAR_DIE : SOUND_MONSTER_DIE);
        
break;
    }
}

The pc_update is the main function of interest here. It determines which keys the
player is pressing and what mouse button is being pressed. Now, take this function
apart to see what makes it tick:


void cGameChars::pc_update(sCharacter* character, long elapsed,
                           
float* x_move, float* y_move, float* z_move)
{
    
if(elapsed == 0)    // do not update if no elapsed time
        return;

    
// rotate character

    
if(m_app->m_keyboard.get_key_state(KEY_LEFT) || m_app->m_keyboard.get_key_state(KEY_A))
    {
        character->direction -= elapsed / 1000.0f * 4.0f;
        character->action = CHAR_MOVE;
    }

    
if(m_app->m_keyboard.get_key_state(KEY_RIGHT) || m_app->m_keyboard.get_key_state(KEY_D))
    {
        character->direction += elapsed / 1000.0f * 4.0f;
        character->action = CHAR_MOVE;
    }

    
// calculate move length along x,z axis

    
if(m_app->m_keyboard.get_key_state(KEY_UP) || m_app->m_keyboard.get_key_state(KEY_W))
    {
        
float speed = elapsed / 1000.0f * m_app->m_game_chars.get_speed(character);

        *x_move = sin(character->direction) * speed;
        *z_move = cos(character->direction) * speed;

        character->action = CHAR_MOVE;
    }

    
// process attack or talk action
    if(m_app->m_mouse.get_button_state(MOUSE_LBUTTON))
    {
        
// see which character is being pointed at and make sure if it is a monster.

        sCharacter* target = m_app->get_char_at(m_app->m_mouse.get_x_pos(), m_app->m_mouse.get_y_pos());

        
if(target != NULL)
        {
            
if(target->type == CHAR_NPC)    // handle talking to npcs
            {
                
// no distance checks, just process their script.

                
char filename[MAX_PATH];
                sprintf(filename, "..\\Data\\Char%lu.mls", target->id);

                m_app->m_game_script.execute(filename);
                
return// do not process anymore
            }
            
else if(target->type == CHAR_MONSTER)   // handle attacking monsters
            {
                
// get distance to target
                float x_diff = fabs(target->pos_x - character->pos_x);
                
float y_diff = fabs(target->pos_y - character->pos_y);
                
float z_diff = fabs(target->pos_z - character->pos_z);

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

                
// offset dist by target's radius
                float monster_radius = get_xz_radius(target);
                dist -= (monster_radius * monster_radius);

                
float attack_range = get_xz_radius(character) + character->char_def.attack_range;

                
// only perform attack if target in range
                if(dist <= (attack_range * attack_range))
                {
                    target->attacker  = character;
                    character->victim = target;

                    
// face victim
                    x_diff = target->pos_x - character->pos_x;
                    z_diff = target->pos_z - character->pos_z;
                    character->direction = atan2(x_diff, z_diff);

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

    
long spell_index = -1;

    
// cast magic spll based on NUM key pressed

    
if(m_app->m_keyboard.get_key_state(KEY_1))
    {
        m_app->m_keyboard.m_locks[KEY_1] = 
true;
        spell_index = SPELL_FIREBALL;
    }
    
else if(m_app->m_keyboard.get_key_state(KEY_2))
    {
        m_app->m_keyboard.m_locks[KEY_2] = 
true;
        spell_index = SPELL_ICE;
    }
    
else if(m_app->m_keyboard.get_key_state(KEY_3))
    {
        m_app->m_keyboard.m_locks[KEY_3] = 
true;
        spell_index = SPELL_HEAL;
    }
    
else if(m_app->m_keyboard.get_key_state(KEY_4))
    {
        m_app->m_keyboard.m_locks[KEY_4] = 
true;
        spell_index = SPELL_TELEPORT;
    }
    
else if(m_app->m_keyboard.get_key_state(KEY_5))
    {
        m_app->m_keyboard.m_locks[KEY_5] = 
true;
        spell_index = SPELL_GROUNDBALL;
    }

    
// cast spell if commanded
    if(spell_index != -1)
    {
        sSpell* spell = m_app->m_game_spells.get_spell(spell_index);

        
// only cast if spell known and has enough mana points
        if(char_can_spell(character, spell, spell_index))
        {
            
// see which character is being pointed
            sCharacter* target = m_app->get_char_at(m_app->m_mouse.get_x_pos(), m_app->m_mouse.get_y_pos());

            
if(target && target->type == CHAR_MONSTER)
            {
                
// get distance to target

                
float x_diff = fabs(target->pos_x - character->pos_x);
                
float y_diff = fabs(target->pos_y - character->pos_y);
                
float z_diff = fabs(target->pos_z - character->pos_z);

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

                
// offset dist by target's radius
                float target_radius = get_xz_radius(target);
                dist -= (target_radius * target_radius);

                
float spell_range = get_xz_radius(character) + spell->max_dist;
        
                
// only perform spell if target in range
                if(dist <= (spell_range * spell_range))
                {
                    character->spell_index = spell_index;
                    character->target_type = CHAR_MONSTER;
                    character->target_x    = target->pos_x;
                    character->target_y    = target->pos_y;
                    character->target_z    = target->pos_z;

                    *x_move = *y_move = *z_move = 0.0f;     
// clear movement

                    // face victim
                    x_diff = target->pos_x - character->pos_x;
                    z_diff = target->pos_z - character->pos_z;

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

                    set_char_action(character, CHAR_SPELL, 0);
                }
            }
            
else if(target == character)
            {
                
if((spell_index == SPELL_HEAL && character->health_points < character->char_def.health_points) ||
                   (spell_index == SPELL_TELEPORT))
                {
                    character->spell_index = spell_index;
                    character->target_type = CHAR_PC;
                    character->target_x    = target->pos_x;
                    character->target_y    = target->pos_y;
                    character->target_z    = target->pos_z;

                    *x_move = *y_move = *z_move = 0.0f;     
// clear movement

                    set_char_action(character, CHAR_SPELL, 0);
                }
            }
        }
    }

    
// enter status frame if right mouse buttom pressed
    if(m_app->m_mouse.get_button_state(MOUSE_RBUTTON))
    {
        m_app->m_mouse.m_locks[MOUSE_RBUTTON] = 
true;
        m_app->m_state_manager.push(status_frame, m_app);
    }
}

pc_update starts by first determining whether an update is in order (based on
whether any time has elapsed) and continues by determining which keys (if any)
are pressed on the keyboard. If the up arrow key is pressed, the character moves
forward, whereas if the left or right arrow keys are pressed, the character’s direction
is modified.

For each movement that the player performs, such as walking forward or turning
left and right, you need to assign the CHAR_MOVE action to the player's character.
Notice that even though pressing left or right immediately rotates the player’s character,
the code does not immediately modify the character’s coordinates. Instead,
you store the direction of travel in the x_move and z_move variables.

You then determine whether the player has clicked the left mouse button. Remember
from the design of the sample game that clicking the left mouse button on a nearby
character either attacks the character (if the character is a monster) or speaks to the
character (if the character is an NPC).

The portion of code just shown calls upon the get_char_at function, which scans
for the character that is positioned under the mouse cursor. If a character is found,
you determine which type of character it is; if it is an NPC, you execute the appropriate
character's script.

On the other hand, if the character clicked is a monster and that monster is within
attack range, you initiate an attack action.

Coming up to the end of the pc_update function, the controller needs to determine
whether a spell has been cast at a nearby character. In the game, positioning the
mouse cursor over a character and pressing one of the number keys (from 1 through
5) casts a spell.

If a spell was cast, the controller determines whether the player knows the spell and
has enough mana to cast the spell and whether the target character is in range.

At this point, the controller has determined that the spell can be cast. You need
to store the coordinates of the target, the number of the spell being cast, and the
player's action in the structure pointed to by the Character pointer.

To finish up the player character update, the controller determines whether the
player clicked the right mouse button, which opens the character’s status window
(by pushing the character-status state onto the state stack).

posted on 2007-12-30 00:24 lovedday 閱讀(336) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


公告

導航

統計

常用鏈接

隨筆分類(178)

3D游戲編程相關鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产一区视频| 免费日韩视频| 久久精品女人的天堂av| 欧美 日韩 国产一区二区在线视频| 国产情侣一区| 亚洲婷婷综合久久一本伊一区| 久久久久久久久一区二区| 最近中文字幕日韩精品 | 久久国产精品99国产精| 女人天堂亚洲aⅴ在线观看| 亚洲国产视频a| 亚洲久色影视| 欧美国产日韩视频| 国产亚洲综合在线| 亚洲免费在线| 99精品国产一区二区青青牛奶| 久久精品视频免费| 亚洲欧洲久久| 亚洲国产欧洲综合997久久| 久久精品视频免费| 日韩五码在线| 亚洲人成网站在线观看播放| 久久麻豆一区二区| 欧美日韩免费一区| 亚洲精品国产精品乱码不99按摩| 免费成人av| 久久精品国产亚洲一区二区| 亚洲国产片色| 亚洲综合日本| 国产一区二区三区av电影| 欧美激情在线狂野欧美精品| 狼狼综合久久久久综合网| 国产综合色产| 久久一区二区三区超碰国产精品| 亚洲欧美电影在线观看| 亚洲国产精品一区二区尤物区| 久久综合伊人77777| 久久久久久穴| 亚洲欧美日韩天堂一区二区| 久久亚洲午夜电影| 欧美一级黄色录像| 亚洲免费影视| 一区二区三区四区五区精品视频| 日韩视频在线观看国产| 欧美午夜精品久久久久久浪潮| 亚洲永久精品大片| 亚洲欧美在线播放| 亚洲国产精品一区二区第一页 | 亚洲激情精品| 国产一区二区三区黄视频| 一本色道久久综合亚洲91| 国产精品资源| 蜜月aⅴ免费一区二区三区 | 你懂的视频一区二区| 久久久欧美精品| 久久一区二区三区国产精品 | 一本在线高清不卡dvd| 99精品久久| 99re热这里只有精品免费视频| 久久精品道一区二区三区| 欧美在线精品免播放器视频| 另类欧美日韩国产在线| 久久九九99| 国产亚洲欧美一区在线观看| 午夜久久tv| 亚洲伦理自拍| 欧美一级午夜免费电影| 亚洲精品一区二区三区樱花| 噜噜噜噜噜久久久久久91| 亚洲性人人天天夜夜摸| 久久精品网址| 欧美va日韩va| 国产精品永久| 欧美伊人久久久久久午夜久久久久| 亚洲激情偷拍| 免费精品99久久国产综合精品| 免费影视亚洲| 日韩视频在线一区| 欧美日韩亚洲一区三区| 亚洲图片激情小说| 日韩视频免费观看高清完整版| 欧美顶级艳妇交换群宴| 久久久久国产精品www| 韩日视频一区| 午夜精品免费在线| 久久先锋资源| 亚洲精品视频在线观看免费| 欧美日韩国产在线播放网站| 欧美激情第8页| 中文亚洲字幕| 国产欧美日韩不卡| 麻豆久久婷婷| 一区二区三区日韩精品| 欧美主播一区二区三区| 1769国产精品| 久久夜色精品| 亚洲人被黑人高潮完整版| 亚洲欧美不卡| 亚洲电影专区| 国产精品ⅴa在线观看h| 久久精品国语| 中文欧美字幕免费| 亚洲在线第一页| 在线观看91精品国产入口| 久久久精品国产一区二区三区| 亚洲国产欧美一区二区三区久久| 亚洲免费视频在线观看| 一区三区视频| 久热精品视频在线免费观看| 一本久久a久久免费精品不卡| 久久久亚洲午夜电影| 99re这里只有精品6| 国内精品模特av私拍在线观看| 欧美激情亚洲视频| 9久草视频在线视频精品| 久久免费视频这里只有精品| 一区二区激情| 亚洲激情社区| 韩国久久久久| 国产欧美精品一区二区色综合 | 久久综合九色综合网站| 亚洲一区二区久久| 久久久国产精品一区二区中文| 日韩视频在线播放| 伊人精品视频| 国产亚洲一区二区三区在线观看 | 欧美大成色www永久网站婷| 日韩视频在线观看| 国产精品v欧美精品v日韩 | 亚洲综合成人婷婷小说| 亚洲国产日韩综合一区| 久久久久高清| 欧美在线黄色| 欧美一二三视频| 亚洲欧美日韩国产精品| 99国产一区二区三精品乱码| 亚洲高清网站| 亚洲福利在线观看| 在线播放日韩专区| 在线观看精品| 在线成人小视频| ●精品国产综合乱码久久久久| 国产专区一区| 韩国女主播一区| 樱桃成人精品视频在线播放| 狠狠色狠狠色综合人人| 狠狠色综合网| 亚洲国产欧美不卡在线观看| 在线观看日韩av先锋影音电影院| 狠狠色狠狠色综合系列| 激情文学一区| 亚洲国产精品成人久久综合一区| 亚洲高清不卡在线| 亚洲毛片网站| 亚洲性视频网址| 欧美影视一区| 夜夜嗨av一区二区三区中文字幕| 最新精品在线| 亚洲视频一二| 午夜在线精品偷拍| 久久久欧美精品sm网站| 欧美多人爱爱视频网站| 亚洲精品乱码久久久久久蜜桃麻豆| 亚洲第一网站| 久热爱精品视频线路一| 欧美国产精品中文字幕| 亚洲欧洲中文日韩久久av乱码| 日韩视频在线观看一区二区| 中日韩男男gay无套| 欧美在线亚洲在线| 欧美va天堂va视频va在线| 欧美日韩一区二区三区在线观看免| 国产精品欧美一区喷水 | 欧美亚洲免费电影| 久久久欧美精品| 欧美破处大片在线视频| 另类成人小视频在线| 欧美日韩少妇| 国产原创一区二区| 99国产精品私拍| 久久久精品999| 亚洲国产精品一区二区第四页av | 亚洲欧洲一区二区在线观看| 国产精品99久久久久久白浆小说| 欧美在线亚洲一区| 欧美日韩国产专区| 在线观看精品| 性18欧美另类| 亚洲精品在线电影| 久久久国产91| 国产精品久久国产三级国电话系列| 欧美日韩中文字幕精品| 欧美日韩一区二区三区四区五区| 国内精品久久久久伊人av| 一区二区久久久久久| 女人天堂亚洲aⅴ在线观看| 亚洲伊人伊色伊影伊综合网| 欧美精品午夜| 亚洲国产欧美另类丝袜| 久久综合狠狠综合久久综合88|