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

25 篇文章 2 订阅
23 篇文章 0 订阅

 

本文由恋花蝶最初发表于 http://blog.csdn.net/lanphaday,欢迎转载,但必须保持全文完整,也必须包含本声明。
译者并示取得中文版的翻译授权,翻译本文只是出于研究和学习目的。任何人不得在未经同意的情况下将英文版和中文版用于商业行为,转载本文产生的法律和道德责任由转载者承担,与译者无关。
State-Driven Game Agent Design
 
 
状态驱动的游戏智能体设计(中)
Mat Buckland
(续上篇)
  ―――――――――――――――――――――――――――――――――――――
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 bank where Bob can deposit any nuggets he finds, a saloon in which he can quench his thirst, and home-sweet-home where 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_Bob ent_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 diagram for 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 Enter and Exit actions. 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.
之前也提及过通常每一个状态都有相应的 Enter Exit 动作,这将使得程序员能够编写仅在进入或者离开状态只执行一次的逻辑以增强 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 Miner changes state. When a state transition occurs, the Miner::ChangeState method first calls the Exit method of the current state, then it assigns the new state to the current state, and finishes by calling the Enter method 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 ChangeState method:
这两个方法仅在 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 Miner passes the this pointer to each state, enabling the state to use the Miner interface to access any relevant data.
注意 Miner this 指针传递到每一个状态,使得状态能够使用 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 Miner may access are derived from the State class, giving us these concrete classes: EnterMineAndDigForNugget , VisitBankAndDepositGold , GoHomeAndSleepTilRested , and QuenchThirst . The Miner::m_pCurrentState pointer is able to point to any of these states. When the Update method of Miner is called, it in turn calls the Execute method of the currently active state with the this pointer 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 类派生而来,具体是: EnterMineAndDigForNugget VisitBankAndDepositGold GoHomeAndSleepTilRested QuenchThirst Miner::m_pCurrrentState 可能指向其中的任何一个。当 Miner Update 方法被调用,它就以 this 指针为参数调用当前活动状态的 Execute 方法。如果你能看图 2.3 UML 图,应该很容易理解这些类之间的关系。( 这里 有对 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 Enter method of EnterMineAndDigForNugget is as follows:
下面是 EnterMineAndDigForNugget Enter 方法:
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 EnterMineAndDigForNugget state. It ensures that the gold miner is located at the gold mine. An agent stores its location as an enumerated type and the ChangeLocation method changes this value to switch locations.
当淘金者第一次进入 EnterMineAndDigForNugget 状态时调用这个方法,这确保淘金者位于金矿场。智能体以枚举量的形式保存当前位置, ChangeLocation 方法用以改变位置值。
EnterMineAndDigForNugget::Execute
EnterMineAndDigForNugget::Execute
The Execute method is a little more complicated and contains logic that can change a miner’s state. (Don’t forget that Execute is 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::ChangeState method is called using QuenchThirst ’s or VisitBankAndDepositGold ’s Instance member, which provides a pointer to the unique instance of that class.
值得注意的是 Miner::ChangeState 方法调用了 QuenchThirst VisitBankAndDepositGold Instance 成员函数,以获得指向该类唯一实例的指针。
  EnterMineAndDigForNugget::Exit
 EnterMineAndDigForNugget::Exit
The Exit method of EnterMineAndDigForNugget outputs a message telling us that the gold miner is leaving the mine.
EnterMineAndDigForNugget Exit 方法只是简单地输出一条消息告诉我们淘金者离开了金矿。
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 Miner class 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 的时候,你将发现它能完美地应用于基于团队而设计的多个小状态机(对应的功能可能是“保旗”或者“探险”),使得能够在需要的时候进行切换。正在状态设计模式使它易于实现。
-----------------
未完待续,敬请期待...
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值