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



Finite state machines, or FSMs as they are usually referred to, have for many years been the AI coder’s instrument of choice to imbue a game agent with the illusion of elligence. You will find FSMs of _disibledevent=>就像经常听到有限状态机(简写为FSM)早就被AI员用来实现游戏智能体以体现智能感你会发现在FSM几乎是所有视频游戏基础构架不管正在出现和流行越来越深奥智能体架构FSM在长久未来仍然有武的地这里是些为什么FSM如此强劲原因:
  • They are quick and simple to code.There are many ways of programming a finite state machine and almost all of them are reasonably simple to implement. You’ll see several alternatives described in this article together with the pros and cons of using them.
  • 可以快速简单地编写代码实现有限状态机有多种途径而且都可以简单实现在本文你就能看到多种描述和赞成或者反对使用它们理由
  • They are easy to debug.Because a game agent’s behavior is broken down o easily manageable chunks, an agent starts acting strangely, it can be debugged by adding tracer code to each state. In this way, the AI programmer can easily follow the sequence of events that precedes the buggy behavior and take action accordingly.
  • 易于调试个游戏智能体行为由个易于管理代码段来实现如果个智能出现奇怪行为可以通过为每个状态增加Tracer来调试这样能够容易地跟踪事件序列就可以针对的前怪异行为修改代码了
  • They have little computational overhead.Finite state machines use hardly any precious processor time because they essentially follow hard- coded rules. There is no real “thinking” involved beyond the -this-then-that sort of thought process.
  • 需要付出点计算代价有限状态机几乎不使用宝贵处理器时间他们本质上跟硬编码是在那种“如果这样就那样”研究处理中根本不存在真正“研究”
  • They are uitive.It’s human nature to think about things as being in _disibledevent=>

  • 符合直觉类天生就以当前处以这种或者哪种状态来研究事情所以我们常常听到我们自己处于什么状态说法多少次你“让你自己进入状态”或者发现你自己处于“正确精神状态”?尽管人类并非真像有限状态机那样工作但通常我们发现这样有利于我们研究我们行为同样地这易于通过系列状态和创造操作规则来实现个游戏智能体行为基于同样原因有限状态机能让你和非员(如游戏策划和关卡设计师等)更好地进行有关你AI设计讨论改进交流和交换观点
  • They are flexible.A game agent’s finite state machine can easily be adjusted and tweaked by the programmer to provide the behavior required by the game designer. It’s also a simple matter to expand the scope of an agent’s behavior by adding states and rules. In addition, as your AI skills grow you’ll find that finite state machines provide a solid backbone with which you can combine other techniques such as fuzzy logic or neural networks.
  • 可伸缩性游戏智能体有限状态机易于调整能够很容易让员实现游戏设计师需要行为也易于通过增加新状态和规则来扩展智能体行为此外随着你AI技术增进你将发现有限状态机提供坚实基础让你能够把模糊逻辑和神经网络的类技术组合到游戏中

What Exactly Is a Finite State Machine?
有限状态机定义
Historically, a finite state machine is a rigidly formalized device used by mathematicians to solve problems. The most famous finite state machine is probably Alan Turing’s hypothetical device: the Turing machine, which he wrote about in his 1936 paper, “On Computable Numbers.” This was a machine presaging modern-day programmable computers that could perform any logical operation by reading, writing, and erasing symbols _disibledevent=>从历史观点上来说有限状态机是种严格公式化被数学家用以解决难题种策略最著名有限状态机可能是阿兰·图灵在1936年发表论文On Computable Numbers上写下猜想——图灵机这是现代计算机雏形能够通过在无限长磁带上进行读、写和擦除符号来实现所有逻辑操作幸运作为AI我们能够对公式化数学定义不加理会如下描述已经足够:
A finite state machine is a device, or a model of a device, which has a finite number of states it can be in at any given time and can operate _disibledevent=>有限状态机是种策略或者种策略模型它由有限系列状态构成在任给定时刻可以通过输入操作作出从种状态到另种状态转换或者产生输出或者发生动作有限状态机在任时刻都只能够处于种状态中
[Page]The idea behind a finite state machine, therefore, is to decompose an object’s behavior o easily manageable “chunks” or states. The light switch _disibledevent=>


因此有限状态机背后思想就是把个对象行为分解为易于管理“块”或者状态例如墙上电灯开关就是种非常简单有限状态机它有两个状态:开和关两个状态通过你指头产生输入来切换把开关扳上它就从关状态转换到开状态把开关扳下它就从开状态转换到关状态在关状态没有任何输出或者动作(除非你装灯泡被关掉视为种动作)但当在开状态下时电流通过开关并且通过灯泡里灯丝照亮房间如图2.1
\"\"
Figure 2.1. A light switch is a finite state machine. (Note that the switches are reversed in Europe and many other parts of the world.)
2.1 开关是种有限状态机(注意:这种开关在欧洲和其它很多国家仍有存在)
Of course, the behavior of a game agent is usually much more complex than a lightbulb (thank goodness!). Here are some examples of how finite state machines have been used in games.
当然游戏智能体行为往往比灯泡要复杂得多下文是些在游戏中使用有限状态机例子
本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday欢迎转载但必须保持全文完整也必须包含本声明
译者并示取得中文版翻译授权翻译本文只是出于研究和学习目任何人不得在未经同意情况下将英文版和中文版用于商业行为转载本文产生法律和道德责任由转载者承担和译者无关
· The ghosts’ behavior in Pac-Man is implemented as a finite state machine. There is _disibledevent=>· Pac-Mac精灵行为用有限状态机实现所有精灵都有Evade(逃避)状态它们实现都是;但每个精灵都Chase(追踪)状态实现各不相同
[Page]· Quake-style bots are implemented as finite state machines. They have states such as FindArmor, FindHealth, SeekCover, and RunAway. Even the weapons in Quake implement their own mini finite state machines. For example, a rocket may implement states such asMove, TouchObject, and Die.
· Quake系列机器人以有限状态机实现它们FindArmor

(找装备)、FindHealth(找补血)、SeekCover(找掩护)和RunAway(逃跑)等多种状态甚至Quake里实现武器都带有小型有限状态机例如个火箭炮实现状态就有Move(移动)、TouchObject(触到物体)和Die(死亡)等几种状态
· Players in sports simulations such as the soccer game FIFA2002 are implemented as state machines. They have states such as Strike, Dribble, ChaseBall, and MarkPlayer. In addition, the teams themselves are often implemented as FSMs and can have states such as KickOff, Defend, or WalkOutOnField.
· FIFA2002的类运动模拟游戏里运动员是用状态机实现它们有Strike(踢出)、Dribble(带球)、ChaseBall(逐球)和MarkPlayer(盯人)等状态此外整个球队通常也是用FSM实现KickOff(发球)、Defend(防守)和WalkOutOnField(不知道如何翻译请足球达人告知下)
· The NPCs (non-player characters) in RTSs (real-time strategy games) such as Warcraft make use of finite state machines. They have states such as MoveToPosition, Patrol, andFollowPath.
· RTS(实时策略游戏)(例如Warcraft)中NPC(非玩家角色)也利用有限状态机它们状态有MoveToPosition(移动到某地)、Patrol(巡逻)和FollowPath(跟随)等



Implementing a Finite State Machine
有限状态机实现
There are a number of ways of implementing finite state machines. A naive approach is to use a series of -then statements or the slightly tidier mechanism of a switch statement. Using a switch with an enumerated type to represent the states looks something like this:
实现有限状态机有许多方式个直观做法就是使用系列-then语句或者稍显整洁switch语句使用switch实现看起来就像这里代码:
enum StateType{state_RunAway, state_Patrol, state_Attack};
void Agent::UpdateState(StateType CurrentState)
{
switch(CurrentState)
{
state_RunAway:
EvadeEnemy;
(Safe)
{
ChangeState(state_Patrol);
}
;
state_Patrol:
FollowPatrolPath;
(Threatened)
{
(StrongerThanEnemy)
{
ChangeState(state_Attack);
}

{
ChangeState(state_RunAway);
}
}
;
state_Attack:
(WeakerThanEnemy)
{
ChangeState(state_RunAway);
}

{
BashEnemyOverHead;
}
;
}//end switch
}





[Page]Although at first glance this approach seems reasonable, when applied practically to anything more complicated than the simplest of game objects, the switch/-then solution becomes a monster lurking in the shadows waiting to pounce. As more states and conditions are added, this sort of structure ends up looking like spaghetti very quickly, making the program flow dficult to understand and creating a debugging nightmare. In addition, it’s inflexible and dficult to extend beyond the scope of its original design, should that be desirable… and as we all know, it most often is. Unless you are designing a state machine to implement very simple behavior (or you are a genius), you will almost certainly find yourself first tweaking the agent to cope with unplanned-for circumstances before honing the behavior to get the results you thought you were going to get when you first planned out the state machine!
尽管咋看这个方案还可以但只要将其应用到比最简单游戏对象稍为复杂实际情况下这个switch/-then方案就变成了蛰伏在阴影下怪物——随时都可能突袭你随着大量状态和条件增加那种结构很快就会变得像意大利面条使用难以理解并成为调试梦魇此外它不可伸缩并且难以在最初设计范围的外进行扩展然而我们都知道它极为常见除非你用状态机实现非常简单行为(或者你是个天才)否则当你第次策划状态机时候在你“磨合”取得结果和你希望取得结果的前你几乎肯定会发现你智能体无法应用未考虑到环境
Additionally, as an AI coder, you will often require that a state perform a specic action (or actions) when it’s initially entered or when the state is exited. For example, when an agent enters the state RunAway you may want it to wave its arms in the air and scream “Arghhhhhhh!” When it finally escapes and changes state to Patrol, you may want it to emit a sigh, wipe its forehead, and say “Phew!” These are actions that _disibledevent=>RunAway state is entered or exited and not during the usual update step. Consequently, this additional functionality must ideally be built o your state machine architecture. To do this within the framework of a switch or -then architecture would be accompanied by lots of teeth grinding and waves of nausea, and produce very ugly code indeed.
此外作为AI你经常需要在某状态实现种特殊行为(或者系列行为)比如在进入或者离开某状态时候例如当个智能体进行RunAway(逃跑)状态时你希望它把武器抛向空中并尖叫声“Arghhhhhh(啊)!”当它成功逃脱并转换到Patrol(巡逻)状态你可能想让它喘口气、擦擦额头然后说声“Phew(呸)!”这些行为都只在进入和离开RunAway(逃跑)状态时才会发生而不是整个普通update(更新)阶段都会出现因此这些额外功能必须被完美地集成到你状态机架构里switch或者-then架构里实现这些将让人难以忍受产生代码将非常丑陋不忍卒读
[Page]本文由恋花蝶最初发表于http://blog.csdn.net/lanphaday欢迎转载但必须保持全文完整也必须包含本声明
译者并示取得中文版翻译授权翻译本文只是出于研究和学习目任何人不得在未经同意情况下将英文版和中文版用于商业行为转载本文产生法律和道德责任由转载者承担和译者无关
State Transition Tables
状态转换表
A better mechanism for organizing states and affecting state transitions is a state transition table. This is just what it says it is: a table of conditions and the states those conditions lead to. Table 2.1 shows an example of the mapping for the states and conditions shown in the previous example.


个能够更好地组织和进行状态转换机制是状态转换表顾名思义这就是个包含条件和条件导致状态2.1是前文代码状态和条件影射表:
Table 2.1. A simple state transition table
2.1 简单状态转换表
Current State
Condition
State Transition

Runaway
Safe
Patrol

Attack
WeakerThanEnemy
RunAway

Patrol
Threatened AND StrongerThanEnemy
Attack



Patrol
Threatened AND WeakerThanEnemy
RunAway



This table can be queried by an agent at regular ervals, enabling it to make any necessary state transitions based _disibledevent=>智能体隔定时间查询这个表格以使得它能够基于从游戏环境接收到消息来进行必须状态转换个状态都能够实现为彼此分离和智能体不耦合对象或以提供清晰和可伸缩架构设计不再那么容易像前文讨论-then/switch架构那样容易成为意大利面条
Someone _disibledevent=>曾有人告诉我个明晰而无聊可视物能帮助人们理解抽象理论让我们来看看当它工作时……
Imagine a robot kitten. It’s shiny yet cute, has wire for whiskers and a slot in its stomach where cartridges — analogous to its states — can be plugged in. Each of these cartridges is programmed with logic, enabling the kitten to perform a specic of actions. Each of actions encodes a dferent behavior; for example, play_with_,eat_fish, or poo_on_carpet. Without a cartridge stuffed inside its belly the kitten is an inanimate metallic sculpture, _disibledevent=>想像存在个机器猫它闪闪发亮但是非常可爱有着金属丝制作胡须并且在胃部有个插槽——可以依照状态插入可插入模组个可插入模组都是段逻辑使得小猫能够实现系列指定动作系列动作都编码为区别行为play_with_eat_fishpoo_on_carpet如果没有在小猫胃部插上可插入模组它就是件死物——坐在那里看起来蛮可受
The kitten is very dexterous and has the ability to autonomously exchange its cartridge for another instructed to do so. By providing the rules that dictate when a cartridge should be switched, it’s possible to together sequences of cartridge insertions permitting the creation of all sorts of eresting and complicated behavior. These rules are programmed _disibledevent=>IF Kitty_Hungry AND NOT Kitty_Playful SWITCH_CARTRIDGE eat_fish


All the rules in the table are tested each time step and instructions are sent to Kitty to switch cartridges accordingly.
这个小猫非常灵巧并且能够根据指令自动地更换可插入模组通过给定什么时候该更换可插入模组规则它能利用连贯地插入系列可插入模组创造所有有趣而复杂行为这些和前文讨论状态转换表相类似规则被编成写入到个极小芯片放置在小猫头部芯片和小猫内部功能通信以获得处理规则时需要信息(如Kitty有多饿和它感觉到好玩度是多少)状态转换芯片可以用如下方式编写规则:
IF Kitty_Hungry AND NOT Kitty_Playful SWITCH_CARTRIDGE eat_fish
在每个时间片都检测表中所有规则从而给Kitty发送指令以切换弹可插入模组
This type of architecture is very flexible, making it easy to expand the kitten’s repertoire by adding cartridges. Each time a cartridge is added, the owner is _disibledevent=>这种架构有良好伸缩性通过增加新可插入模组就可以轻易扩展小猫指令表次增加新可插入模组只需要用起子打开小猫头壳重编程状态转换规则芯片即可不需要和其它内部电路打交道
Embedded Rules
规则内嵌
An alternative approach is to embed the rules for the state transitions within the states themselves. Applying this concept to Robo-Kitty, the state transition chip can be dispensed with and the rules moved directly o the cartridges. For instance, the cartridge for play_with_ can monitor the kitty’s level of hunger and instruct it to switch cartridges for the eat_fish cartridge when it senses hunger rising. In turn the eat_fish cartridge can monitor the kitten’s bowel and instruct it to switch to the poo_on_carpet cartridge when it senses poo levels are running dangerously high.
[Page]可选思路方法是把状态转换规则内嵌到状态本身当中在对机器猫应用这个概念后可以去除状态转换芯片直接将规则内置到可插入模组里例如play_with_可插入模组能够监视小猫饥饿度并适时地命令它切换到eat_fish可插入模组同样地eat_fish可插入模组能够监视小猫是否已经吃饱并在感觉到迫切排泄感时命令它切换到poo_on_carpet可插入模组
Although each cartridge may be aware of the existence of any of the other cartridges, each is a self-contained unit and not reliant _disibledevent=>尽管每个可插入模组需要知道其它模组存在但它们都是自包含无论是否要其它模组来替换自己都并不需要任何外部逻辑来帮助决策从而可以推论出其中简明关系甚至可以用全新模组集合替换已有集合(可能这会使用小猫行为像鸟类样)使用这个方案不再需要用起子打开小猫头部只要改变可插入模组即可


Let’s take a look at how this approach is implemented within the context of a video game. Just like Kitty’s cartridges, states are encapsulated as objects and contain the logic required to facilitate state transitions. In addition, all state objects share a common erface: a pure virtual named State. Here’s a version that provides a simple erface:
现在来看看在视频游戏中如何实现这方案像刚才讨论小猫可插入模组可以封装到个对象里其中包含辅助状态转换逻辑另外所有状态共享个通用接口:个命名为State纯虚类这里有个接口简单实现:
Class State
{
public:

virtual void Execute (Troll* troll) = 0;
};



Now imagine a Troll that has member variables for attributes such as health, anger, stamina, etc., and an erface allowing a client to query and adjust those values. A Troll can be given the functionality of a finite state machine by adding a poer to an instance of a derived object of the State, and a method permitting a client to change the instance the poer is poing to.
现在想象Troll类有系列数值成员变量:healthangerstamina当然也有相应接口以查询和设置这些变量值Troll通过增加个成员指针变量(指向State类派生类例子)来增加有限状态机功能还提供个改变指针指向例子思路方法
Troll
{
/* ATTRIBUTES OMITTED */

State* m_pCurrentState;

public:

/* INTERFACE TO ATTRIBUTES OMITTED */

void Update
{
m_pCurrentState->Execute(this);
}

void ChangeState(const State* pNewState)
{
delete m_pCurrentState;
m_pCurrentState = pNewState;
}
};





[Page]When the Update method of a Troll is called, it in turn calls the Executemethod of the current state type with the this poer. The current state may then use the Troll erface to query its owner, to adjust its owner’s attributes, or to effect a state transition. In other words, how a Troll behaves when updated can be made completely dependent _disibledevent=>TrollUpdate思路方法时它以this指针为参数当前状态类型Excecute思路方法当前状态可能使用Troll接口查询它拥有者设置拥有者属性或者产生个状态转换换句话说Troll能依赖当前状态逻辑作出完整行为这里有最好例子表达这观点让我们来完成两个状态实现以使得Troll能够在危险时逃跑或者在安全时睡觉
//----------------------------------State_Runaway
State_RunAway : public State
{
public:

void Execute(Troll* troll)
{
(troll->isSafe)
{
troll->ChangeState( State_Sleep);
}

{
troll->MoveAwayFromEnemy;
}
}
};

//----------------------------------State_Sleep
State_Sleep : public State
{
public:

void Execute(Troll* troll)
{
(troll->isThreatened)
{
troll->ChangeState( State_RunAway)
}


{
troll->Snore;
}
}
};





As you can see, when updated, a troll will behave dferently depending _disibledevent=>m_pCurrentState pos to. Both states are encapsulated as objects and both provide the rules effecting state transition. All very neat and tidy.
如你所见UpdateTroll行为依赖m_pCurrentState指向状态区别而有所区别两者状态都封装到对象里并且都提供了产生状态转换规则所有这切都灵巧而整洁
This architecture is known as the state design patternand provides an elegant way of implementing state-driven behavior. Although this is a departure from the mathematical formalization of an FSM, it is uitive, simple to code, and easily extensible. It also makes it extremely easy to add enter and exit actions to each state; all you have to do is create Enter and Exit methods and adjust the agent’s ChangeState method accordingly. You’ll see the code that does exactly this very ly.
[Page]架构即是有名状态设计模式它提供了雅致状态驱动行为实现尽管这有违FSM数学形式但它符合直觉、易于编码并且容易扩展它同样也能够极其容易地增加进入和离开状态时动作;你需要做只是实现 EnterExit思路方法并相应地改变ChangeState思路方法你将可以看到完成这些所产生代码真非常短小
Tags:  智能驱动

延伸阅读

最新评论

发表评论