`
阿尔萨斯
  • 浏览: 4178563 次
社区版块
存档分类
最新评论

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

 
阅读更多
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog336280.html" frameborder="0" width="336" scrolling="no" height="280"></iframe>

本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday,欢迎转载,但必须保持全文完整,也必须包含本声明。
译者并示取得中文版的翻译授权,翻译本文只是出于研究和学习目的。任何人不得在未经同意的情况下将英文版和中文版用于商业行为,转载本文产生的法律和道德责任由转载者承担,与译者无关。
State-Driven Game Agent Design
状态驱动的游戏智能体设计(下)
Mat Buckland
(续上篇)
――――――――――――――――――――――――――――――――――
Making the State Base Class Reusable
编写可重用的State基类
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 entity_type></class>
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<miner></miner>
{
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<miner>* m_pGlobalState;</miner>
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<miner>* m_pCurrentState;</miner>
State<miner>* m_pPreviousState;</miner>
State<miner>* m_pGlobalState;</miner>
...
public:
void ChangeState(State<miner>* pNewState);</miner>
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 entity_type></class>
class StateMachine
{
private:
//a pointer to the agent that owns this instance
entity_type* m_pOwner;
State<entity_type>* m_pCurrentState;</entity_type>
//a record of the last state the agent was in
State<entity_type>* m_pPreviousState;</entity_type>
//this state logic is called every time the FSM is updated
State<entity_type>* m_pGlobalState;</entity_type>
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;}</entity_type>
void SetGlobalState(State<entity_type>* s) {m_pGlobalState = s;}</entity_type>
void SetPreviousState(State<entity_type>* s){m_pPreviousState = s;}</entity_type>
//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<entity_type>* pNewState)</entity_type>
{
assert(pNewState &&
"<:changestate>: trying to change to a null state");</:changestate>
//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<entity_type>* CurrentState() const{return m_pCurrentState;}</entity_type>
State<entity_type>* GlobalState() const{return m_pGlobalState;}</entity_type>
State<entity_type>* PreviousState() const{return m_pPreviousState;}</entity_type>
//returns true if the current state’s type is equal to the type of the
//class passed as a parameter.
bool isInState(const State<entity_type>&amp; st)const;</entity_type>
};
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 Minerclass now looks like this:
新实现的Miner类看起来就是这样的:
class Miner : public BaseGameEntity
{
private:
//an instance of the state machine class
StateMachine<miner>* m_pStateMachine;</miner>
/* 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<miner>(this);</miner>
m_pStateMachine->SetCurrentState(GoHomeAndSleepTilRested::Instance());
m_pStateMachine->SetGlobalState(MinerGlobalState::Instance());
}
~Miner(){delete m_pStateMachine;}
void Update()
{
++m_iThirst;
m_pStateMachine->Update();
}
StateMachine<miner>* GetFSM()const{return m_pStateMachine;}</miner>
/* 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.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 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项目的输出示例。
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...
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(射击)等战斗时需要的状态。
本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday,欢迎转载,但必须保持全文完整,也必须包含本声明。
译者并示取得中文版的翻译授权,翻译本文只是出于研究和学习目的。任何人不得在未经同意的情况下将英文版和中文版用于商业行为,转载本文产生的法律和道德责任由转载者承担,与译者无关。
全文完



分享到:
评论

相关推荐

    C++实现状态驱动智能体设计——消息功能

    设计精度的游戏趋向于事件驱动。即当一个事件发生了(武器发射了子弹等),事件被广播给游戏中的相关的对象。这样它们可以恰当地做出反应。而这个消息可以是立即执行,也可以设定多久后才执行。更多详情参见本人博客...

    有限状态机(FSM)

    游戏人工智能,状态驱动智能体设计——有限状态机(FSM),编译环境:VS2010。本人博客:http://blog.csdn.net/sinat_24229853

    基于强化学习和深度 Q 学习的 AI 驱动的蛇游戏python源码+项目说明.zip

    每次智能体执行一个动作时,环境都会给智能体一个奖励,奖励可以是正面的,也可以是负面的,这取决于该特定状态下动作的好坏程度。 深度强化学习 (DRL) 将 RL 的上述思想与深度神经网络相结合。神经网络学习“Q ...

    NodeCanvas 3.1.8.rar

    ● 图形、GameObject 和全局黑板变量,以创建可重复使用和以智能体为中心的参数行为。 ● 具有实例或静态属性和字段的数据绑定变量。 ● 使用 UNET 的网络同步变量 (Network Sync Variable)。 (由于现已弃用 UNET,...

    JAVA上百实例源码以及开源项目

    例如,容易实现协议的设计。 Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;...

    JAVA上百实例源码以及开源项目源代码

    例如,容易实现协议的设计。 Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在...

    c语言编写单片机技巧

    C语言是一种结构化程序设计语言,它支持当前程序设计中广泛采用的由顶向下结构化程序设计技术。此外,C语言程序具有完善的模块程序结构,从而为软件开发中采用模块化程序设计方法提供了有力的保障。因此,使用C语言...

    vc++ 应用源码包_6

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_5

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_1

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_2

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_3

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 开发实例源码包

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

Global site tag (gtag.js) - Google Analytics