找回密码
 立即注册
查看: 518|回复: 0

Unreal Engine 4 Tutorial 09 人工智能+行为树

[复制链接]
发表于 2022-8-31 09:19 | 显示全部楼层 |阅读模式
资源与声明:

1-本文章部分图片与文字来源 Tommy Tran《Unreal Engine 4 Tutorial for Beginners》
https://www.raywenderlich.com/663-unreal-engine-4-blueprints-tutorial
本文章提供自己的见解看法,与学习笔记,如有侵权 欢迎联系删除,若文章有误,欢迎指正讨论;
<hr/>关键点有几个:
1-创建一个可以控制Pawn的AI AIC_Muffin
2-创建行为树 BT_Muffin
3-AI感知提供Pawn的视觉
4-Pawn的漫游与攻击敌人

下载启动项目并解压缩。导航到项目文件夹并打开MuffinWar.uproject
播放开始游戏。在围栏区域内左键单击以生成松饼。


在本教程中,您将创建一个会四处游荡的 AI。当敌人的松饼进入 AI 的视野范围时,AI 会移动到敌人并攻击它。
要创建一个 AI 角色,您需要三件事:是逐级递进的

  • 身体这是角色的物理表现。在这种情况下,松饼就是身体。
  • 灵魂灵魂是控制角色的实体。这可能是玩家或 AI。
  • 大脑大脑是人工智能做出决定的方式。您可以通过不同的方式创建它,例如 C++ 代码、蓝图或行为树。
既然你已经有了身体,你所需要的只是一个灵魂和大脑。首先,您将创建一个将成为灵魂的控制器。
控制器是可以拥有Pawn的非物理角色。Possession 允许控制器——你猜对了——控制Pawn。但在这种情况下,“控制”是什么意思?
对于玩家来说,这意味着按下一个按钮并让 Pawn 做一些事情。控制器从玩家接收输入,然后它可以将输入发送到 Pawn。控制器也可以改为处理输入,然后告诉 Pawn 执行操作。



在 AI 的情况下,Pawn 可以从控制器或大脑接收信息(取决于您如何对其进行编程)。
要使用 AI 控制松饼,您需要创建一种特殊类型的控制器,称为AI 控制器。 就是一个控制Muffin的控制器。
1-创建 AI 控制器

导航到Characters\Muffin\AI并创建一个新的Blueprint Class。选择AIController作为父类并将其命名为AIC_Muffin。(第一个文件)


接下来,您需要告诉松饼使用您的新 AI 控制器。导航到Characters\Muffin\Blueprints并打开BP_Muffin
默认情况下,详细信息面板应显示蓝图的默认设置。如果没有,请单击工具栏中的类默认值


转到 Details 面板并找到Pawn部分。将AI 控制器类设置为AIC_Muffin。这将在松饼生成时生成控制器实例。


由于您正在生成松饼,因此您还需要将Auto Possess AI设置为Spawned。这将确保AIC_Muffin在生成时自动拥有BP_Muffin


单击编译,然后关闭BP_Muffin
现在,您将创建驱动松饼行为的逻辑。为此,您可以使用行为树
2-创建行为树

导航到Characters\Muffin\AI并选择Add New\Artificial Intelligence\Behavior Tree。将其命名为BT_Muffin,然后打开它。
2-1行为树编辑器

行为树编辑器包含两个新面板:



  • 行为树:此图是您将在其中创建节点以制作行为树的地方
  • 详细信息:您选择的节点将在此处显示其属性
  • 黑板:此面板将显示黑板键(稍后会详细介绍)及其值。仅在游戏运行时显示。
与蓝图一样,行为树由节点组成。行为树中有四种类型的节点。前两个是任务复合
2-2什么是任务和组合?

顾名思义,任务是“做”某事的节点。这可能是复杂的事情,例如执行组合。也可以是简单的事情,例如等待。


要执行任务,您需要使用组合。行为树由许多分支(行为)组成。每个分支的根部是一个复合体。不同类型的组合有不同的方式来执行它们的子节点。
例如,您有以下一系列操作:


要执行序列中的每个操作,您将使用序列组合。这是因为序列从左到右执行其子级。这是它的样子:


注意:从组合开始的所有内容都可以称为子树。一般来说,这些是你的行为。在这个例子中,SequenceMove To EnemyRotate Towards EnemyAttack可以被认为是“攻击敌人”的行为。
如果序列的任何子节点失败,序列将停止执行。
例如,如果 Pawn 无法移动到敌人身边,Move To Enemy将失败。这意味着Rotate Towards EnemyAttack不会执行。但是,如果 Pawn 成功移动到敌人身边,它们将执行。
稍后,您还将了解Selector组合。现在,您将使用序列使 Pawn 移动到随机位置,然后等待。
2-3移动到随机位置

创建一个Sequence并将其连接到Root


接下来,您需要移动 Pawn。创建一个MoveTo并将其连接到Sequence。该节点会将 Pawn 移动到指定的位置或演员。


然后,创建一个Wait并将其连接到Sequence。确保将其放置在MoveTo的右侧。顺序在这里很重要,因为孩子们会从左到右执行。


注意:您可以通过查看每个节点右上角的数字来检查执行顺序。编号较低的节点优先于编号较高的节点。
恭喜,您刚刚创建了您的第一个行为!它会将 Pawn 移动到指定位置,然后等待五秒钟。
要移动 Pawn,您需要指定一个位置。但是,MoveTo只接受通过黑板提供的值,因此您需要创建一个。
2-4创建黑板

黑板是一种资产,其唯一功能是保存变量(称为)。你可以把它想象成人工智能的记忆
虽然您不需要使用它们,但黑板提供了一种方便的方式来读取和存储数据。这很方便,因为行为树中的许多节点只接受黑板键。
要创建一个,请返回内容浏览器并选择Add New\Artificial Intelligence\Blackboard。将其命名为BB_Muffin,然后打开它。
2-5黑板编辑器

黑板编辑器由两个面板组成:



  • 黑板:此面板将显示您的按键列表
  • 黑板详细信息:此面板将显示所选键的属性
现在,您需要创建一个保存目标位置的密钥。
2-6创建目标位置键

由于您将位置存储在 3D 空间中,因此您需要将其存储为矢量。单击New Key并选择Vector。将其命名为TargetLocation


接下来,您需要一种方法来生成随机位置并将其存储在黑板上。为此,您可以使用第三种类型的行为树节点:服务
2-7什么是服务?

服务就像您使用它们做某事的任务。但是,您使用服务来执行检查或更新黑板,而不是让 Pawn 执行操作。
服务不是单独的节点。相反,它们附加到任务或组合上。这会产生更有条理的行为树,因为您需要处理的节点更少。以下是使用任务的外观:



以下是使用服务的外观:



现在,是时候创建一个生成随机位置的服务了。
2-8创建服务

返回BT_Muffin并单击New Service



这将创建一个新服务并自动打开它。将其命名为BTService_SetRandomLocation。您需要返回内容浏览器来重命名它。
该服务只需要在 Pawn 想要移动时执行。为此,您需要将其附加到MoveTo
打开BT_Muffin,然后右键单击MoveTo。选择Add Service\BTService Set Random Location


现在,BTService_SetRandomLocation将在MoveTo激活时激活。
接下来,您需要生成一个随机目标位置。
2-9生成随机位置

打开BTService_SetRandomLocation
要知道服务何时激活,请创建一个Event Receive Activation AI节点。这将在服务的父节点(它所连接的节点)激活时执行。



注意:还有另一个称为Event Receive Activation的事件可以做同样的事情。这两个事件的区别在于Event Receive Activation AI还提供了Controlled Pawn
要生成随机位置,请添加突出显示的节点。确保将Radius设置为500



这将在 Pawn 的500个单位内为您提供一个随机的可导航位置。
注意: GetRandomPointInNavigableRadius使用导航数据(称为NavMesh)来确定一个点是否可导航。在本教程中,我已经为您创建了 NavMesh。您可以通过转到 Viewport 并选择Show\Navigation来可视化它。



如果您想创建自己的 NavMesh,请创建Nav Mesh Bounds Volume。缩放它,使其封装您想要导航的区域。
接下来,您需要将位置存储到黑板上。有两种方法可以指定使用哪个键:

  • 您可以通过在Make Literal Name节点中使用其名称来指定密钥
  • 您可以将变量公开给行为树。这将允许您从下拉列表中选择一个键。
您将使用第二种方法。创建Blackboard Key Selector类型的变量。将其命名为BlackboardKey并启用Instance Editable。当您在行为树中选择服务时,这将允许变量出现。



然后,创建突出显示的节点:
就是把这个Random生成的节点 存储到这个blackboard的key里面



概括:

  • 事件接收激活 AI在其父级(在本例中为MoveTo)激活时执行
  • GetRandomPointInNavigableRadius返回受控松饼500个单位内的随机可导航位置
  • Set Blackboard Value as Vector将黑板键(由BlackboardKey提供)的值设置为随机位置
单击编译,然后关闭BTService_SetRandomLocation
接下来,您需要告诉行为树使用您的黑板。
2-10选择黑板

打开BT_Muffin并确保您没有选择任何东西。转到详细信息面板。在Behavior Tree下,将Blackboard Asset设置为BB_Muffin



之后,MoveToBTService_SetRandomLocation将自动使用第一个黑板键。在这种情况下,它是TargetLocation



最后,您需要告诉 AI 控制器运行行为树。
2-11运行行为树

打开AIC_Muffin并将Run Behavior Tree连接到Event BeginPlay。将BTAsset设置为BT_Muffin



这将在AIC_Controller生成时运行BT_Muffin
单击编译,然后返回主编辑器。按Play,生成一些松饼,看着它们四处游荡。



这是很多设置,但你到了那里!接下来,您将设置 AI 控制器,以便它可以检测到其视野范围内的敌人。为此,您可以使用AI Perception
3-设置 AI 感知

AI Perception 是一个可以添加到 actor 的组件。使用它,您可以为您的 AI 赋予感官(例如视觉和听觉)。
打开AIC_Muffin,然后添加一个AIPerception组件。


接下来,您需要添加一种感觉。由于您想检测另一个松饼何时进入视野,因此您需要添加视觉
选择AIPerception,然后转到详细信息面板。在AI Perception下,向Senses Config添加一个新元素。


将元素0设置为AI Sight 配置,然后展开它。


视线有三个主要设置:

  • 视线半径松饼可以看到的最大距离。将其保留为3000
  • 失明半径如果松饼看到了敌人,这是在松饼看不见之前敌人必须移动的距离。将其保留为3500
  • 周边视野半角度数:松饼的视野有多宽。将此设置为45。这将使松饼有90度的视野。




默认情况下,AI 感知仅检测敌人(分配给不同团队的演员)。但是,演员默认没有团队。当演员没有团队时,AI Perception 认为它是中立的。
在撰写本文时,还没有使用蓝图分配团队的方法。相反,您可以告诉 AI Perpcetion 检测中立的演员。为此,请展开按从属关系检测并启用Detect Neutrals


单击编译,然后返回主编辑器。按播放并生成一些松饼。按'键显示 AI 调试屏幕。按数字键盘上的4以可视化 AI 感知。当松饼进入视野时,会出现一个绿色球体。


接下来,您将松饼移向敌人。为此,行为树需要了解敌人。您可以通过在黑板上存储对敌人的引用来做到这一点。
4-Pawn的漫游与攻击敌人

4-1创建敌人密钥

打开BB_Muffin,然后添加一个Object类型的键。将其重命名为Enemy


现在,您将无法在MoveTo中使用Enemy。这是因为键是ObjectMoveTo只接受VectorActor类型的键。
要解决此问题,请选择Enemy,然后展开Key Type。将基类设置为Actor。这将允许行为树将Enemy识别为Actor


关闭BB_Muffin。现在,您需要创建一个行为以向敌人移动。
4-2走向敌人

打开BT_Muffin然后断开SequenceRoot。您可以通过按住 alt 键单击连接它们的电线来完成此操作。暂时将漫游子树移到一边。
接下来,创建突出显示的节点并将其Blackboard Key设置为Enemy


这会将 Pawn 移向Enemy。在某些情况下,Pawn 不会完全面向其目标,因此您还可以使用Rotate 来面对 BB entry
现在,当 AI Perception 检测到另一个松饼时,您需要设置Enemy 。
4-3设置敌人键

打开AIC_Muffin,然后选择AIPerception组件。添加一个On Perception Updated事件。


每当感知更新时,都会执行此事件。在这种情况下,每当人工智能看到或看不见某物时。此事件还提供了它当前感知的演员列表。
添加突出显示的节点。确保将Make Literal Name设置为Enemy


这将检查 AI 是否已经有敌人。如果没有,你需要给它一个。为此,请添加突出显示的节点:


概括:

  • IsValid将检查是否设置了Enemy
  • 如果未设置,则遍历所有当前感知的演员
  • Cast To BP_Muffin将检查演员是否是松饼
  • 如果是松饼,检查它是否死了
  • 如果IsDead返回false,将松饼设置为新的敌人,然后打破循环
单击编译,然后关闭AIC_Muffin。按播放,然后生成两个松饼,使一个在另一个前面。后面的松饼会自动走向另一个松饼。


接下来,您将创建一个自定义任务以使松饼执行攻击。
4-4创建攻击任务

您可以在内容浏览器而不是行为树编辑器中创建任务。创建一个新的蓝图类并选择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会让行为树知道任务已经成功完成
单击编译,然后关闭BTTask_Attack
现在,您需要将BTTask_Attack添加到行为树中。
4-5向行为树添加攻击

打开BT_Muffin然后,在序列的末尾添加一个BTTask_Attack


接下来,将Wait添加到Sequence的末尾。将其等待时间设置为2。这将确保松饼不会不断攻击。


返回主编辑器并按Play。像上次一样产生两个松饼。松饼会向敌人移动并旋转。之后,它会攻击并等待两秒钟。如果它看到另一个敌人,它将再次执行整个序列。


在最后一节中,您将把攻击和漫游子树组合在一起。
4-6合并子树

要组合子树,您可以使用Selector组合。与序列一样,它们也从左到右执行。但是,当子成功而不是失败时,选择器将停止。通过使用此行为,您可以确保行为树只执行一个子树。
打开BT_Muffin ,然后在Root节点之后创建一个Selector 。然后,像这样连接子树:


这种设置一次只允许运行一个子树。以下是每个子树的运行方式:

  • 攻击: 选择器将首先运行攻击子树。如果所有任务都成功,则序列也将成功。选择将检测到这一点,然后停止执行。这将阻止漫游子树运行。
  • 漫游:选择器将首先尝试运行攻击子树。如果没有设置Enemy , MoveTo将失败。这也会导致Sequence失败。由于攻击子树失败,Selector将执行其下一个子树,即漫游子树。
返回主编辑器,按Play。产生一些松饼来测试它。


“等一下,松饼为什么不立即攻击另一个?”
在传统的行为树中,每次更新都从根开始执行。这意味着每次更新,它都会先尝试攻击子树,然后再尝试漫游子树。这意味着如果Enemy的值发生变化,行为树可以立即更改子树。
但是,虚幻的行为树的工作方式不同。在 Unreal 中,从最后执行的节点开始执行。由于 AI 感知不会立即感知其他参与者,因此漫游子树开始运行。行为树现在必须等待漫游子树完成,然后才能重新评估攻击子树。
要解决此问题,您可以使用最终类型的节点:装饰器
4-7创建装饰器

像服务一样,装饰器附加到任务或组合上。通常,您使用装饰器来执行检查。如果结果为真,装饰器也将返回真,反之亦然。通过使用它,您可以控制装饰器的父级是否可以执行。
装饰器还具有中止子树的能力。这意味着一旦设置了Enemy,您就可以停止漫游子树。这将允许松饼在检测到敌人后立即攻击敌人。
要使用中止,您可以使用Blackboard装饰器。这些只是检查是否设置了黑板键。打开BT_Muffin,然后右键单击攻击子树的序列。选择添加装饰器\黑板。这会将 Blackboard 装饰器附加到序列。


接下来,选择Blackboard装饰器并转到 Details 面板。将Blackboard Key设置为Enemy


这将检查是否设置了 Enemy。如果没有设置,装饰器会失败,导致Sequence失败。这将允许漫游子树运行。
为了中止漫游子树,您需要使用Observer Aborts设置。
4-8使用观察者中止

如果选定的黑板键已更改,观察者中止将中止子树。有两种类型的中止:

  • Self:此设置将允许攻击子树在Enemy无效时自行中止。如果敌人在攻击子树完成之前死亡,就会发生这种情况。
  • 较低优先级:此设置将导致较低优先级的树在设置敌人时中止。由于漫游子树在攻击之后,它的优先级较低。
观察者中止设置为两者。这将启用两种中止类型。
现在,如果攻击子树不再有敌人,它可以立即进入漫游状态。此外,一旦检测到敌人,漫游子树可以立即进入攻击模式。
这是完整的行为树:


攻击子树总结:

  • 如果设置了Enemy , Selector将运行攻击子树
  • 如果设置,Pawn 将向敌人移动并旋转
  • 之后,它将执行攻击
  • 最后,Pawn 将等待两秒钟
漫游子树总结:

  • 如果攻击子树失败,Selector将运行漫游子树。在这种情况下,如果没有设置Enemy,它将失败。
  • BTService_SetRandomLocation将生成一个随机位置
  • Pawn 将移动到生成的位置
  • 之后,它将等待五秒钟
关闭BT_Muffin,然后按Play。生成一些松饼,为有史以来最致命的大逃杀做好准备!


您可以在此处下载已完成的项目。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 12:48 , Processed in 0.097236 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表