智能驱动:状态驱动的游戏智能体设计( 3)



As the design stands, it’s necessary to create a separate Statebase for each character type to derive its states from. Instead, let’s make it reusable by turning it o a template. 作为立足的本有必要构造个独立State基类以供每个角色类类型获得自身状态我们可以通过类模板来使得它可重用:
template < entity_type>
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:
下面是MinerEnterMineAndDigForNugget状态:
EnterMineAndDigForNugget : public State<Miner>
{

public:

/* OMITTED */
};



This, as you will see ly, makes le 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 _disibledevent=>

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 that owns the FSM.
通常当设计有限状态机时候你最后都会在所有状态中出现重复代码例如Maxis开发流行游戏The Sims(第 2人生)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 template we have to declare the entity type
State<Miner>* m_pGlobalState;



[Page]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 s 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 s 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

Miner has acquired two extra member variables and _disibledevent=>到现在为了完成这些额外功能Miner类已经增加了两个成员变量和个思路方法它最后看起来就像这样(忽略无关元素):
Miner : public BaseGameEntity
{
private:

State<Miner>* m_pCurrentState;
State<Miner>* m_pPreviousState;
State<Miner>* m_pGlobalState;
...

public:

void ChangeState(State<Miner>* 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 o a state machine . 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 StateMachine template.
现在来看看StateMachine模板类
template < entity_type>
StateMachine
{
private:

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

State<entity_type>* m_pCurrentState;

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

//this state logic is called every time the FSM is updated
State<entity_type>* 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<entity_type>* s){m_pCurrentState = s;}
void SetGlobalState(State<entity_type>* s) {m_pGlobalState = s;}
void SetPreviousState(State<entity_type>* s){m_pPreviousState = s;}

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

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

//change to a state
void ChangeState(State<entity_type>* pNewState)
{
assert(pNewState &&
\"<StateMachine::ChangeState>: 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 state
m_pCurrentState = pNewState;

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

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

//accessors
State<entity_type>* CurrentState const{ m_pCurrentState;}
State<entity_type>* GlobalState const{ m_pGlobalState;}
State<entity_type>* PreviousState const{ m_pPreviousState;}

//s true the current state’s type is equal to the type of the
// passed as a parameter.
bool isInState(const State<entity_type>& st)const;
};





[Page]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功能
本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday欢迎转载但必须保持全文完整也必须包含本声明
译者并示取得中文版翻译授权翻译本文只是出于研究和学习目任何人不得在未经同意情况下将英文版和中文版用于商业行为转载本文产生法律和道德责任由转载者承担和译者无关
The improved Miner now looks like this:
新实现Miner类看起来就是这样:
Miner : public BaseGameEntity
{
private:

//an instance of the state machine
StateMachine<Miner>* m_pStateMachine;

/* EXTRANEOUS DETAIL OMITTED */

public:

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

{
// up state machine
m_pStateMachine = StateMachine<Miner>(this);

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

~Miner{delete m_pStateMachine;}

void Update
{
m_iThirst;
m_pStateMachine->Update;
}

StateMachine<Miner>* GetFSMconst{ m_pStateMachine;}

/* EXTRANEOUS DETAIL OMITTED */
};





Notice how the current and global states must be explicitly when a StateMachineis instantiated.The hierarchy is now like that shown in Figure 2.4.
注意StateMachine例子化后如何正确设计当前和全局状态2.4是现在类层次结构图
[Page]

\"\"\">
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 we. Elsa doesn’t do much; she’s ly 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.5Elsa状态转换图
\"\"
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 o 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 d, WesGlobalState, 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状态是如何以状态闪动形式实现(也就是它如何返回到前个状态)同样值得注意是定义了个全局状态——WesGlobalState它包含了Elsa上洗手间所需逻辑在全局状态中包含这逻辑是Elsa可能在任何时候都会感到内急这是天性哈哈
Here is a sample of the output from WestWorldWithWoman.
这里是WestWorldWithWoman

项目输出举例
MinerBob:Pickin\'upanugget
MinerBob:Ah\'mleavin\'thegoldminewithmahpocketsfullo\'sweetgold
MinerBob:Goin\'tothebank.Yessiree
Elsa:Walkin\'tothecan.Needtopowdamahprettyli\'lnose
Elsa:Ahhhhhh!Sweetrelief!
Elsa:Leavin\'thejohn
MinerBob:Depositin\'gold.Totalsavingsnow:4
MinerBob:Leavin\'thebank
MinerBob:Walkin\'tothegoldmine
Elsa:Walkin\'tothecan.Needtopowdamahprettyli\'lnose
Elsa:Ahhhhhh!Sweetrelief!
Elsa:Leavin\'thejohn
MinerBob:Pickin\'upanugget
Elsa:Moppin\'thefloor
MinerBob:Pickin\'upanugget
MinerBob:Ah\'mleavin\'thegoldminewithmahpocketsfullo\'sweetgold
MinerBob:Boy,ahsureisthusty!Walkin\'tothesaloon
Elsa:Moppin\'thefloor
MinerBob:That\'smightyfinesippin\'liquor
MinerBob:Leavin\'thesaloon,feelin\'good
MinerBob:Walkin\'tothegoldmine
Elsa:Makin\'thebed
MinerBob:Pickin\'upanugget
MinerBob:Ah\'mleavin\'thegoldminewithmahpocketsfullo\'sweetgold
MinerBob:Goin\'tothebank.Yessiree
Elsa:Walkin\'tothecan.Needtopowdamahprettyli\'lnose
Elsa:Ahhhhhh!Sweetrelief!
Elsa:Leavin\'thejohn
MinerBob:Depositin\'gold.Totalsavingsnow:5
MinerBob:Woohoo!Richenoughfornow.Backhometomahli\'llady
MinerBob:Leavin\'thebank
MinerBob:Walkin\'home
Elsa:Walkin\'tothecan.Needtopowdamahprettyli\'lnose
Elsa:Ahhhhhh!Sweetrelief!
Elsa:Leavin\'thejohn
MinerBob:ZZZZ...





[Page]
Well, that\'s it folks. The complexity of the behavior you can create with finite state machines is _disibledevent=>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(射击)等战斗时需要状态

本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday欢迎转载但必须保持全文完整也必须包含本声明
译者并示取得中文版翻译授权翻译本文只是出于研究和学习目任何人不得在未经同意情况下将英文版和中文版用于商业行为转载本文产生法律和道德责任由转载者承担和译者无关
Tags:  智能驱动

延伸阅读

最新评论

发表评论