15、追逐玩家

现在我们的AI无法做出任何决策,它总是执行相同的决策。我们先把感知系统中的相关信息提供给AI,让AI知道如何做出决策,然后我们会修改行为树。我们首先需要创建新的黑板键,这样我们就能在行为树上保存这些信息。打开”BB_EnenmyAI “,在左侧的“黑板”选项卡中,点击“新建”按钮,选择“对象”类型,将这个新建命名为“Target Actor”。在右侧的“黑板详细信息”面板中,在“键”分段中展开“键类型”选项,在“基类”下拉菜单中将类型从“object”改为“Actor”。回到“黑板”面板,再次点击“新建”,这次选择布尔类型,把这个黑板键命名为“Has Line Of Sight”。

接下来,首先在内容浏览器中找到“AIC ThirPerson Character”然后打开它,接着创建一些辅助函数以便让黑板键处理起来更加容易。第一个函数有一个Actor输入,并会把某个黑板键设置为相同的Actor值,在“我的蓝图”面板中点击“函数”分段中的加号图标,新建一个函数,将函数命名为“Update Target Actor Key”。在细节面板中,点击“输入”分段中的加号,新建一个输入,选择“Actor”作为输入类型,将此输入命名为“Target Actor”。第一步是获取当前的黑板。右键事件图表,搜索“Get Blackboard”,选择“AI”>“变量”中的“Get Blackboard”。拖动“黑板”组件对象引用的引脚然后输入“Set value as Object”,这样会自动把黑板对象作为“Set value as Object”的目标参数。接下来,我们需要创建一个键名,它指向与行为树相关联的黑板中的黑板键。为此,我们拖动“Set value as Object”的“key name”,选择提升至变量,将这个新变量命名为“Target Actor Name”。保持选中状态,移到细节面板,找到类别面板,新建一个类别,在这个选项框中输入“Key Names”并以此命名。注意,这样会把我们的新变量自动归类到“我的蓝图”面板中的“Keys Names”类型。下一步是设置“Target Actor Name”的默认值,在此之前,我们需要编译蓝图。

编译后细节面板中“Target Actor Name”的默认值为无,将其设置为与黑板键名相同,即“Target Actor”。“Set value as Object”需要的最后一个参数就是传递给黑板的数值。这里就要用到我们此前创建的输入。将“Target Actor”连到“set values as object”的“object value”,把这个函数的执行引脚连到“Set value as Object”。

我们要创建的下一个函数拥有一个黑板键,它能保存AI当前能否通过感知系统观察到玩家。和之前一样,先在“我的蓝图”面板中新建一个函数,将它命名为“UpdateHasLineOfSightKey”,在细节面板的“输入”分段中,点击加号添加新的输入,确保这个输入是布尔类型,将这个新参数命名为“HasLineOfSight”。和之前的函数一样,我们首先要获得正确的黑板,右键点击事件图表,然后输入“Get Blackboard”,选择“AI”>”变量”中的函数,拖动这个黑板引用的引脚,然后输入“Set value as Bool”,拖动“Key name”变量,选择“提升为变量”,将其命名为“HasLineOfSightName”。 下一步是设置“HasLineOfSightName”的默认值,在此之前,我们需要编译蓝图。编译后细节面板中“HasLineOfSightName”的默认值为无,将其设置为与黑板键名相同,即Has Line Of Sight”。然后将两个函数引脚相连,将“Has Line Of Sight”输入引脚与“bool value”相连。

现在我们要回到角色的“on target perception updated”事件,然后使用这个时间来更新我们新建的黑板键。这意味着每当感知状态发生改变时,相关的黑板键也会更新。

在内容浏览器中找到“AICharacter1”,首先在触发“target lost”事件时,清空“target actor”黑板键。当前,这个事件会在目标超出视野5秒后触发,这表示AI完全遗忘了目标Actor,并放弃进行跟踪。为了访问我们刚刚创建的函数,我们首先要获取AI控制器的引用。右键点击事件图表,然后输入“Get Controller”,直到出现这个函数,这个函数会返回一个泛型控制器引用。我们需要将这个泛型类型转换为“AIC ThirdPerson Character”。为此,我们可以拖动返回值,输入“Cast”,选择“Cast to AIC ThirdPerson Character”。为了保证图表条理清晰便于理解,我们可以转换成纯类型转换,右键点击节点选择“转换为纯类型转换”。现在拖动“AIC ThirdPerson Character”引脚然后引用我们定义的函数即“Update Target Actor Key”,然后连接设置节点的执行引脚,如图所示:

此时,期望的黑板状态是让“target actor”的值为空,也就是现在没有target actor。为此,这个函数不需要提供任何参数。

让我们来看这个事件的另一种结果。我们需要使用“”line of sight”键来表示这种情况,我们利用函数把“HasLineOfSight”键设置为假,我们可以复制这两个节点“Get Controller”和“Cast to AIC ThirdPerson Character”,他们允许我们获得“AIC ThirdPerson Character”AI控制器。再次拖动“AIC ThirdPerson Character”引脚然后引用我们定义的函数即“update has line if sight key”, 然后连接设置节点的执行引脚,如图所示:

复制这三个节点“Get Controller”和“Cast to AIC ThirdPerson Character”和“Update Target Actor Key”,将他们的执行节点连接到“clear and invalidate timer by handle“。这个句柄当前连到分支的”真“值引脚,这种情况下我们需要提供”target actor“。所幸我们之前已经设置好了,找到”我的蓝图“面板,找到”PerceivedActor“,按住Ctrl键,左键点击它并拖到事件图表中,将”PerceivedActor“连到”target Actor“。”PerceivedActor“是之前在事件中定义的变量,我们获取了事件和感知系统提供的Actor,然后将”PerceivedActor“赋值给它,最后,复制上面这三个节点 “Get Controller”和“Cast to AIC ThirdPerson Character”和“update has line if sight key”,它们用于获取“update has line of sight key“函数,将他们连接到“Update Target Actor Key”。注意,分支的这个部分用于定义Actor刚刚被感知系统被感知到时的状态。这里要把“has line of sight“设置为真,勾选函数中的复选框。

让我们快速回顾一下做了那些修改。可以看到,这个“on target perception updated“事件为AI定义了三种不同状态。第一种状态,Actor被感知时,这个状态定义了AI看到Actor时的情况。第二种结果,返回值为”假“的结果,定义了看不到Actor时的状态。即使看不到,我们仍在黑板中保留了被感知Actor的值,这种状态表示AI记得看到了某个对象,只是当前看不到了。最后是”target lost“事件,它会在对象消失5秒后触发,这种状态表示AI当前看不到,当前感知的Actor并且对它丧失了兴趣。值得一提的是,我们之所以设置黑板键,就是为了提供信息,并通过黑板键将信息提供给行为,它不做任何决策,这由行为树决定。

下面我们在行为树中把所有这些修改内容拼合起来。我们将借助新的黑板键和装饰器,让AI有能力决定是追逐玩家还是继续随机漫游。首先,在内容浏览器中打开行为树资源“BT_EnemyAI“,我们将使用当前保存在黑板中的信息,在两个序列中二选一。删除第一个序列,拖动根节点,在菜单中选择”选择器“,把选择器连至现在的”随机漫游“序列。随机漫游序列的优先级比我们创建的序列要低。在行为树中执行顺序是从左到右。通过刚刚创建的选择器新建一个序列,在细节面板中的”描述“分段中,将节点名称改为”chase player“,拖动”chase player“序列,选择”move to task“,我们需要将AI移到目标Actor的位置,为此,在右侧细节面板中的”黑板“分段点击”黑板键“,在下拉菜单中选择”Target Actor“。”Target Actor“是我们创建的用于和函数一起更新的黑板键。接着,再次拖动追逐玩家序列,在”move to“节点的右侧新建一个节点,选择”Wait“节点,在细节面板的”等待“分段中,将等待时间五秒改为一秒。通常在任务结束后会添加一些等待任务,因为这能避免行为树在不同序列间快速循环,从而显得不自然。添加这两个序列后,”追逐玩家“序列基本完成了,考虑到行为树的执行顺序,这个新的分支会始终在随机漫游序列之前执行。

接下来,需要使用装饰器控制这个分支的执行方式,只有当前需要设置目标Actor时才执行它。右键点击,”追逐玩家“序列,选择”添加装饰器“>”黑板“。接下来,选中这个新的装饰器,在细节面板中的描述段将节点名称改为”is a target actor set“。我们来看看要使用哪些黑板键,由于我们关心的是目标Actor,所以应该在细节面板中”黑板“分段中,在”黑板键“下拉菜单中选中”SetActor“。接下来我们需要思考的是和键有关的是什么内容。”黑板“分段允许我们定义我们期望的结果。上面的”流程控制“分段允许我们控制观察到期望结果时执行流程会发生什么。”通知观察者“下拉菜单有两个选项,默认选项是”on result change“。每当键查询的结果发生变化时,我们会按照”observer aborts“描述的内容更改执行流程。

UE4蓝图AI角色制作(七)之追逐玩家的更多相关文章

  1. UE4蓝图AI角色制作(四)之Gameplay调试器

    8. 寻路网格体和Gameplay调试器 为了及时识别出AI系统中的导航问题,UE4提供了一个工具用来解决这类问题,它叫Gameplay调试器.打开项目设置,在左侧找到"引擎",然 ...

  2. UE4蓝图AI角色制作(三)

    接上一节 6. 寻路网格体代理 通过允许配置多个"代理",虚幻引擎使得用户能够轻松为大小各异的AI创建寻路网格体.首先,选中世界大纲视图中的"RecastNavMesh& ...

  3. UE4蓝图AI角色制作(六)之行为树

    13.行为树原理 AI最重要的环节就是行为树.我们将解释什么是行为树.为何它如此重要,以及构建行为树需要哪些元素. 借助行为树,我们可以轻松控制并显示AI的决策制定过程.行为树是一种将AI在场景中的决 ...

  4. 【摸鱼向】UE4的AI模块探索手记(1)

    前言 之前实现了自主创作的角色导入进UE4并成功控制其进行一系列动作,但目前的样子距离基本的游戏架构还差了一个很大的模块:NPC,而这部分是由电脑来进行自动控制,所以,我有一句话不知当讲不当讲(对,我 ...

  5. UE4简单AI

    首先做个小小的声明把,由于俺之前也没接触过AI ,所以有一些专业的词汇可能翻译存在各种问题,如果你发现的话,还是希望能够提出来哦,我们一起进步. 记住配合视频食用更佳哦~ 视频连接:http://ww ...

  6. UE4蓝图编程的第一步

    认识UE4蓝图中颜色与变量类型: UE4中各个颜色对应着不同的变量,连接点和连线的颜色都在表示此处是什么类型的变量.对于初学者来说一开始看到那么多连接点, 可能会很茫然,搞不清还怎么连,如果知道了颜色 ...

  7. UE4的AI学习(2)——官方案例实例分析

    官方给出的AI实例是实现一个跟随着玩家跑的AI,当玩家没有在AI视野里时,它会继续跑到最后看到玩家的地点,等待几秒后如果仍然看不到玩家,则跑回初始地点.官方的案例已经讲得比较详细,对于一些具体的函数调 ...

  8. [UE4]让AI跑起来

    让AI由静止状态变成跑步状态,做法跟玩家角色走路一样. 一.创建1D混合动画 二.在AI角色关联的动画蓝图中使用第一步创建的混合动画

  9. UE4蓝图与C++交互——射击游戏中多武器系统的实现

    回顾   学习UE4已有近2周的时间,跟着数天学院"UE4游戏开发"课程的学习,已经完成了UE4蓝图方面比较基础性的学习.通过UE4蓝图的开发,我实现了类似CS的单人版射击游戏,效 ...

随机推荐

  1. android http get

    Executors.newSingleThreadExecutor().execute{ val uri = "https://www.cnblogs.com/hangj" val ...

  2. JS 根据文件路径获取名字和后缀名

    var fileName = this.from.doc.substring(this.from.doc.lastIndexOf('/')+1); //文件名           var extNam ...

  3. 启动线程组报错:Error occurred starting thread group :test_1, error message:Invalid duration 0 set in Thread Group:test_1, see log file for more details

    线程组基础信息都已经配置好,启动时报错,如下图: 排查原因:勾选了线程组调度器,并未设置参数 解决方案:取消勾选或者设置参数

  4. 算法:实现strStr(),字符串indexOf方法

    描述 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返回  -1. 个人思路: ...

  5. Linux内核中的Workqueue机制分析

    1. 什么是workqueue Linux中的workqueue(工作队列)主要是为了简化在内核创建线程而设计的.通过相应的工作队列接口,可以使开发人员只关心与特定功能相关的处理流程,而不必关心内核线 ...

  6. ClickOnce手动更新

    if (ApplicationDeployment.IsNetworkDeployed == true)             {                 ApplicationDeploy ...

  7. JavaScript循环 — for、for/in、while、do/while

    for 多次遍历代码块 const array = []for (var i = 0; i < 5; i++) { array.push(i)}console.log(array) // [0, ...

  8. HDU2094产生冠军 (拓扑排序)

    HDU2094产生冠军 Description 有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛. 球赛的规则如下: 如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认 ...

  9. java设计模式,工厂,代理模式等

    javaEE设计模式: 工厂模式:主要分为三种模式: 定义:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行. 为什么要使用工厂模式: (1) 解耦 : ...

  10. .Net Core with 微服务 - 分布式事务 - 可靠消息最终一致性

    前面我们讲了分布式事务的2PC.3PC , TCC 的原理.这些事务其实都在尽力的模拟数据库的事务,我们可以简单的认为他们是一个同步行的事务.特别是 2PC,3PC 他们完全利用数据库的事务能力,在一 ...