UE5 Artificial Intelligence
人工智能 (AI) 通常是指非玩家角色如何做出决定。这可能就像敌人看到玩家然后攻击一样简单。它也可以是更复杂的东西,例如实时策略中的 AI 控制玩家。
在虚幻引擎中,可以使用行为树来创建 AI 。行为树是用于确定AI 应该执行哪种行为的系统。
例如,可能有打架和逃跑行为。可以创建行为树,以便 AI 在生命值高于 50% 时进行战斗。如果低于50%,它就会跑掉。
- 创建可以控制 Pawn 的 AI 实体
- 创建和使用行为树(behavior trees)和黑板(blackboards)
- 使用 AI Perception 给 Pawn 视线
- 创建行为以使 Pawn 漫游并攻击敌人
入门
下载起始项目并解压缩。导航到项目文件夹并打开MuffinWar.uproject。
按播放开始游戏。在围栏区域内左键单击以生成松饼。
在本教程中,将创建一个会四处游荡的 AI。
当敌人的松饼进入 AI 的视野范围内时,AI 会移动到敌人身边并对其进行攻击。
要创建 AI 角色,需要三样东西:
- 身体:这是角色的物理表现。在这种情况下,松饼就是身体。
- 灵魂:灵魂是控制角色的实体。这可能是玩家或 AI。
- 大脑:大脑是人工智能做出决定的方式。可以用不同的方式创建它,例如 C++ 代码、蓝图或行为树。
既然已经有了身体,那么所需要的只是灵魂和大脑。首先,将创建一个作为灵魂的控制器。
什么是控制器?
控制器是可以拥有Pawn 的非物理参与者。Possession 允许控制器(猜对了)控制Pawn。但在这种情况下,“控制”是什么意思?
对于玩家来说,这意味着按下按钮并让 Pawn 做某事。控制器接收来自玩家的输入,然后它可以将输入发送到 Pawn。控制器也可以改为处理输入,然后告诉 Pawn 执行操作。
在 AI 的情况下,Pawn 可以从控制器或大脑接收信息(取决于对其进行编程的方式)。
要使用 AI 控制松饼,需要创建一种特殊类型的控制器,称为AI 控制器。
创建一个人工智能控制器
导航到 Characters\Muffin\AI
并创建一个新的 Blueprint Class
。选择 AIController
作为父类并将其命名为 AIC_Muffin
。
接下来,需要告诉松饼使用的新 AI 控制器。导航到 Characters\Muffin\Blueprints
并打开 BP_Muffin。
默认情况下,Details 面板应显示蓝图的默认设置。如果没有,请单击工具栏中的类默认值。
转到 Details 面板并找到Pawn部分。将AI 控制器类设置为AIC_Muffin。这将在松饼生成时生成控制器的一个实例。
由于要生成松饼,因此还需要将Auto Possess AI设置为Spawned。这将确保AIC_Muffin在生成时自动拥有BP_Muffin。
单击Compile,然后关闭BP_Muffin。
现在,将创建驱动松饼行为的逻辑。为此,可以使用行为树。
创建行为树
导航到 Characters\Muffin\AI
并选择 Add New\Artificial Intelligence\Behavior Tree
。将其命名为BT_Muffin
然后打开它。
行为树编辑器
行为树编辑器包含两个新面板:
- 行为树:此图是创建节点以制作行为树的位置
- 详细信息:选择的节点将在此处显示其属性
- 黑板:此面板将显示黑板键(稍后会详细介绍)及其值。只会在游戏运行时显示。
与蓝图一样,行为树由节点组成。
行为树中有四种类型的节点。
前两个是tasks和composites。
什么是任务和组合? tasks & composites
顾名思义,任务是一个“做”某事的节点。
这可能是一些复杂的事情,例如执行组合。也可以是简单的事情,比如等待。
要执行任务,需要使用复合材料。行为树由许多分支(行为)组成。每个分支的根是一个组合。不同类型的组合有不同的方式来执行它们的子节点。
例如,有以下操作序列:
要按顺序执行每个操作,可以使用Sequence组合。这是因为 Sequence 从左到右执行其子级。
这是它的样子:
注意:从组合开始的一切都可以称为子树。通常,这些是的行为。
在这个例子中,序列、移动到敌人、旋转到敌人和攻击可以被认为是“攻击敌人”行为。
如果一个Sequence的任何一个孩子失败,序列将停止执行。
例如,如果 Pawn 无法移动到敌人,Move To Enemy将失败。这意味着Rotate Towards Enemy和Attack将不会执行。但是,如果 Pawn 成功移动到敌人,它们就会执行。
稍后,还将了解Selector组合。现在,将使用Sequence让 Pawn 移动到随机位置,然后等待。
移动到随机位置
创建一个Sequence并将其连接到Root。
接下来,需要移动 Pawn。创建一个MoveTo并将其连接到Sequence。该节点会将 Pawn 移动到指定位置或角色。
然后,创建一个Wait并将其连接到Sequence。确保将它放在MoveTo的右侧。顺序在这里很重要,因为孩子们将从左到右执行。
注意:可以通过查看每个节点右上角的数字来检查执行顺序。编号较低的节点优先于编号较高的节点。
恭喜,刚刚创建了第一个行为!它会将 Pawn 移动到指定位置,然后等待五秒钟。
要移动 Pawn,需要指定一个位置。但是,MoveTo只接受通过 blackboards 提供的值,因此需要创建一个。
创建黑板 blackboards
黑板是一种资产,其唯一功能是保存变量(称为键)。可以将其视为 AI 的记忆。
虽然不需要使用它们,但黑板提供了一种方便的方式来读取和存储数据。
这很方便,因为行为树中的许多节点只接受黑板键。
要创建一个,返回内容浏览器并选择 添加新 \ 人工智能 \ 黑板 。将其命名为 BB_Muffin 然后打开它。
黑板编辑器
黑板编辑器由两个面板组成:
- 黑板:此面板将显示的按键列表
- 黑板详细信息:此面板将显示所选键的属性
现在,需要创建一个密钥来保存目标位置。
创建目标位置键
由于在 3D 空间中存储位置,因此需要将其存储为矢量。点击New Key并选择Vector。将其命名为TargetLocation。
接下来,需要一种方法来生成随机位置并将其存储在黑板中。为此,可以使用第三种行为树节点:服务。
什么是服务? Service
服务就像任务一样,可以使用它们来做某事。但是,不是让 Pawn 执行操作,而是使用服务来执行检查或更新黑板。
服务不是单独的节点。相反,它们附加到任务或复合材料。这会导致更有条理的行为树,因为需要处理的节点更少。这是使用任务的样子:
这是使用服务的样子:
现在,是时候创建一个将生成随机位置的服务了。
创建服务
返回BT_Muffin并单击New Service。
这将创建一个新服务并自动打开它。将其命名为BTService_SetRandomLocation。需要返回到内容浏览器来重命名它。
该服务只需要在 Pawn 想要移动时执行。为此,需要将其附加到MoveTo。
打开BT_Muffin,然后右键单击MoveTo。选择添加服务\BTService 设置随机位置。
现在,BTService_SetRandomLocation将在 MoveTo激活时激活。
接下来,需要生成一个随机目标位置。
生成随机位置
打开BTService_SetRandomLocation。
要知道服务何时激活,请创建一个事件接收激活 AI节点。这将在服务的父级(它附加到的节点)激活时执行。
注意:还有另一个名为Event Receive Activation的事件执行相同的操作。这两个事件的区别在于Event Receive Activation AI还提供了Controlled Pawn。
要生成随机位置,请添加突出显示的节点。确保将半径设置为500。
这将为提供一个在Pawn 500 个单位范围内的随机导航位置。
注意: GetRandomPointInNavigableRadius使用导航数据(称为NavMesh)来确定一个点是否可导航。在本教程中,我已经为创建了 NavMesh。可以通过转到视口并选择Show\Navigation来可视化它。
如果想创建自己的 NavMesh,请创建一个Nav Mesh Bounds Volume。缩放它,以便它封装想要导航的区域。
接下来,需要将位置存储到黑板中。有两种方法可以指定使用哪个键:
- 可以通过在Make Literal Name节点中使用其名称来指定密钥
- 可以向行为树公开一个变量。这将允许从下拉列表中选择一个键。
将使用第二种方法。创建Blackboard Key Selector类型的变量。将其命名为BlackboardKey并启用Instance Editable。当在行为树中选择服务时,这将允许变量出现。
然后,创建突出显示的节点:
概括:
- 事件接收激活 AI在它的父级(在本例中为MoveTo)激活时执行
- GetRandomPointInNavigableRadius返回受控松饼500个单位内的随机导航位置
- Set Blackboard Value as Vector将黑板键(由 BlackboardKey提供)的值设置为随机位置
点击Compile然后关闭BTService_SetRandomLocation。
接下来,需要告诉行为树使用的黑板。
选择黑板
打开BT_Muffin并确保没有选择任何东西。转到“详细信息”面板。在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。
单击编译,然后返回到主编辑器。按Play,生成一些松饼并观察它们四处游荡。
这是很多设置,但做到了!接下来,将设置 AI 控制器,以便它可以检测其视野范围内的敌人。
为此,可以使用AI Perception。
设置 AI 感知 - AI Perception
AI Perception 是可以添加到 Actor 的组件。使用它,可以为的 AI 提供感官(例如视觉和听觉)。
打开AIC_Muffin,然后添加一个AIPerception组件。
接下来,需要添加一种感觉。由于想要检测另一个松饼何时进入视野,因此需要添加视觉感官。
选择AIPerception,然后转到“详细信息”面板。在AI Perception下,向Senses Config添加一个新元素。
将元素0设置为AI Sight 配置,然后将其展开。
视线主要有以下三种设置:
- Sight Radius 视线半径:松饼可以看到的最大距离。将其保留为3000。
- Lose Sight Radius:如果松饼看到敌人,这是在松饼看不见敌人之前敌人必须移动多远。将其保留在3500。
- Peripheral Vision Half Angle Degrees:松饼的视野有多宽。将其设置为45。这将使松饼具有90度的视野范围。
默认情况下,AI Perception 仅检测敌人(分配给不同团队的演员)。
但是,默认情况下,演员没有团队。当演员没有团队时,AI Perception 认为它是中立的。
在撰写本文时,还没有使用蓝图分配团队的方法。相反,可以只让 AI Perpcetion 检测中立演员。
为此,展开Detection by Affiliation并启用Detect Neutrals。
单击编译,然后返回到主编辑器。按播放并生成一些松饼。按 ‘
键显示 AI 调试屏幕。按小键盘上的4
可视化 AI 感知。当松饼进入视野时,会出现一个绿色球体。
接下来,将把松饼移向敌人。为此,行为树需要了解敌人。可以通过在黑板上存储对敌人的引用来做到这一点。
创建敌人钥匙
打开BB_Muffin ,然后添加一个 Object类型的键。将其重命名为Enemy。
现在,将无法在MoveTo中使用Enemy。这是因为键是一个对象,但MoveTo只接受**Vector或Actor类型的键。
要解决此问题,请选择Enemy然后展开Key Type。将基类设置为Actor。这将允许行为树将Enemy识别为Actor。
关闭BB_Muffin。现在,需要创建一种行为来向敌人移动。
走向敌人
打开BT_Muffin然后断开Sequence和Root。可以通过按住 alt 键并单击**连接它们的电线来执行此操作。暂时将 roam 子树移到一边。
接下来,创建突出显示的节点并将其Blackboard Key设置为Enemy:
这会将 Pawn 移向Enemy。在某些情况下,Pawn 不会完全面向其目标,因此还可以使用Rotate 来面向 BB 入口。
现在,当 AI Perception 检测到另一个松饼时,需要设置Enemy。
设置敌人键
打开AIC_Muffin,然后选择AIPerception组件。添加On Perception Updated事件。
只要感知更新,就会执行此事件。在这种情况下,每当 AI 看到或看不到某物时。此事件还提供了它当前检测到的参与者列表。
添加突出显示的节点。确保将Make Literal Name设置为Enemy。
这将检查 AI 是否已经有敌人。如果没有,需要给它一个。为此,添加突出显示的节点:
概括:
- IsValid将检查Enemy键是否已设置
- 如果没有设置,循环遍历所有当前感知到的actors
- Cast To BP_Muffin将检查演员是否是松饼
- 如果是松饼,检查它是否死了
- 如果IsDead返回false,将松饼设置为新的Enemy然后中断循环
单击Compile,然后关闭AIC_Muffin。按播放键,然后生成两个松饼,一个在另一个前面。后面的松饼会自动走向另一个松饼。
接下来,将创建一个自定义任务来让松饼进行攻击。
创建攻击任务
可以在内容浏览器而不是行为树编辑器中创建任务。创建一个新的蓝图类并选择BTTask_BlueprintBase作为父类。
将其命名为BTTask_Attack然后打开它。添加事件接收执行 AI节点。该节点将在行为树执行BTTask_Attack时执行。
首先,需要制作松饼。BP_Muffin包含一个IsAttacking变量。设置后,松饼将进行攻击。为此,添加突出显示的节点:
如果在当前状态下使用任务,执行将卡在它上面。这是因为行为树不知道任务是否已经完成。要解决此问题,请将Finish Execute添加到链的末尾。
接下来,启用Success。由于使用的是Sequence,这将允许执行BTTask_Attack之后的节点。
图表应该是这样的:
概括:
- Event Receive Execute AI会在行为树运行BTTask_Attack时执行
- Cast To BP_Muffin将检查Controlled Pawn是否为BP_Muffin类型
- 如果是,则设置其IsAttacking变量
- Finish Execute会让行为树知道任务已经成功完成
单击Compile,然后关闭BTTask_Attack。
现在,需要将BTTask_Attack添加到行为树中。
向行为树添加攻击
打开BT_Muffin。然后,将BTTask_Attack添加到**序列的末尾
接下来,将Wait添加到 Sequence的末尾。将其等待时间设置为2。这将确保松饼不会不断发作。
返回主编辑器并按Play。像上次一样生成两个松饼。松饼会向敌人移动和旋转。之后,它会攻击并等待两秒钟。如果它看到另一个敌人,它将再次执行整个序列。
在最后一节中,将把攻击子树和漫游子树组合在一起。
合并子树
要组合子树,可以使用Selector组合。与序列一样,它们也是从左到右执行的。但是,选择器将在孩子成功时停止。通过使用此行为,可以确保行为树只执行一个子树。
打开BT_Muffin,然后在Root节点后创建一个Selector。然后,像这样连接子树:
此设置一次只允许一个子树运行。以下是每个子树的运行方式:
- 攻击: 选择器将首先运行攻击子树。如果所有任务都成功,序列也将成功。选择器将检测到这一点,然后停止执行。这将阻止漫游子树运行。
- 漫游:选择器将首先尝试运行攻击子树。如果没有设置Enemy , MoveTo将失败。这也会导致Sequence失败。由于攻击子树失败,选择器将执行它的下一个子树,即漫游子树。
返回主编辑器,按Play。产生一些松饼来测试它。
“等等,松饼为什么不立即攻击另一个?”
在传统的行为树中,每次更新都从根开始执行。这意味着每次更新,它都会先尝试攻击子树,然后再尝试漫游子树。这意味着如果Enemy的值发生变化,行为树可以立即更改子树。
但是,Unreal 的行为树的工作方式不同。
在 Unreal 中,执行从最后执行的节点开始。由于 AI Perception 不会立即感知到其他参与者,因此漫游子树开始运行。行为树现在必须等待漫游子树完成,然后才能重新评估攻击子树。
要解决此问题,可以使用最终类型的节点:decorators。
创建装饰器 - decorators
与服务一样,装饰器附加到任务或组合。通常,使用装饰器来执行检查。如果结果为真,装饰器也将返回真,反之亦然。通过使用它,可以控制装饰器的父级是否可以执行。
装饰器也有中止子树的能力。这意味着一旦设置了Enemy,就可以停止漫游子树。这将使松饼在检测到敌人后立即攻击敌人。
要使用中止,可以使用黑板装饰器。这些只是检查是否设置了黑板键。打开BT_Muffin,然后右键单击攻击子树的序列。选择添加装饰器\黑板。这会将黑板装饰器附加到序列。
接下来,选择Blackboard装饰器并转到 Details 面板。将Blackboard Key设置为Enemy。
这将检查是否设置了Enemy 。如果不设置,装饰器将失败并导致Sequence失败。这将允许漫游子树运行。
为了中止漫游子树,需要使用Observer Aborts设置。
使用观察者中止
如果选定的黑板键已更改,观察者中止将中止子树。有两种类型的中止:
- Self:此设置将允许攻击子树在Enemy变得无效时自行中止。如果敌人在攻击子树完成之前死亡,就会发生这种情况。
- Lower Priority:此设置将导致较低优先级的树在设置Enemy时中止。由于漫游子树在攻击之后,它的优先级较低。
将Observer Aborts设置为Both。这将启用两种中止类型。
现在,如果攻击子树不再有敌人,它可以立即进入漫游状态。此外,一旦检测到敌人,漫游子树就可以立即进入攻击模式。
这是完整的行为树:
攻击子树总结:
- 如果设置了敌人,选择器 将运行攻击子树
- 如果已设置,Pawn 将向敌人移动和旋转
- 之后,它将执行攻击
- 最后,Pawn 将等待两秒钟
漫游子树总结:
- 如果攻击子树失败,选择器将运行漫游子树。在这种情况下,如果没有设置Enemy,它将失败。
- BTService_SetRandomLocation将生成一个随机位置
- Pawn 将移动到生成的位置
- 之后,它将等待五秒钟
关闭BT_Muffin,然后按Play。生成一些松饼,为有史以来最致命的大逃杀做准备!
扩展
如果想创建更高级的 AI,请查看环境查询系统。该系统将允许的 AI 收集有关环境的数据并对其做出反应。