原文:Unreal Engine 4 Tutorial: Artificial Intelligence
做者:Tommy Tran
译者:Shuchang Liuhtml
在本篇教程中,你将学习如何使用行为树和AI感知来建立一个能四处走动,攻击敌人的简单AI。web
在视频游戏中,人工智能(AI)一般指的是拥有自主决策行为的非玩家角色。AI能够是看到玩家而后进行攻击的简单角色,也能够是即时策略(RTS)游戏里的强大对手。app
在Unreal引擎里,咱们能够经过行为树建立AI。行为树是一个决定AI作哪一种行为的实时决策系统。好比,若是AI有战斗和逃跑两种行为。你能够建立行为树,让AI在高于50%血量时进行战斗,低于50%血量时逃跑。dom
在本篇教程中,你将学习到:编辑器
注意:本篇教程只是Unreal Engine 4系列教程的其中一篇:ide
下载示例项目并解压。进入项目文件夹,双击MuffinWar.uproject打开项目。svg
按下Play运行游戏,在围栏内点击左键生成蘑菇小人。学习
在本例中,咱们将建立一个能四处走动的AI,当其余蘑菇小人进入AI的视野时,AI会追逐对方并进行攻击。动画
要建立一个AI角色,咱们须要三个元素:ui
如今咱们已经有了身体,接着要搞来灵魂和大脑。首先,咱们要建立控制器做为灵魂。
控制器是一个能控制角色单位的非物理Actor。这里所说的“控制”,具体指的是什么意思呢?
对于玩家而言,控制指的是能经过按键操控角色单位。控制器获取玩家输入,并将输入直接传给角色。固然,控制器也能够获取输入进行处理,而后再告诉角色单位作哪一个行为。
对于AI来讲,角色单位就是由控制器或“大脑”(取决于实现方式)来通知其作什么行为的。
为了用AI控制蘑菇小人,咱们须要建立一类特殊的控制器——AI控制器。
打开Characters\Muffin\AI目录并建立Blueprint Class,选中AIController做为父类并命名为AIC_Muffin。
接着,咱们须要让蘑菇小人使用这个AI控制器,打开Characters\Muffin\Blueprints并双击打开BP_Muffin。
默认状况下,Details面板会显示蓝图的默认设置,若是没有显示,就点击Toolbar的Class Defaults。
在Details面板找到Pawn设置,将AI Controller Class设为AIC_Muffin,这样当蘑菇小人生成时,就会对应生成一个AI控制器实例。
因为咱们要动态生成蘑菇小人,Auto Possess AI要设成Spawned。这样当蘑菇小人生成时,AIC_Muffin就会自动控制BP_Muffin。
点击Compile并关闭BP_Muffin。
如今,咱们要来建立决策蘑菇小人行为的逻辑,就要用上行为树。
打开Characters\Muffin\AI目录,并选择Add New\Artificial Intelligence\Behavior Tree,将其命名为BT_Muffin并打开。
行为树编辑器包含3个新面板:
像蓝图同样,行为树也是由节点构成的。行为树有4类节点,前两种分别是任务(tasks)和组合(composites)节点。
顾名思义,任务节点负责完成具体任务,能够是表现一套连招这样的复杂任务,也能够是原地等待这样的简单任务。
要完成多个任务,咱们就要用上组合节点。一个行为树由许多分支(行为)组成。每一个分支的根节点,都是一个组合节点。不一样类型的组合节点,执行其子节点的方式也各不相同。
好比,咱们有一组以下序列的行为:
要按顺序执行每一个行为,咱们就要用上Sequence组合节点,由于Sequence节点可以从左至右的执行子节点,图表看起来是这样的:
注意:从组合节点衍生出来的节点能够称为子树(subtree)。一般来讲,这些节点就统称为一个行为。好比,Sequence,Move To Enemy,Rotate Towards Enemy和Attack就统称为“攻击敌人”行为。
若是Sequence的任意节点执行失败,整个Sequence节点就会中止执行。
好比,若是角色没法移动到敌人身边,Move To Enemy节点就执行失败了,这样Rotate Towards Enemy和Attack节点也就没法继续执行了。反之,若是角色成功移动到敌人边上,就能执行随后两个节点。
后续咱们还会学习Selector组合节点,不过如今先让咱们用Sequence节点实现角色随机移动到某个位置并原地停留。
首先,建立Sequence节点并与Root节点相连。
接着,咱们须要让角色移动起来,建立MoveTo节点与Sequence节点相连,这个节点能够驱动角色移动到特定位置或Actor。
随后,建立Wait节点与Sequence节点相连,确保将其放置在MoveTo节点右边,放置顺序很是重要,由于子节点是按照从左到右的顺序执行的。
注意:你能够经过每一个节点右上角的数字确认其执行顺序。数字越小执行顺序越高。
恭喜你,你刚刚建立了你的第一个行为!它将会驱动角色移动到指定位置并原地停留数秒。
为了让角色移动,咱们还须要指定要移动的位置。因为MoveTo节点只接受由黑板提供的数值,咱们要先建立一个黑板。
黑板是一个单纯用来存放变量(键值)的资源。咱们能够将其理解为AI的内存。
虽然黑板不是必须使用的,但它确实为咱们读取,存取数据提供了极大便利,这么说的缘由是不少行为树节点只接受黑板键值做为参数输入。
要建立一个黑板,咱们在Content Browser选择新建Add New\Artificial Intelligence\Blackboard,将其命名为BB_Muffin并打开。
黑板编辑器由2个面板组成:
如今,咱们要建立一个键值用于存放目标位置。
因为是3D空间里的一个位置点,咱们须要用Vector来进行存储。点击New Key并选择Vector,将其命名为TargetLocation。
接着,咱们须要随机生成一个位置并将其存在黑板里,咱们就须要用到第三种类型的行为树节点:服务(service)节点。
服务节点相似于任务节点,用于完成一些事情。然而,不一样于操控角色作特定行为,服务节点用于执行检查或更新黑板操做。
服务并非独立节点,而是依附于任务节点或者组合节点。这样使得行为树更加简洁易于组织,不会横生太多节点。若是咱们用任务节点来实现,效果以下图所示:
若是用服务节点来实现,则以下图所示:
如今,让咱们来建立一个生成随机位置的服务吧。
回到BT_Muffin并点击New Service。
这样就会新建一个服务并自动打开,咱们回到Content Browser将其重命名为BTService_SetRandomLocation。
服务应当且仅当在角色准备移动时才执行,所以咱们要将它附着在MoveTo节点上。
打开BT_Muffin,右键点击MoveTo节点,从弹出菜单选择Add Service\BTService Set Random Location。
如今,当MoveTo激活执行时,BTService_SetRandomLocation也会跟着激活执行。
接着,咱们须要随机生成目标点位置。
打开BTService_SetRandomLocation。
为了监听获知服务什么时候触发执行,咱们建立Event Receive Activation AI节点,这个节点会在服务父类(所附着的节点)激活时触发执行。
注意:另外一个事件Event Receive Activation也有着相同的触发时机,二者区别在于Event Receive Activation AI事件额外提供了Controlled Pawn参数。
为了生成随机位置,添加以下高亮节点,确保将Radius设置为500。
这样就能返回获得该角色500单位半径内的一个随机可达目标点。
注意:GetRandomPointInNavigableRadius节点使用了导航数据(称之为NavMesh)来判断一个点是否可达。在本例中,我已提早建立好了NavMesh。你能够经过在Viewport选中Show\Navigation观察NavMesh。
![]()
若是你想建立本身的NavMesh,请建立 Nav Mesh Bounds Volume,缩放其大小为理想可达区域。
接下来,咱们须要将位置数据存储到黑板里。有两种方式指定要存放的键值:
这里咱们使用第二种方法。建立类型为Blackboard Key Selector的变量。将其命名为BlackboardKey并启用Instance Editable,这样行为树里的服务就会出现对应变量。
随后,建立以下高亮节点:
小结:
点击Compile并关闭BTService_SetRandomLocation。
接着,咱们须要让行为树来使用这个黑板值。
打开BT_Muffin并确保没有选中任何东西。在Details面板的Behavior Tree设置处,将Blackboard Asset设为BB_Muffin。
而后MoveTo和BTService_SetRandomLocation就会自动使用黑板的第一个键值,在本例中,就是TargetLocation。
最后,咱们须要让AI控制器来运行行为树。
打开AIC_Muffin并链接Run Behavior Tree节点与Event BeginPlay节点,将BTAsset设为BT_Muffin。
这样当AIC_Controller生成时就会执行BT_Muffin。
点击Compile并返回主编辑器,按下Play运行游戏,生成一些蘑菇小人,观察它们四处走动吧。
虽然设置很繁琐,咱们仍是搞定了!接着,咱们要进一步设置AI控制器,让它能够在必定范围内感知敌人所在。要实现这点,就要使用AI感知(AI Perception)。
AI感知是一个能够添加给Actor的组件,经过它,咱们能够给AI添加感官能力(如视觉和听觉)。
打开AIC_Muffin并添加AIPerception。
接着,咱们要添加一个感官,因为咱们想要蘑菇小人可以感知到其余小人靠近,咱们给它加上视觉感官。
选中AIPerception并在Details面板的AI Perception设置处,给Senses Config添加新元素。
将元素0设置为AI Sight config并展开它。
对于视觉有3个主要设置:
默认状况下,AI感知只检测敌人(被指定为不一样队伍(team)的Actor)。然而,Actor默认是没有设置队伍的,若是Actor没有队伍,AI感知就会将其认为中立(neutral)角色。
截至目前,尚未方法能经过蓝图设置Actor的队伍,退而求其次,咱们展开Detection by Affiliation设置,启用Detect Neutrals。
点击Compile并回到主编辑器。按下Play运行游戏来生成蘑菇。按下 ‘ 键能够显示AI调试信息,按下小键盘的数字键4能够可视化AI感知组件。当蘑菇小人进入视野时,就会显示绿色球体。
接着,咱们要让蘑菇小人往敌人的方向走去。要实现这点,行为树就要了解敌人的信息,咱们经过在黑板存储敌人的引用来完成这件事。
打开BB_Muffin并添加类型为Object的键值,将其命名为Enemy。
如今,咱们还不能在MoveTo节点使用Enemy,由于其键值类型为Object,但MoveTo只接受Vector或Actor类型的键值。
为了解决这点,咱们选中Enemy并展开Key Type,将Base Class设置为Actor。这样行为树就能将Enemy识别为Actor了。
关闭BB_Muffin,如今,咱们要建立一个行为让AI向敌人走去。
打开BT_Muffin并断开Sequence和Root链接。咱们能够经过按住Alt键点击连线来作到,并将移动子树移到一边。
接着,建立以下高亮节点,并将Blackboard Key设置为Enemy:
这样角色就会朝Enemy走去。有时候,角色不会恰好面对着它的目标,因此咱们还须要用上Rotate to face BB entry节点。
如今,咱们须要在AI感知检测到其余蘑菇时,将其设置为Enemy的值。
打开AIC_Muffin并选中AIPerception组件,添加Perception Updated事件。
只要感官发生更新,这个事件就会触发执行。在本例中,当AI得到或丢失了某物体的视野,这个事件就会执行,并提供了其当前所能感知到的Actor列表。
添加以下高亮节点,并确保将Make Literal Name节点设置为Enemy。
这样就能够判断AI目前有没有敌人对象,若是没有,咱们就要给它设置一个敌人,所以添加以下节点:
小结:
点击Compile并关闭AIC_Muffin,按下Play运行游戏并生成两个蘑菇小人,其中一个生成暴露在另外一个面前,后者就会自动向前者走过去。
接着,你要建立一个自定义任务,让蘑菇小人能够表演攻击行为。
咱们能够直接在Content Browser建立任务,而无须经过行为树编辑器。建立新的Blueprint Class类,并将BTTask_BlueprintBase做为其父类。
将新建类命名为BTTask_Attack并打开,添加Event Receive Execute AI节点,这个节点会在行为树激活BTTask_Attack时触发执行。
首先,你须要让蘑菇执行攻击行为。BP_Muffin包含一个IsAttacking变量,当变量设置为true时,蘑菇会执行一次攻击,所以咱们添加以下高亮节点:
若是这个任务节点在这里就结束了,那行为树执行就会卡在这个节点上,由于行为树并不知道该节点已执行完毕了,因此咱们要在节点链末端添加Finish Execute节点。
接着,启用Success,因为咱们用的是Sequence,这样就能让BTTask_Attack的后续节点得以执行。
如今图表看起来应该是这样的:
小结:
点击Compile并关闭BTTask_Attack。
如今,咱们须要将BTTask_Attack节点添加到行为树中。
打开BT_Muffin,随后,将BTTask_Attack节点添加到Sequence节点后面。
接着,将Wait节点添加到Sequence节点后面,并将Wait Time设置为2。确保蘑菇小人不会攻击个不停。
回到主编辑器点击Play运行游戏,像上次同样生成两个蘑菇小人。蘑菇小人会朝着敌人走去。随后,它会尝试攻击,而后休息两秒。当它发现另外一个敌人时,又会重复以上行为。
在最后一部分,咱们要将攻击和移动两颗子树合并在一块儿。
为了合并子树,咱们要用上Selector组合节点。相似于Sequence节点,它也是按从左向右的顺序执行的。然而,Selector节点会在子节点返回成功而非失败时中止执行。利用这个特性,就能够确保行为树每次只执行一颗子树。
打开BT_Muffin并在Root节点下建立Selector节点。随后,以下图链接两个子树:
这样同一时间只有一颗子树会获得执行,下面是每颗子树的执行状况:
攻击: Selector节点会首先运行第一颗子树,若是全部任务都成功了,Sequence节点也会返回执行成功。Selector节点得知执行成功,就会中止执行后面的节点,这样就不会再执行移动节点。
移动: Selector节点会尝试运行前面的攻击子树,若是Enemy尚未值,MoveTo节点就会执行失败,Sequence节点也就一样失败。因为第一个子树失败了,Selector节点就会执行后续这颗移动子树。
回到主编辑器,按下Play运行游戏,生成一些蘑菇小人试试看吧!
“等等,为何图中这个蘑菇小人没有立刻攻击另外一只呢?”
在传统的行为树设计里,行为树每帧都会从根节点开始执行,意味着每帧更新,它都会尝试执行第一颗攻击子树,而后再执行第二颗移动子树,这也意味着当Enemy值发生变化时,行为树就会立刻切换执行另外一颗子树。
然而,Unreal的行为树并非这样设计执行的。在Unreal里,行为树会继续执行上一帧选中的那颗子树。图中因为AI感知没有立刻感知到另外一只蘑菇小人的存在,行为树开始执行移动子树,因而行为树就只能乖乖等待移动子树执行完毕,才能从新评估肯定执行攻击子树。
为了解决这个问题,咱们须要用上最后一种类型节点:装饰(decorators)节点。
相似于服务节点,装饰节点也依附于任务或组合节点。一般而言,装饰节点用于作前置检查。若是检查结果为true,装饰节点就返回true,反之亦然。经过装饰节点,就能控制其依附节点是否可以执行。
装饰节点也有能力停止子树的运行,这意味着咱们能实现一旦Enemy有设值,就当即停止移动子树。这样蘑菇小人就能在发现敌人的第一时间攻击敌人。
要实现停止功能,咱们可使用Blackboard装饰节点,这个节点只是简单地检查某个黑板键值是否有值。打开BT_Muffin,并在攻击子树的Sequence节点点击右键,从弹出菜单选中Add Decorator\Blackboard,这样Sequence节点就会添加上Blackboard节点。
接着,选中Blackboard装饰节点,并在Details面板将Blackboard Key设为Enemy。
这样能够判断Enemy是否有值,若是没有值,节点返回失败,从而致使Sequence失败,从而让移动子树获得执行。
为了停止移动子树,咱们须要用上Observer Aborts设置。
Observer Aborts可以实现所选中的黑板键值发生变化时,停止执行子树,这里分为两种类型的停止:
咱们将Observer Aborts设为Both,同时启用两种类型的停止。
如今,当AI已经没有敌人目标时,能够立刻从攻击子树切换运行移动子树。一样的,当AI检测到敌人目标时,又能从移动子树切换运行攻击子树。
如下是完整的行为树图表:
攻击子树小结:
移动子树小结:
关闭BT_Muffin并按下Play运行游戏,生成一些蘑菇小人进行一场你死我活的决斗吧!
你能够在这里下载完整项目。
如你所见,制做简单AI还算一件不难的事。若是你想建立一个更加高级的AI,请查阅场景查询系统,这个系统容许AI收集场景数据并做出相应的反馈。
若是你还想继续学习引擎其余内容,点击下篇教程,将教你如何制做一个简单的第一人称射击游戏。