`
javayestome
  • 浏览: 1061740 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

阅读更多

本文由恋花蝶最初发表于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 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>
{
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;
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;
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 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 StateMachine
{
private:
//a pointer 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 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)
{
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 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;}
State<entity_type>* GlobalState() const{return m_pGlobalState;}
State<entity_type>* 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<entity_type>& 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功能。
本文由恋花蝶最初发表于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;
/* 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);
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;}
/* 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 ...

    《游戏编程精粹》AI程序设计源代码

    对于多人在线游戏,可能会涉及到合作与竞争的AI策略,如多智能体系统(Multi-Agent System, MAS)。在这种环境中,每个AI都要与其他AI进行交互,以达到各自的目标或团队目标。 同时,书中可能还会包含一些模拟和...

    2020级中山大学软件工程3D游戏编程与设计

    这门课程涵盖了游戏开发的关键领域,包括但不限于游戏引擎的使用、3D建模、动画制作、物理模拟、人工智能以及用户交互设计。 1. **游戏引擎**:游戏引擎是游戏开发的核心,如Unity或Unreal Engine。这些引擎提供了...

    智能移动终端应用开发设计报告Android-贪吃蛇.doc

    1. **图形界面**:游戏界面需要使用Android的图形库(如Canvas或OpenGL ES)来绘制蛇、食物和游戏区域,同时实时更新屏幕内容以反映游戏状态。 2. **事件处理**:通过监听触摸屏事件来控制蛇的移动,这涉及到Android...

    multiagent.zip_AI assignment2_learnmtt

    MDP)的理论和技术,特别是多智能体环境下的学习方法,如多智能体强化学习(Multi-Agent Reinforcement Learning, MARL)。 描述中提到,这是伯克利大学2014年AI课程的一部分,暗示了这个作业可能基于经典的Pacman...

    3D 游戏程序设计入门

    理解状态机、事件驱动编程和行为树可以帮助设计游戏规则和角色智能。简单的AI,如追逐、回避或路径寻找,是初学者可以着手实现的项目。 最后,游戏性能优化是确保游戏流畅运行的关键。这包括减少Draw Call、优化...

    VC版人工智能俄罗斯方块

    《VC版人工智能俄罗斯方块》是一款基于Visual C++编写的具有人工智能元素的俄罗斯方块游戏。这个项目不仅提供了传统俄罗斯方块的基本玩法,更引入了AI算法,使得游戏更具挑战性和趣味性。以下是对该项目中涉及的主要...

    人工智能 (3).ppt

    10. **多Agent系统**:研究多个智能体间的互动行为,常见于多人在线游戏。 11. **人工生命**:模拟生物系统的行为,如群组行为,如羊群移动。 12. **机器人技术**:让虚拟角色在复杂环境中互动。 13. **遗传算法**:...

    三款经典android小游戏源码分析.7z

    4. **状态机(State Machine)**:游戏通常包含多个状态(如开始、暂停、游戏结束等),状态机设计模式在此非常有用。每个游戏都会有自己的状态管理机制,确保游戏流程的正确切换。 5. **数据结构与算法**:猜牌...

    java版贪食蛇、贪食蛇游戏源码、j2me游戏源码、触屏游戏源码、j2me实例

    Java版的贪食蛇游戏是基于Java Micro Edition (J2ME) 平台开发的一款经典游戏,它在移动设备上非常流行,尤其是早期的智能手机和平板电脑。J2ME是Java的一个子集,专为资源有限的嵌入式设备如手机、电视盒等设计,...

    java经典小游戏源码大集合

    3. **五子棋**:五子棋是一种策略游戏,Java实现时需要设计棋盘状态的表示和转换,实现人工智能算法(如Minimax或Alpha-Beta剪枝)来让计算机进行智能决策。此外,还需要处理玩家输入和游戏结束条件。 4. **连连看*...

    simspark源码

    通过分析源码,我们可以了解其内部工作原理,例如事件驱动的仿真循环、智能体的决策机制以及环境的物理规则。 3. **核心引擎** 核心引擎是SimSpark的核心部分,它负责管理仿真时间、智能体的生命周期、消息传递和...

    人工智能之计算机博弈相关研究报告.doc

    此外,多智能体博弈、模糊逻辑、遗传算法等也是研究的重点,它们旨在进一步增强计算机博弈的智能表现和适应性。 总的来说,计算机博弈不仅是人工智能领域的一项基础研究,也是推动智能决策和机器学习技术发展的驱动...

    基于深度强化学习的智能频谱分配策略研究.pdf

    深度强化学习通过让智能体(即算法的代理)在未知的频谱环境下不断尝试和探索,根据当前环境状态和历史经验,自动调整信道选择策略。这种策略能够有效应对复杂的网络环境,同时在网络环境变化时,智能体能够快速调整...

    html5 qq表情消除小游戏源码下载

    8. **Game Loop**:游戏循环是所有游戏的核心,它不断更新游戏状态、处理用户输入、绘制屏幕,并确保游戏的流畅性。在这个QQ表情消除游戏中,JavaScript中的定时器常被用来实现游戏循环。 9. **事件驱动编程**:...

    利用python制作与4399等概念的5433小游戏平台

    在这个5433小游戏平台上,Tkinter被用来设计各种游戏界面,如游戏规则、游戏板以及按钮和文本框等元素。通过Tkinter,开发者可以自定义窗口大小、颜色、字体和布局,以满足游戏的视觉需求。例如,井字棋界面可能包括...

    游戏脚本高级编程光盘文件1

    9. **AI和行为树**:智能体的行为通过AI算法实现,如有限状态机(FSM)、行为树等,让游戏角色具备自主决策能力。 10. **资源管理**:游戏资源如纹理、音频、模型等的加载和卸载,需要通过脚本来管理,以减少内存...

    打怪游戏的运行应用程序

    首先,打怪游戏的运行应用程序是游戏引擎和游戏逻辑的结合体,它负责处理游戏的所有计算、渲染和用户交互。游戏引擎是游戏开发的核心,如Unity、Unreal Engine或Cocos2d-x,它们提供了图形渲染、物理模拟、音频处理...

Global site tag (gtag.js) - Google Analytics