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

天行健 君子當自強而不息

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 閱讀(333) 評論(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>
            久久久久久亚洲精品中文字幕| 亚洲黑丝一区二区| 亚洲国产毛片完整版| 国产欧美日韩精品丝袜高跟鞋| 一区二区三区高清不卡| 一区二区三区四区在线| 欧美国产日韩一区| 亚洲人成人99网站| 欧美成人在线网站| 亚洲美女黄色| 欧美在现视频| 在线免费高清一区二区三区| 久久亚洲免费| aⅴ色国产欧美| 美腿丝袜亚洲色图| 一本久久知道综合久久| 国产九区一区在线| 欧美a级片一区| 亚洲欧美在线网| 国产一区二区三区在线观看免费视频| 久久九九全国免费精品观看| 亚洲国产aⅴ天堂久久| 亚洲新中文字幕| 国产精品视频一二三| 久久人人爽爽爽人久久久| 久久人人爽国产| 欧美日本不卡| 欧美成人精品高清在线播放| 欧美精品一区视频| 国产情人节一区| 亚洲精选在线| 在线观看亚洲精品视频| 欧美三级特黄| 美国十次成人| 久久精品一区二区三区不卡牛牛| 久久婷婷激情| 国产精品久久999| 欧美日韩亚洲免费| 欧美www视频| 国产精品第一区| 曰本成人黄色| 欧美一级视频| 一本色道久久综合亚洲精品按摩| 欧美一区二区三区免费观看视频| 欧美国产欧美亚洲国产日韩mv天天看完整 | 久久综合九色综合网站| 亚洲午夜一区| 日韩午夜在线视频| 最新亚洲一区| 亚洲欧洲日韩综合二区| 亚洲欧美另类综合偷拍| 亚洲免费视频网站| 欧美日韩成人在线播放| 欧美日本乱大交xxxxx| 国产一区在线观看视频| 国产一区二区三区高清| 亚洲午夜小视频| 亚洲理论在线| 欧美精品电影| 国产精品久久久久久久久久久久久久| 欧美成人午夜视频| 精品91在线| 亚洲日韩视频| 日韩天堂av| 亚洲一区二区免费| 亚洲国产毛片完整版 | 欧美一区二区三区的| 亚洲国产精品一区二区尤物区| 久久高清一区| 免费国产一区二区| 韩国三级电影久久久久久| 国外成人在线视频| 久久久在线视频| 久久久免费av| 欧美日韩国产探花| 99精品视频一区| 亚洲精品黄色| 欧美日韩免费看| 亚洲影视中文字幕| 欧美a一区二区| 亚洲中字黄色| 国内精品久久久| 女女同性精品视频| 蜜臀久久99精品久久久画质超高清| 亚洲激情视频在线观看| 亚洲激情不卡| 国产精品自拍一区| 久久天堂成人| 亚洲欧美日韩国产另类专区| 国产欧美日韩亚洲精品| 久久综合久久综合久久| 欧美高清自拍一区| 午夜久久影院| 一区二区高清视频在线观看| 国产精品系列在线| 美女黄网久久| 欧美性做爰毛片| 亚洲精品综合精品自拍| 艳女tv在线观看国产一区| 国产免费观看久久| 欧美高清视频一区二区| 欧美在线高清| 欧美午夜精品电影| 久久精品最新地址| 亚洲一区二区三区免费观看| 欧美福利精品| 午夜精品久久久久久久久久久久久| 久久精品在线播放| 在线中文字幕一区| 久久精品国产清高在天天线| 一区二区日韩伦理片| 亚欧美中日韩视频| 国产欧美日韩另类一区 | 久久一区激情| 国产精品jizz在线观看美国| 男女精品网站| 国产色综合网| 性做久久久久久免费观看欧美| 久久久久国内| 久久av老司机精品网站导航| 亚洲午夜精品久久| 伊人激情综合| 亚洲伊人网站| 亚洲婷婷在线| 亚洲一区二区精品在线| 91久久精品国产91性色tv| 久久综合色天天久久综合图片| 午夜视频久久久久久| 亚洲性xxxx| 99国产成+人+综合+亚洲欧美| 久久精品人人做人人爽| 欧美一级午夜免费电影| 欧美日韩在线三区| 亚洲精品网站在线播放gif| 亚洲高清电影| 亚洲国产精品久久久久秋霞影院| 国产日韩综合一区二区性色av| 亚洲看片网站| 99精品99| 欧美激情国产日韩精品一区18| 你懂的视频一区二区| 极品尤物av久久免费看| 欧美与黑人午夜性猛交久久久| 亚洲男人的天堂在线| 亚洲欧美一区二区在线观看| 亚洲一区二区三区高清不卡| 欧美久久成人| 日韩一区二区精品葵司在线| 艳妇臀荡乳欲伦亚洲一区| 欧美日韩成人在线播放| 正在播放日韩| 在线成人h网| 久久婷婷久久| 欧美激情精品| 99精品国产在热久久| 欧美日韩三区四区| 99精品视频免费全部在线| 宅男精品视频| 国产伦一区二区三区色一情| 欧美一级播放| 麻豆国产精品va在线观看不卡| 在线成人黄色| 欧美日韩精品免费看| 一本久道久久久| 欧美在线国产精品| 国语自产精品视频在线看一大j8| 久久国产成人| 最新国产乱人伦偷精品免费网站| 一区二区三区波多野结衣在线观看| 欧美午夜精品电影| 欧美一级淫片播放口| 欧美福利电影在线观看| 一级日韩一区在线观看| 国产欧美日韩视频一区二区| 免费亚洲一区二区| 99国产精品久久久久久久久久| 先锋资源久久| 亚洲欧洲日本mm| 国产精品美女久久久久久2018 | 亚洲高清视频在线| 欧美精品91| 校园激情久久| 亚洲精品一区二区在线| 久久激情视频免费观看| 国产精品成av人在线视午夜片| 亚洲女ⅴideoshd黑人| 久久永久免费| 亚洲欧美国产77777| 影音先锋日韩精品| 国产精品欧美一区喷水| 欧美成年人网站| 欧美一区高清| 一区二区欧美激情| 欧美插天视频在线播放| 香蕉精品999视频一区二区| 亚洲国产精品第一区二区三区| 亚洲视频精品| 亚洲人成人一区二区在线观看| 久久精品国产99| 日韩午夜精品视频|