遊戲程式開發:狀態驅動的遊戲智能體設計(三)

來源:互聯網
上載者:User

轉自:

狀態驅動的遊戲智能體設計(一)

http://edu.gamfe.com/tutor/d/30601.html

狀態驅動的遊戲智能體設計(二)

http://edu.gamfe.com/tutor/d/30600.html

狀態驅動的遊戲智能體設計(三)

http://edu.gamfe.com/tutor/d/39940.html

狀態驅動的遊戲智能體設計(三)

As the design stands, it’s necessary to create a separate Statebase class for each character type to derive its states from. Instead, let’s make it reusable by turning it into a class template.
作為立足之本,有必要構造一個獨立的State基類,以供每一個角色類類型獲得自身的狀態。我們可以通過類模板來使得它可重用:
template
class State
{
public:

virtual void Enter(entity_type*)=0;

virtual void Execute(entity_type*)=0;

virtual void Exit(entity_type*)=0;

virtual ~State(){}
};

The declaration for a concrete state — using the EnterMineAndDigForNuggetminer state as an example — now looks like this:
下面是Miner類的EnterMineAndDigForNugget狀態:
class EnterMineAndDigForNugget : public State
{

public:

/* OMITTED */
};

This, as you will see shortly, makes life easier in the long run.
如你所見,它短小精悍。
Global States and State Blips
全域狀態和狀態閃動(誠心求更好的譯法)
More often than not, when designing finite state machines you will end up with code that is duplicated in every state. For example, in the popular game The Sims by Maxis, a Sim may feel the urge of nature come upon it and have to visit the bathroom to relieve
itself. This urge may occur in any state the Sim may be in and at any time. Given the current design, to bestow the gold miner with this type of behavior, duplicate conditional logic would have to be added to every one of his states, or alternatively, placed
into the Miner::Updatefunction. While the latter solution is accept- able, it’s better to create a global statethat is called every time the FSM is updated. That way, all the logic for the FSM is contained within the states and not in the agent class that
owns the FSM.
通常當設計有限狀態機器的時候,你最後都會在所有狀態中出現重複代碼。例如,在Maxis開發的流行遊戲《The Sims(第二人生)》中,Sim可以感受到內急等生理需要,必須去洗手間解決。無論Sim在哪裡、在什麼時間,內急都可能發生。根據當前的設計,給淘金者加上這樣一種行為,重複的條件邏輯就可能增加到每一個狀態,或者放到Miner::Update函數裡。下面介紹一個可接受的解決方案,它增加了一個全域狀態——供FSM更新的時候調用。這樣,FSM的所有的邏輯都包含在狀態內,而不在智能體類的FSM裡。
To implement a global state, an additional member variable is required:
實現全域狀態,需要增加一個成員變數:
//notice how now that State is a class template we have to declare the entity type
State* m_pGlobalState;

In addition to global behavior, occasionally it will be convenient for an agent to enter a state with the condition that when the state is exited, the agent returns to its previous state. I call this behavior a state blip. For example, just as in The Sims,
you may insist that your agent can visit the bathroom at any time, yet make sure it always returns to its prior state. To give an FSM this type of functionality it must keep a record of the previous state so the state blip can revert to it. This is easy to
do as all that is required is another member variable and some additional logic in the Miner::ChangeStatemethod.
有時智能體從一個狀態進入另一個狀態,當它退出這個狀態時需要回到它的前一個狀態,我將之稱為狀態閃動。例如就像《The Sims》中你可能必須讓你的智能體能夠在任何時間進入洗手間,之後再回到之前的狀態。要實現這樣的功能,就必須記錄前一個狀態,以便在狀態閃動時返回。這可以容易地通過增加成員變數和對Miner::ChangeState方法增加一些額外邏輯來實現。
[譯註:狀態閃動這一概念的確比較難以理解。所以我畫了下面這一張圖來協助理解]

譯註圖1狀態閃動
By now though, to implement these additions, the Minerclass has acquired two extra member variables and one additional method. It has ended up looking something like this (extraneous detail omitted):
到現在,為了完成這些額外功能,Miner類已經增加了兩個成員變數和一個方法。它最後看起來就像這樣(忽略無關元素):
class Miner : public BaseGameEntity
{
private:

State* m_pCurrentState;
State* m_pPreviousState;
State* m_pGlobalState;
...

public:

void ChangeState(State* pNewState);
void RevertToPreviousState();
...
};

Hmm, looks like it’s time to tidy up a little.
嗯,的確需要整理一下。
Creating a State Machine Class
建立一個狀態機器類
The design can be made a lot cleaner by encapsulating all the state related data and methods into a state machine class. This way an agent can own an instance of a state machine and delegate the management of current states, global states, and previous states
to it.
把所有的狀態有關的資料和方法封裝到一個狀態機器類裡有利於精簡設計。這使智能體能夠擁有一個狀態機器執行個體並委派它管理目前狀態、全域狀態和前一個狀態。
With this in mind take a look at the following StateMachineclass template.
現在來看看StateMachine模板類。
template
class StateMachine
{
private:

//a pointer to the agent that owns this instance
entity_type* m_pOwner;

State* m_pCurrentState;

//a record of the last state the agent was in
State* m_pPreviousState;

//this state logic is called every time the FSM is updated
State* m_pGlobalState;

public:

StateMachine(entity_type* owner):m_pOwner(owner),
m_pCurrentState(NULL),
m_pPreviousState(NULL),
m_pGlobalState(NULL)
{}

//use these methods to initialize the FSM
void SetCurrentState(State* s){m_pCurrentState = s;}
void SetGlobalState(State* s) {m_pGlobalState = s;}
void SetPreviousState(State* s){m_pPreviousState = s;}

//call this to update the FSM
void Update()const
{
//if a global state exists, call its execute method
if (m_pGlobalState) m_pGlobalState->Execute(m_pOwner);

//same for the current state
if (m_pCurrentState) m_pCurrentState->Execute(m_pOwner);
}

//change to a new state
void ChangeState(State* pNewState)
{
assert(pNewState &&
": trying to change to a null state");

//keep a record of the previous state
m_pPreviousState = m_pCurrentState;

//call the exit method of the existing state
m_pCurrentState->Exit(m_pOwner);

//change state to the new state
m_pCurrentState = pNewState;

//call the entry method of the new state
m_pCurrentState->Enter(m_pOwner);
}

//change state back to the previous state
void RevertToPreviousState()
{
ChangeState(m_pPreviousState);
}

//accessors
State* CurrentState() const{return m_pCurrentState;}
State* GlobalState() const{return m_pGlobalState;}
State* PreviousState() const{return m_pPreviousState;}

//returns true if the current state’s type is equal to the type of the
//class passed as a parameter.
bool isInState(const State& st)const;
};
Now all an agent has to do is to own an instance of a StateMachineand implement a method to update the state machine to get full FSM functionality.
現在所有的智能體都能夠擁有一個StateMachine執行個體,需要做的就是實現一個方法來更新狀態機器以獲得完整的FSM功能。

譯者並示取得中文版的翻譯授權,翻譯本文只是出於研究和學習目的。任何人不得在未經同意的情況下將英文版和中文版用於商業行為,轉載本文產生的法律和道德責任由轉載者承擔,與譯者無關。
The improved Minerclass now looks like this:
新實現的Miner類看起來就是這樣的:
class Miner : public BaseGameEntity
{
private:

//an instance of the state machine class
StateMachine* m_pStateMachine;

/* EXTRANEOUS DETAIL OMITTED */

public:

Miner(int id):m_Location(shack),
m_iGoldCarried(0),
m_iMoneyInBank(0),
m_iThirst(0),
m_iFatigue(0),
BaseGameEntity(id)

{
//set up state machine
m_pStateMachine = new StateMachine(this);

m_pStateMachine->SetCurrentState(GoHomeAndSleepTilRested::Instance());
m_pStateMachine->SetGlobalState(MinerGlobalState::Instance());
}

~Miner(){delete m_pStateMachine;}

void Update()
{
++m_iThirst;
m_pStateMachine->Update();
}

StateMachine* GetFSM()const{return m_pStateMachine;}

/* EXTRANEOUS DETAIL OMITTED */
};

Notice how the current and global states must be set explicitly when a StateMachineis instantiated.The class hierarchy is now like that shown in Figure 2.4.
注意StateMachine執行個體化後如何正確設計當前和全域狀態。圖2.4是現在的類階層圖。

Figure 2.4. The updated design
Introducing Elsa
介紹Elsa
To demonstrate these improvements, I’ve created another project: WestWorldWithWoman. In this project, West World has gained another inhabitant, Elsa, the gold miner’s wife. Elsa doesn’t do much; she’s mainly preoccupied with cleaning the shack and emptying
her bladder (she drinks way too much cawfee). The state transition diagram for Elsa is shown in Figure 2.5.
為了驗證這些改進,我建立了一個新的項目——WestWorldWithWoman。在這個項目裡,WestWorld多了一個人物——Elsa,她是淘金者Bob的妻子。Elsa做的事不多,主要是打掃房子和上洗手間(她喝了太多咖啡)。圖2.5是Elsa的狀態轉換圖。

Figure 2.5. Elsa’s state transition diagram. The global state is not shown in the figure because its logic is effectively implemented in any state and never changed.
When you boot up the project into your IDE, notice how the VisitBathroomstate is implemented as a blip state (i.e., it always reverts back to the previous state). Also note that a global state has been defined, WifesGlobalState, which contains the logic required
for Elsa’s bathroom visits. This logic is contained in a global state because Elsa may feel the call of nature during any state and at any time.
當你把這個項目匯入到你的IDE的時候,注意VisitBathroom狀態是如何以狀態閃動的形式實現的(也就是它如何返回到前一個狀態),同樣值得注意的是定義了一個全域狀態——WifesGlobalState,它包含了Elsa上洗手間所需的邏輯。在全域狀態中包含這一邏輯是因為Elsa可能在任何時候都會感到內急,這是天性,哈哈。
Here is a sample of the output from WestWorldWithWoman.
這裡是WestWorldWithWoman項目的輸出樣本。

Miner Bob: Pickin' up a nugget
Miner Bob: Ah'm leavin' the gold mine with mah pockets full o' sweet gold
Miner Bob: Goin' to the bank. Yes siree
Elsa: Walkin' to the can. Need to powda mah pretty li'l nose
Elsa: Ahhhhhh! Sweet relief!
Elsa: Leavin' the john
Miner Bob: Depositin' gold. Total savings now: 4
Miner Bob: Leavin' the bank
Miner Bob: Walkin' to the gold mine
Elsa: Walkin' to the can. Need to powda mah pretty li'l nose
Elsa: Ahhhhhh! Sweet relief!
Elsa: Leavin' the john
Miner Bob: Pickin' up a nugget
Elsa: Moppin' the floor
Miner Bob: Pickin' up a nugget
Miner Bob: Ah'm leavin' the gold mine with mah pockets full o' sweet gold
Miner Bob: Boy, ah sure is thusty! Walkin' to the saloon
Elsa: Moppin' the floor
Miner Bob: That's mighty fine sippin' liquor
Miner Bob: Leavin' the saloon, feelin' good
Miner Bob: Walkin' to the gold mine
Elsa: Makin' the bed
Miner Bob: Pickin' up a nugget
Miner Bob: Ah'm leavin' the gold mine with mah pockets full o' sweet gold
Miner Bob: Goin' to the bank. Yes siree
Elsa: Walkin' to the can. Need to powda mah pretty li'l nose
Elsa: Ahhhhhh! Sweet relief!
Elsa: Leavin' the john
Miner Bob: Depositin' gold. Total savings now: 5
Miner Bob: Woohoo! Rich enough for now. Back home to mah li'l lady
Miner Bob: Leavin' the bank
Miner Bob: Walkin' home
Elsa: Walkin' to the can. Need to powda mah pretty li'l nose
Elsa: Ahhhhhh! Sweet relief!
Elsa: Leavin' the john
Miner Bob: ZZZZ...

Well, that's it folks. The complexity of the behavior you can create with finite state machines is only limited by your imagination. You don’t have to restrict your game agents to just one finite state machine either. Sometimes it may be a good idea to use
two FSMs working in parallel: one to control a character’s movement and one to control the weapon selection, aiming, and firing, for example. It’s even possible to have a state itself contain a state machine. This is known as a hierarchical state machine.
For instance, your game agent may have the states Explore, Combat, and Patrol. In turn, the Combat state may own a state machine that manages the states required for combat such as Dodge, ChaseEnemy, and Shoot.
誇張點說,這相當了不起啊。你能夠用有限狀態機器創造非常複雜的行為,到底有多複雜僅受限於你的相像力。你無需限制你的遊戲智能體只能有一個有限狀態機器,有時候你可以使用兩個FSM來並行工作:一個控制角色的移動,而另一個控制武器選擇、瞄準和開火。你甚至可以創造包含狀態機器的狀態機器,即分級狀態機器。例如你的遊戲智能體可能有Explore(探測)、Combat(戰鬥)和Patrol(邏輯)等狀態,而Combat(戰鬥)狀態又可以擁有一個狀態機器來管理Dodge(躲避)、ChaseEnemy(追逃)和Shoot(射擊)等戰鬥時需要的狀態。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.