根据网站statista.com的数据,2017年全球视频游戏市场价值1045.7亿美元,到2020年将达到1312.3亿美元。不用说,视频游戏是一项庞大的业务。

《吃豆人》是有史以来最著名,最成功的视频游戏之一。 它于1980年投放市场,到1990年代末已赚了25亿美元。 成功的关键是追赶吃豆人的鬼魂的疯狂行为。 对于不熟练的人来说,逃脱幽灵是一项艰巨,令人上瘾的工作,并且(在街机时代)是一项昂贵的工作。
出乎意料的是,对于这种成功的游戏而言,使用有限状态机(FSM)可以轻松理解这种鬼行为。 让我们看一下幽灵如何思考吃豆人迷宫中的生活:
尽管互联网上有很多关于鬼AI的FSM图,但是我发现Jared Mitchell的UML图很好地说明了转换的决策标准。
AI程式范例
主页|| 关于/联系|| 简历|| 文章|| 自从我开始学习如何编程和实现……
jaredemitchell.com
从图中可以看出,有5种主要工作状态:
- WanderAroundBase
- 迷宫漫步
- SeekTowardsPlayer
- FleeFromPlayer
- ReturnToBase
接下来,我们将探索如何使用帧机符号(FMN)来建模和实现此AI。
框架机器表示法(FMN)是UML状态图的演变,我一直在开发该图,以提供一种更精确和更具表现力的语言,用于使用面向对象的语言开发自动机。 请点击链接以获取更多详细信息,并请参阅我在Medium上发表的其他文章。
在本文中,我将讨论FMN条件表示法,然后说明如何将其应用于Ghost AI。
FMN语法的主要目标是为事件建立“事件映射”,以将事件路由到要触发的行为。 FMN为if-then-else条件测试引入了一种简约的新语法:

这些令牌的使用如下所示:

条件表示法受到C和其他语言中的三元运算符的启发,但已扩展为可处理无限数量的操作数。
现在让我们逐个状态地探究虚假状态机,并查看FMN表示法如何与UML图对齐。
上面的UML图中未捕获的真实游戏编程的一个方面是游戏引擎更新循环的功能。 通常,诸如Unity之类的平台会在渲染周期的每一帧中调用重要的游戏对象,以根据环境更新其状态。 UML中未显示此方面,但将在FMN规范中针对虚影进行捕获。
首先,该界面支持启动,停止和更新事件:

接口的开始和停止方法分别发送“ >> ”和“ << ”消息,这称为消息别名。 但是,该更新调用将以不混叠的形式直接发送到计算机中。 开始和停止别名是可选的,只是Frame标准命名法的一部分,但不是必需的。
UML图显示了从初始游戏开始状态到基本漫游状态的简单过渡。

除非引擎执行此操作,否则实际的实现将需要初始化虚影以及启动更新计时器。 但是,我们将假定在此实现中需要管理自己的计时器,并将使用此要求来说明如何使用帧启动和停止挂钩来正确管理资源。
这是我们的国家版本的FMN:

请注意,如果$ GameStart状态没有处理事件,则将事件传递给$ Default状态。 这是实现:

现在,我们可以看到状态的三个(大部分)等效表示形式:
- 图形模型
- 文字说明
- 代码实施
对于本文,我们将对图形模型使用UML表示法。 但是,创建Frame的许多动机是由于UML可视化建模符号缺乏精确性,我们将看到一个重要的例子。 在以后的文章中,我们将探究Frame的视觉表示法,它是精确的,并使用FMN作为定义状态内部行为的手段。
进入第一个实际的工作状态!

在上方,我们看到了“基本漫游”状态的部分逻辑。 如果计时器大于某个恒定的“ Spawn Time”,则由保护条件触发过渡。
下面我们显示| update |的FMN规范。 触发等效防护测试的事件isPastSpawnTime() 。

下面我们可以看到上面指定的所有转换:

该实现揭示了如何将FMN规范转换为代码:

如果能量球未激活且玩家未关闭,则幻影将过渡到$ WanderAroundMaze状态,在其中它会漂移以寻找吃豆人。 离开此状态有两种过渡-一种是追逐玩家,另一种是逃跑。

这些状态转换是UML状态图固有的歧义的一个很好的例子。 请注意,“迷宫漫游”中两个过渡的表示没有定义优先级。 如果两个条件同时成立, 我们将不知道将进行哪个过渡以及幻影应该进入哪个状态。
但是,在下面的FMN实现中,每个| update |都会先检查功率小球是否处于活动状态,然后再检查玩家是否处于活动状态。 因此,优先级是使用FMN定义的并且是明确的。

逃离玩家状态是鬼可以被吞噬的唯一状态,这开始了它回到基地和新化身的旅程。 如果未食用,则关闭电源球会触发状态变化,以追逐玩家或迷宫游戏。


这是我们看到嵌套的if-then-else语法的第一种状态。 相当简洁的?-:-::
语句是新颖的。 语法的关键是要识别每个?
(如果)还是?!
(如果不是)则以匹配的::
:(如果结束)终止。 寻找那些匹配项可以使控制流程清晰明了。
在$ SeekTowardsPlayer状态下,幽灵使吃豆人生活变得艰难。

该州还具有两个过渡,其优先级与$ WanderAroundMaze州相同。 FMN再次向营救者澄清。
如果玩家不靠近,则幽灵会回到游荡状态;而如果威力球处于活动状态,我们的幽灵就会逃跑。

最后一个要检查的UML状态是“返回基础”。 在该图中,我们在过渡上的绿色矩形中看到了一个过程动作,该动作既重置了Eaten标志又重置了计时器。

到现在为止,我一直都非常遵守UML模型。 但是,在这种状态下,我正在探索一种关于幽灵返回基地时应该做什么的稍微不同的方法:

首先,我们看到一个|>|
事件处理程序,其中给予了幽灵指令以使其回到基部:
|> | headToBase()^
从那里开始,每一次|update|
进行测试以确定“我们到那儿了”的事件吗? 如果是这样,我们将执行处理块逻辑,即重置计时器和进食标志,然后再次转换为$ WanderAroundBase。
这样就完成了对UML图中状态的探索。 现在,让我们快速看一下剩余的FMN状态,这些状态管理默认行为并清理虚影控制器。
$ End状态的任务是清除控制器拥有的唯一资源,即更新计时器。 如前所述,如果将此控制器实现为由游戏引擎的更新计时器驱动,则没有必要。

$ Default状态是用于实现行为继承的标准框架模式的示例。 $ Default唯一的事件处理程序是stop事件|<<|
它只是转换为$ End状态。
除$ End状态外的所有状态均从$ Default继承此行为。

这是完整的FMN规范:
在复习有关游戏AI的大量文章和文档时,我经常提到有限状态机(FSM)以及使用UML或类似的图表来表示AI逻辑。 但是,许多这些示例都遭受了UML关于其模型的许多重要方面的歧义的困扰,我们在本文中看到了其中之一。
框架机器符号旨在解决此类歧义,并且仅允许创建机器规范,这些规范具有清晰的代码实现方式。
在以后的文章中,我将以FMN规范为主题返回游戏AI,同时还将探索其他有趣的应用程序。