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

来源:互联网 发布:js接口安全域名 编辑:程序博客网 时间:2024/04/29 10:53

 

本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday,欢迎转载,但必须保持全文完整,也必须包含本声明。
译者并示取得中文版的翻译授权,翻译本文只是出于研究和学习目的。任何人不得在未经同意的情况下将英文版和中文版用于商业行为,转载本文产生的法律和道德责任由转载者承担,与译者无关。
State-Driven Game Agent Design
 
 
状态驱动的游戏智能体设计(中)
Mat Buckland
赖勇浩(http://blog.csdn.net/lanphaday)
原文地址:http://www.ai-junkie.com/architecture/state_driven/tut_state2.html
(续上篇)
状态驱动的游戏智能体设计(上)http://blog.csdn.net/lanphaday/archive/2007/06/24/1664369.aspx
 ―――――――――――――――――――――――――――――――――――――
The West World Project
WestWorld项目
As a practical example of how to create agents that utilize finite state machines, we are going to look at a game environment where agents inhabit an Old West-style gold mining town named West World. Initially there will only be one inhabitant — a gold miner named Miner Bob — but later his wife will also make an appearance. You will have to imagine the tumbleweeds, creakin’ mine props, and desert dust blowin’ in your eyes because West World is implemented as a simple text-based console application. Any state changes or output from state actions will be sent as text to the console window. I’m using this plaintext-only approach as it demonstrates clearly the mechanism of a finite state machine without adding the code clutter of a more complex environment.
作为一个如何利用有限状态机的创造智能体的实例,我们创建名为WestWorld的旧西部风格的淘金镇的游戏,并研究其中的智能体实现。一开始只存在一个名为Miner Bob的淘金者,随后他的妻子也出现。你可以想像风滚草、叽叽作响的淘金用具和沙漠的风把沙吹进你的眼睛,因为WestWorld只是一个简单的基于文本的控制台程序。所有的状态改变和状态动作产生的输出都作为文本传送到控制台窗口。我使用纯文本的原因是为了清晰地示范有限状态机的机制,不想增加代码以免搞得太过于复杂。
There are four locations in West World: a goldmine, a bankwhere Bob can deposit any nuggets he finds, a saloonin which he can quench his thirst, and home-sweet-homewhere he can sleep the fatigue of the day away. Exactly where he goes, and what he does when he gets there, is determined by Bob’s current state. He will change states depending on variables like thirst, fatigue, and how much gold he has found hacking away down in the gold mine.
WestWorld有四个场景:一个金矿、一个储藏库(Bob把找到的金块存放在这里)、一个酒吧(喝水吃饭)和一个家(睡觉)。确切来讲就是他去哪里、做什么和什么去,都由Bob当前的状态决定。他根据饥渴度、疲惫度和从金旷获得的金块数量来改变状态。
Before we delve into the source code, check out the following sample output from the WestWorld1 executable.
在我们研究代码之前,我们先来看看WestWorld1可执行文件产生的输出:
Miner  Bob:  Pickin'  up  a  nugget
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
Miner  Bob:  Depositin’  gold.  Total  savings  now:  3
Miner  Bob:  Leavin'  the  bank
Miner  Bob:  Walkin'  to  the  gold  mine
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
Miner  Bob:  That's  mighty  fine  sippin  liquor
Miner  Bob:  Leavin'  the  saloon,  feelin'  good
Miner  Bob:  Walkin'  to  the  gold  mine
Miner  Bob:  Pickin'  up  a  nugget
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
Miner  Bob:  Depositin'  gold.  Total  savings  now:  4
Miner  Bob:  Leavin'  the  bank
Miner  Bob:  Walkin'  to  the  gold  mine
Miner  Bob:  Pickin'  up  a  nugget
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
Miner  Bob:  That's  mighty  fine  sippin'  liquor
Miner  Bob:  Leavin'  the  saloon,  feelin'  good
Miner  Bob:  Walkin'  to  the  gold  mine
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
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
Miner  Bob:  ZZZZ...
Miner  Bob:  ZZZZ...
Miner  Bob:  ZZZZ...
Miner  Bob:  ZZZZ...
Miner  Bob:  What  a  God-darn  fantastic  nap!  Time  to  find  more  gold
In the output from the program, each time you see Miner Bob change location he is changing state. All the other events are the actions that take place within the states. We’ll examine each of Miner Bob’s potential states in just a moment, but for now, let me explain a little about the code structure of the demo.
 (You can download the accompanying project files here (24k))
从程序的输出来看,Miner Bob每一次改变他所处的场景时,他都会改变状态。所有的其它事件都发生在状态里的动作。我们将会检测Miner Bob在每一时刻的每一个潜在状态,但现在让我来对demo的代码结构稍作解释。
(你可以从 这里 下载项目代码(24k))
The BaseGameEntity Class
BaseGameEntity
All inhabitants of West World are derived from the base class BaseGameEntity. This is a simple class with a private member for storing an ID number. It also specifies a pure virtual member function, Update, which must be implemented by all subclasses. Update is a function that gets called every update step and will be used by subclasses to update their state machine along with any other data that must be updated each time step.
WeskWorld游戏里的所有物体都从BaseGameEntity类派生。这是只有一个私有成员(用以保存ID)的简单类,此外就只有一个纯虚函数Update了,它必须在子类中实现。Update函数将在更新步骤里调用,用以给子类在每一个时间片依据其它数据更新他们的状态机里必须被更新的其它数据。
The BaseGameEntity class declaration looks like this:
BaseGameEntity的声明如下:
class BaseGameEntity
{
private:
 
  //every entity has a unique identifying number
  int          m_ID;
 
  //this is the next valid ID. Each time a BaseGameEntity is instantiated
  //this value is updated
  static int  m_iNextValidID;
 
  //this is called within the constructor to make sure the ID is set
  //correctly. It verifies that the value passed to the method is greater
  //or equal to the next valid ID, before setting the ID and incrementing
  //the next valid ID
  void SetID(int val);
 
public:
 
  BaseGameEntity(int id)
  {
    SetID(id);
  }
 
  virtual ~BaseGameEntity(){}
 
  //all entities must implement an update function
  virtual void  Update()=0;
 
  int           ID()const{return m_ID;} 
};
For reasons that will become obvious later [in the book], it’s very important for each entity in your game to have a unique identifier. Therefore, on instantiation, the ID passed to the constructor is tested in the SetID method to make sure it’s unique. If it is not, the program will exit with an assertion failure. In the example given, the entities will use an enumerated value as their unique identifier. These can be found in the file EntityNames.h as ent_Miner_Bob and ent_Elsa.
为游戏里的每一个实体设置一个唯一的ID是非常重要的,在本书后面的章节将为你讲述为什么非常重要。因此,在实例化的时候把ID通过构造函数传递,并通过SetID函数来测试它是否唯一,如果不唯一,程序将会退出,产生一个断言失败错误。在本文的例子中,将把一个枚举值作为唯一的ID,在EntityNames.h文件里可以找到ent_Miner_Bobent_Elsa等枚举值。
The Miner Class
Miner
The Miner class is derived from the BaseGameEntity class and contains data members representing the various attributes a Miner possesses, such as its health, its level of fatigue, its position, and so forth. Like the troll example shown earlier, a Miner owns a pointer to an instance of a State class in addition to a method for changing what State that pointer points to.
Miner类从BaseGameEntity类派生,它包括健康、疲惫程度和位置等数据成员。像前文描述过的Troll例子,Miner也有一个指向State类实例的指针,当然也少不了用以改变State指针所指向的实例的方法。
Class Miner : public BaseGameEntity
{
private:
 
  //a pointer to an instance of a State
  State*                m_pCurrentState;
 
  // the place where the miner is currently situated
  location_type         m_Location;
 
  //how many nuggets the miner has in his pockets
  int                   m_iGoldCarried;
 
  //how much money the miner has deposited in the bank
  int                   m_iMoneyInBank;
 
  //the higher the value, the thirstier the miner
  int                   m_iThirst;
 
  //the higher the value, the more tired the miner
  int                   m_iFatigue;
 
public:
 
  Miner(int ID);
 
  //this must be implemented
  void Update();
 
  //this method changes the current state to the new state
  void ChangeState(State* pNewState);
 
  /* bulk of interface omitted */
};
 The Miner::Update method is straightforward; it simply increments the m_iThirst value before calling the Execute method of the current state. It looks like this:
Miner::Update方法直接明了:它在调用当前状态的Execute方法之前简单地增加m_iThirst。它的实现如下:
本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday,欢迎转载,但必须保持全文完整,也必须包含本声明。
译者并示取得中文版的翻译授权,翻译本文只是出于研究和学习目的。任何人不得在未经同意的情况下将英文版和中文版用于商业行为,转载本文产生的法律和道德责任由转载者承担,与译者无关。
void Miner::Update()
{
  m_iThirst += 1;
 
  if (m_pCurrentState)
  {
    m_pCurrentState->Execute(this);
  }
}
Now that you’ve seen how the Miner class operates, let’s take a look at each of the states a miner can find itself in.
现在你知道Miner类的操作了,让我们来看看它的每一个状态是怎么样的。
The Miner States
Miner的状态
The gold miner will be able to enter one of four states. Here are the names of those states followed by a description of the actions and state transitions that occur within those states:
淘金者Bob能够进入这四个状态之一。下文是这些状态的名字(结合了动作的描述),状态转换发生在状态内部。
  • EnterMineAndDigForNugget: If the miner is not located at the gold mine, he changes location. If already at the gold mine, he digs for nuggets of gold. When his pockets are full, Bob changes state to VisitBankAndDepositGold, and if while digging he finds himself thirsty, he will stop and change state to QuenchThirst.
  • EnterMinAndDigForNuggetBob不在金矿的时候,他移动到金矿。如果已经在金矿,他会持续掘金。直到他的袋子装满金矿石,Bob将会转换到VisitBankAndDepositGold状态。但如果在掘金的时候觉得饥渴,他就会停下来,把状态转换到QuenchThirst
  • VisitBankAndDepositGold: In this state the miner will walk to the bank and deposit any nuggets he is carrying. If he then considers himself wealthy enough, he will change state to GoHomeAnd- SleepTilRested. Otherwise he will change state to EnterMine- AndDigForNugget.
  • VisitBankAndDepositGold处于这个状态时淘金者会走到储藏库并把带来的金矿石保存起来。如果他觉得自己足够富有,他就转换到GoHomeAndSleepTilRested状态,否则就转换到EnterMineAndDigForNugget
  • GoHomeAndSleepTilRested: In this state the miner will return to his shack and sleep until his fatigue level drops below an acceptable level. He will then change state to EnterMineAndDigForNugget.
  • GoHomeAndSleepTilRested:处于此状态的淘金者会返回到他的房子里睡觉,直到疲惫程序下降到可接受的情况,这时转换到EnterMineAndDigForNugget
  • QuenchThirst: If at any time the miner feels thirsty (diggin’ for gold is thusty work, don’t ya know), he changes to this state and visits the saloon in order to buy a whiskey. When his thirst is quenched, he changes state to EnterMineAndDigForNugget.
  • QuenchThirst任何时候当淘金者感到饥渴,他就改变他的状态去商店买威士忌,解渴后转换到EnterMineAndDigForNugget
Sometimes it’s hard to follow the flow of the state logic from reading a text description like this, so it’s often helpful to pick up pen and paper and draw a state transition diagramfor your game agents. Figure 2.2 shows the state transition diagram for the gold miner. The bubbles represent the individual states and the lines between them the available transitions.
通过阅读来理解状态逻辑流是相当困难的,所以最后为你的游戏智能体画一张状态转换图。图2.2是淘金者的状态转换图,圆角矩形是独立的状态,它们之间的连线是允许的转换。
A diagram like this is better on the eyes and can make it much easier to spot any errors in the logic flow. 
一个这样的图示有助于我们理解,也更容易找出逻辑流中的错误。
 
Figure 2.2. Miner Bob’s state transition diagram
2.2         淘金者Bob的状态转换图
 The State Design Pattern Revisited
重温状态设计模式
You saw a brief description of this design pattern earlier, but it won’t hurt to recap. Each of a game agent’s states is implemented as a unique class and each agent holds a pointer to an instance of its current state. An agent also implements a ChangeState member function that can be called to facilitate the switching of states whenever a state transition is required. The logic for determining any state transitions is contained within each State class. All state classes are derived from an abstract base class, thereby defining a common interface. So far so good. You know this much already.
之前已经对这个模式作了简单介绍,但不够深入。每一个游戏智能体的状态机都作为唯一的类来实现,智能体拥有一个指向当前状态实例的指针。智能体需要实现ChangeState成员函数以实现状态切换。决定状态转换的逻辑包含在每一个State派生类的内部。所有的状态类都从一个抽象类派生,以获得统一接口。现在,你已经知道足够多关于状态设计模式的知识了。
Earlier it was mentioned that it’s usually favorable for each state to have associated Enterand Exitactions. This permits the programmer to write logic that is only executed once at state entry or exit and increases the flexibility of an FSM a great deal. With these features in mind, let’s take a look at an enhanced State base class.
之前也提及过通常每一个状态都有相应的EnterExit动作,这将使得程序员能够编写仅在进入或者离开状态只执行一次的逻辑以增强FSM的可伸缩性。为了实现这一点,让我们来看看改进后的State基类。
class State
{
public:
 
  virtual ~State(){}
 
  //this will execute when the state is entered
  virtual void Enter(Miner*)=0;
 
  //this is called by the miner’s update function each update-step
  virtual void Execute(Miner*)=0;
 
  //this will execute when the state is exited
  virtual void Exit(Miner*)=0;
}
 These additional methods are only called when a Minerchanges state. When a state transition occurs, the Miner::ChangeStatemethod first callsthe Exitmethod of the current state, then it assigns the new state to the current state, and finishes by calling the Entermethod of the new state (which is now the current state). I think code is clearer than words in this instance, so here’s the listing for the ChangeStatemethod:
这两个方法仅在Miner改变状态的时候调用,当发生一个状态转换,Miner::ChangeState方法首先调用当前状态的Exit方法,然后它为当前状态指派一个新的状态,最后调用新状态的Enter方法。我认为代码比言语更清晰,所有这里列出ChangeState方法的代码:
void Miner::ChangeState(State* pNewState)
{
  //make sure both states are valid before attempting to
  //call their methods
  assert (m_pCurrentState && pNewState);
 
  //call the exit method of the existing state
  m_pCurrentState->Exit(this);
 
  //change state to the new state
  m_pCurrentState = pNewState;
 
  //call the entry method of the new state
  m_pCurrentState->Enter(this);
}
 Notice how a Minerpasses the thispointer to each state, enabling the state to use the Minerinterface to access any relevant data.
注意Minerthis指针传递到每一个状态,使得状态能够使用Miner的接口获取相关数据。
TIP: The state design pattern is also useful for structuring the main components of your game flow. For example, you could have a menu state, a save state, a paused state, an options state, a run state, etc.
提示:状态设计模式对于游戏主流程的组织也是非常有用的,例如,你可能有菜单状态、保存状态、暂停状态、设置状态和运行状态等。
Each of the four possible states a Minermay access are derived from the Stateclass, giving us these concrete classes: EnterMineAndDigForNugget, VisitBankAndDepositGold, GoHomeAndSleepTilRested, and QuenchThirst. The Miner::m_pCurrentStatepointer is able to point to any of these states. When the Updatemethod of Mineris called, it in turn calls the Executemethod of the currently active state with the thispointer as a parameter. These class relationships may be easier to understand if you examine the simplified UML class diagram shown in Figure 2.3. (Click here for an introduction to UML class diagrams)
Miner可能处于四个状态之一,它们都从State类派生而来,具体是:EnterMineAndDigForNuggetVisitBankAndDepositGoldGoHomeAndSleepTilRestedQuenchThirstMiner::m_pCurrrentState可能指向其中的任何一个。当MinerUpdate方法被调用,它就以this指针为参数调用当前活动状态的Execute方法。如果你能看图2.3UML图,应该很容易理解这些类之间的关系。(这里有对UML图的介绍)
本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday,欢迎转载,但必须保持全文完整,也必须包含本声明。
译者并示取得中文版的翻译授权,翻译本文只是出于研究和学习目的。任何人不得在未经同意的情况下将英文版和中文版用于商业行为,转载本文产生的法律和道德责任由转载者承担,与译者无关。
Each concrete state is implemented as a singleton object. This is to ensure that there is only one instance of each state, which agents share (those of you unsure of what a singleton is, please read this). Using singletons makes the design more efficient because they remove the need to allocate and deallocate memory every time a state change is made. This is particularly important if you have many agents sharing a complex FSM and/or you are developing for a machine with limited resources.
每一个状态都以单件对象的形式实现,这是为了确保只有一个状态的实例,所有的智能体共享这一实例(想了解什么是单件,可以阅读这个文档)。使用单件使得这一设计更加高效,因为避免了在每一次状态转换的时候申请和释放内存。这在你有很多智能体共享复杂的FSM的时候变得极其重要,特别是你在资源受限的机器上进行开发的话。
 
Figure 2.3. UML class diagram for Miner Bob’s state machine implementation
2.3         Miner Bob的状态机实现的UML类图
 
NOTE     I prefer to use singletons for the states for the reasons I’ve already given, but there is one drawback. Because they are shared between clients, singleton states are unable to make use of their own local, agent-specific data. For instance, if an agent uses a state that when entered should move it to an arbitrary position, the position cannot be stored in the state itself (because the position may be different for each agent that is using the state). Instead, it would have to be stored somewhere externally and be accessed by the state via the agent’s interface. This is not really a problem if your states are accessing only one or two pieces of data, but if you find that the states you have designed are repeatedly accessing lots of external data, it’s probably worth considering disposing of the singleton design and writing a few lines of code to manage the allocation and deallocation of state memory.
注意:我乐于使用单件的原因在上文已经给出,但这也有一个缺陷。因为他们由客户共享,单件状态不能使用他们自有的,特定智能体的数据。例如,当某一处于某状态的智能体移动到某一位置时,他不能把这一位置存储在状态内(因为这个状态可能与其它正处于这一状态的智能体不同)。它只能把它存储在其它地方,然后由状态机通过智能体的接口来存取。如果你的状态只有一两个数据要存取,那这也不是什么大问题,但如果你在很多外部数据,那可能就值得考虑放弃单件设计,而转而写一代码来管理状态内存的申请与释放了。
 
Okay, let’s see how everything fits together by examining the complete code for one of the miner states.
好了,现在让我们来看看如何把所有的东西都融合在一起完成一个淘金者的状态。
The EnterMineAndDigForNuggetState
EnterMineAndDigForNugget状态
In this state the miner should change location to be at the gold mine. Once at the gold mine he should dig for gold until his pockets are full, when he should change state to VisitBankAndDepositNugget.If the miner gets thirsty while digging he should change state to QuenchThirst.
淘金者在这个状态会改变所在地,去到金矿场,到矿场后就开始掘金,直到装满口袋,这时改变状态到VisitBankanDepositNugget。如果掘金中途感到口渴,淘金者就转换到QuenchThirst状态。
 
Because concrete states simply implement the interface defined in the virtual base class State, their declarations are very straightforward:
因为具类只是简单地实现虚基类State定义的接口,它们的声明非常简明:
class EnterMineAndDigForNugget : public State
{
private:
 
  EnterMineAndDigForNugget(){}
 
  /* copy ctor and assignment op omitted */
 
public:
 
  //this is a singleton
  static EnterMineAndDigForNugget* Instance();
 
  virtual void Enter(Miner* pMiner);
 
  virtual void Execute(Miner* pMiner);
 
  virtual void Exit(Miner* pMiner);
};
 As you can see, it’s just a formality. Let’s take a look at each of the methods in turn.
如你所见,这只是一个模式,让我们来看看其它方法。
EnterMineAndDigForNugget::Enter
EnterMineAndDigForNugget::Enter
The code for the Entermethod of EnterMineAndDigForNuggetis as follows:
下面是EnterMineAndDigForNuggetEnter方法:
void EnterMineAndDigForNugget::Enter(Miner* pMiner)
{
  //if the miner is not already located at the goldmine, he must
  //change location to the gold mine
  if (pMiner->Location() != goldmine)
  {
    cout << "/n" << GetNameOfEntity(pMiner->ID()) << ": "
         << "Walkin' to the goldmine";
 
    pMiner->ChangeLocation(goldmine);
  }
}
This method is called when a miner first enters the EnterMineAndDigForNuggetstate. It ensures that the gold miner is located at the gold mine.An agent stores its location as an enumerated type and the ChangeLocationmethod changes this value to switch locations.
当淘金者第一次进入EnterMineAndDigForNugget状态时调用这个方法,这确保淘金者位于金矿场。智能体以枚举量的形式保存当前位置,ChangeLocation方法用以改变位置值。
EnterMineAndDigForNugget::Execute
EnterMineAndDigForNugget::Execute
The Executemethod is a little more complicated and contains logic that can change a miner’s state. (Don’t forget that Executeis the method called each update step from Miner::Update.)
Execute有点复杂,它包含了改变淘金者状态的逻辑。(不要忘记Miner::Update在每一个更新帧都会调用Execute方法。)
void EnterMineAndDigForNugget::Execute(Miner* pMiner)
  //the miner digs for gold until he is carrying in excess of MaxNuggets.
  //If he gets thirsty during his digging he stops work and
  //changes state to go to the saloon for a beer.
  pMiner->AddToGoldCarried(1);
 
  //digging is hard work
  pMiner->IncreaseFatigue();
 
  cout << "/n" << GetNameOfEntity(pMiner->ID()) << ": "
       << "Pickin' up a nugget";
 
  //if enough gold mined, go and put it in the bank
  if (pMiner->PocketsFull())
  {
    pMiner->ChangeState(VisitBankAndDepositGold::Instance());
  }
 
  //if thirsty go and get a beer
  if (pMiner->Thirsty())
  {
    pMiner->ChangeState(QuenchThirst::Instance());
  }
}
 Note here how the Miner::ChangeStatemethod is called using QuenchThirst’s or VisitBankAndDepositGold’s Instancemember, which provides a pointer to the unique instance of that class.
值得注意的是Miner::ChangeState方法调用了QuenchThirstVisitBankAndDepositGoldInstance成员函数,以获得指向该类唯一实例的指针。
 EnterMineAndDigForNugget::Exit
 EnterMineAndDigForNugget::Exit
The Exitmethod of EnterMineAndDigForNuggetoutputs a message telling us that the gold miner is leaving the mine.
EnterMineAndDigForNuggetExit方法只是简单地输出一条消息告诉我们淘金者离开了金矿。
void EnterMineAndDigForNugget::Exit(Miner* pMiner)
{
  cout << "/n" << GetNameOfEntity(pMiner->ID()) << ": "
       << "Ah'm leavin' the goldmine with mah pockets full o' sweet gold";
}
I hope an examination of the preceding three methods helps clear up any confusion you may have been experiencing and that you can now see how each state is able to modify the behavior of an agent or effect a transition into another state. You may find it useful at this stage to load up the WestWorld1 project into your IDE and scan the code. In particular, check out all the states in MinerOwnedStates.cpp and examine the Minerclass to familiarize yourself with its member variables. Above all else, make sure you understand how the state design pattern works before you read any further. If you are a little unsure, please take the time to go over the previous text until you feel comfortable with the concept.
我希望前述的三个方法能帮助你理清头绪,现在你应该已经理解了每一个状态怎么改变智能体的行为,又如何从一个状态到另一个状态转换。你用IDE打开WestWorld1项目并浏览一遍代码应该有助于理解,可以抽取出MinerOwnedStates.cpp里的所有状态并检阅Miner类实现,让你熟悉它的成员变量。最重要的是,确定你理解了状态设计模式是如何工作的,然后再作进一步阅读。如果你有一些不了解,请重温上文直到你觉得已经完全理解了相关理论。
You have seen how the use of the state design pattern provides a very flexible mechanism for state-driven agents. It’s extremely easy to add additional states as and when required. Indeed, should you so wish, you can switch an agent’s entire state architecture for an alternative one. This can be useful if you have a very complicated design that would be better organized as a collection of several separate smaller state machines. For example, the state machine for a first-person shooter (FPS) like Unreal 2 tends to be large and complex. When designing the AI for a game of this sort you may find it preferable to think in terms of several smaller state machines representing functionality like “defend the flag” or “explore map,” which can be switched in and out when appropriate. The state design pattern makes this easy to do.
正如你所见,状态设计模式为状态驱动的智能体提供了具有非常好的伸缩性的机制,当需要的时候,你可以极其容易地增加新的状态。在你有非常复杂的设计,而且能更好地组织一系列的分散的小状态机的时候,甚至可以替换智能体的整个状态架构。例如,像Unreal2这样的第一人称射击游戏(FPS)有着巨大而复杂的状态机,当设计这种游戏的AI的时候,你将发现它能完美地应用于基于团队而设计的多个小状态机(对应的功能可能是“保旗”或者“探险”),使得能够在需要的时候进行切换。正在状态设计模式使它易于实现。
-----------------
未完待续,敬请期待...



原创粉丝点击