重要说明:原Unity公众号“Unity官方平台”,因为某些原因无法正常进行更新。现在我们将正式启用新的Unity订阅号Unity官方开发者社区ID:Unitycommunity,为大家分享Unity最新的资讯、功能、教程、活动。请开发者关注新的公众号,一如既往的支持Unity !


在1月的《Unity实现高级可配置化游戏AI系统》直播课程中,我们通过使用ScriptableObject为坦克项目创建了可配置的AI系统。

课程的主要包括四部分的内容:
1 可配置化AI系统介绍及选择ScriptableObject的原因
2 基于有限状态机(FSM)的AI系统设计
3 有限状态机中的状态(State),动作(Action),决策(Decision),状态转化(Transition)的具体实现
4 如何快速扩展新的AI行为

Unity技术经理成亮会对本次课程进行一个全面的梳理与回顾,帮助大家温故知新。

以下为直播视频,视频长1个半小时,请注意请在Wi-Fi状态下观看。
http://v.qq.com/x/page/c0537cidpg9.html


可配置化AI系统及选择ScriptableObject

1 可配置化AI系统介绍
我们期望实现可以灵活配置的AI系统,如图01所示,不同的AI行为对应不同的芯片,坦克只需要切换一下芯片就可视实现不同的AI行为。
041326ltabh7hz5ywy1e9d.jpg
图 01

为了实现AI的可配置化,我们需要代码逻辑能够被保存到数据资产(Asset)中,也就是说支持序列化。很自然的,我们会想到常用的MonoBehavior类,但是Unity还提供了ScriptableObject类,也具有同样的能力。那么该选择哪一个类来实现我们的AI系统呢?下面我们就对二者进行一个比较。

2 为什么选择使用ScriptableObject
我们列举了ScriptableObject和MonoBehaviour的一些特点进行比较。如图02所示。二者都支持数据序列化以及可视化(可以在编辑器中暴露变量并进行编辑),这是实现可配置化系统所必须的。
041326c0u3o6903rok03h5.jpg
图 02

我们再看三个主要的不同点:

(a) ScriptableObject可以保存在”.asset”文件中,而MonoBehaviour只能保存在”.scene”或者”.prefab”中。由于prefab通常是作为物件模版来使用,如果又用于保存逻辑,会造成概念的混淆;
(b)ScriptableObject在运行时不需要作为GameObject的Component,使用相对简单和直接;
(c) 不包含Transform, gameObject等数据,比MonoBehaviour更加轻量级。

因此,使用ScriptableObject来实现可配置化AI会更加的简洁和方便。

基于有限状态机(FSM)的AI系统
我们来介绍下AI系统的具体设计。在游戏开发中,常用的一些AI技术包括有限状态机,行为树,以及最近开始流行的机器学习等。这次我们在坦克项目中所采用的是有限状态机。

1 有限状态机介绍

我们可以用下面的句话来描述有限状态机:

(a) 一台具有有限个状态的抽象机器。比如我们可以把坦克就比做这台机器,它包含巡逻,追逐等有限个状态。
(b) 状态机中的状态可以因为输出或者环境改变转换到另外的状态。比如当坦克发现敌人后就从巡逻状态转换到追逐状态。
(c) 每个状态包含一些列动作以及状态转换所需要的决策。比如当坦克发现敌人后,是转换到追逐状态,还是保持当前状态。

041325n1ui5y6zvk202l0l.jpg
图 03

相较于完全用if语句去编写AI,通过有限状态机,AI逻辑会划分得更加的清晰,甚至可以开发出对应的图形化工具进行AI设计与实现。

2 坦克AI系统设计
通过以上介绍,坦克的AI系统采用了有限状态机。我们要实现的第一个AI行为称之为追逐者,它表现为在没有发现敌人的时候会沿着设定好的路径进行巡视,当发现敌人后就一只追逐敌人直到把目标摧毁。

因此我们为它设计了两个状态:巡视(Patrol)和追逐(Chase)。为了引用和控制这些状态的执行,我们为坦克设计了StateController的组件,可以把他想象为AI芯片的插槽。AI系统的构成如图04所示。
041325xc5f6mcn4uboi7mc.jpg
图 04


有限状态机的实现
介绍完整个坦克AI系统的设计,我们再继续介绍有限状态机的具体实现。当然由于篇幅所限,这里也仅仅是介绍实现中的一些原理和要点。

1 面向对象的设计

在我们的系统中,有的类需要采用到面向对象的方式来设计,比如状态(State)中的动作(Action)。我们既希望用子类来表现不同的实现,也希望用基类来提供同意的接口。所以不同的Action都有一个基类Action, 方便State用统一的接口来管理这些Action。另外,在基类中Act方法我们把它定义为abstract 方法,因为并不需要具体的实现。
041324nfe1592zjlq40z1i.jpg
图 05

2 动作的实现
在目前的AI系统中,我们主要包括3个动作:巡逻,追逐,以及开火。巡逻动作在巡逻状态中执行,追逐和开火动作在追逐状态中执行。下面我们分别来介绍相应的实现。

(a)巡逻(PatrolAction)
巡逻的行为是绕着在地图上设定好的路径点行走,通过Unity自带的导航系统,我们可以很方便的实现这样的功能。另外通过CreateAssetMenu属性,我们可以很方便的在菜单上添加创建PatrolAction资产的命令。
041324m0uyy65ukhthdtdk.jpg
图 06

实现好脚本后,在Unity中就可以创建PatrolAction的资产了。
041324jbywg4dyea9gdrpy.jpg
图 07

(b)追逐(ChaseAction)
追逐的行为是朝着攻击目标移动,实现原理和巡逻类似,也是利用了导航系统。不同的是移动的目标改变了。这个追逐目标是在决策中发现并保存到StateController中的,后面会讲到。
041323wp7qp4stoh3k5453.jpg
图 08


(c) 开火(AttackAction)
开火的行为是朝攻击目标发射炮弹。发射炮弹是坦克项目已经具备的功能,我们调用TankShooting组件的Fire函数就可以实现。
041323tq245dqad294xwv4.jpg
图 09


3 决策的实现

目前系统包括两个决策,一个是巡逻状态的观察决策,另一个是追逐状态的目标是否存活的决策。

(a) 观察决策(LookDecision)
观察决策继承于Decision这个基类,这个实现方式和Action类似。LookDecision同样使用了CreateAssetMenu属性来添加创建资产的菜单项。在目标检查的功能实现上采用了Physics.SphereCast,相对于Physics.Raycast更真实一点。最后当检测到另外的坦克后,就会把该坦克的位置 保存到controller.chaseTarget中作为追逐的目标。
041323lm4mv17qzzbeyz5e.jpg
图 10

(b)目标是否存活决策 (ActiveStateDecision)
判断目标是否存活的决策较为简单,只需判断是否物体是否处于active状态即可。
041322josssnblvi8e8rsl.jpg
图 11

当实现完相应的代码后,我们可以回到Unity创建相应的资产。
041322oo9tlzv65524phl2.jpg
图 12

4 状态转换的实现
状态转换不需要单独作为资产,只是保存决策以及决策对应的两个目标状态。

041322pdzzv8bt6saetbed.jpg
图 13

(a)状态的实现
最后,我们来看一下状态的实现。首先状态(State)继承于ScriptableObject,也使用了CreateAssetMenu属性。包含了相关的动作(Action)和状态转换(Transition)数组。然后在每一帧会调用的UpdateState函数中执行当前状态的动作,以及决策。
041322usbiroqs70s1ymi1.jpg
图 14

实现好代码后,我们就可以在Unity中创建State资产,并配置该状态了。下图就是巡逻状态的配置。
041321mmts1fommmm7r0xi.jpg
图 15

把这些State添加到StateController组件后,我们的坦克就可以执行相应的AI行为了。到此为止,我们的可配置AI系统已经实现了。我们可以组合不同的Action和Decision来实现不同的State,然后通过不同的State来实现不同的AI行为。

增加新的AI
最后,我们再来实现一个稍微不同的AI行为来检视一下我们的可配置AI系统,就是当进入追逐状态后,不再是一直追逐直到目标被摧毁。而是目标离开视线后,就原地巡视,如果再次发现目标,就进入追逐状态,如果巡视时间结束就返回巡逻状态。

(a)AI设计
通过分析,我们为这样的AI行为实现了如下图 16 所示的状态机。
041321n9ml1zd1n1ng9cg1.jpg
图 16

和之前的状态机稍有不同。首先我们对追逐状态做了修改,把判断目标存活的决策替换为观察决策。然后我们增加了预警状态(AlertScanner),在预警状态中,我们使用了扫描决策(ScanDecision)和观察决策(LookDecision)。 而整个状态机的构建唯一需要实现的只有扫描决策,可见我们的状态机具有很好的可配置性。


(b)扫描决策(ScanDecision)实现
该决策的实现比较简单,主要就是选择坦克,以及判断扫描时间是否结束。
041320wtt74xclgt4zxlpy.jpg
图 17

总结

通过本次课程,我们学习了如何用有限状态机来设计AI系统。通过有限状态机我们可以更加清晰的表示游戏物体的AI逻辑,便于我们设计一些较为复杂的AI行为。



除此之外,我们利用ScriptableObject来实现有限状态机中的动作,决策和状态。由于这些对象都可以保存为资产,并且可以在编辑器中进行可视化操作,使得我们可以方便的配置出我们期望的AI行为。而这也正是我们所说的可配置化AI系统。



更多Unity精彩文章, 尽在Unity官方中文论坛(Unitychina.cn)! 直播课程锐亚教育

锐亚教育 锐亚科技 unity unity教程