前言

之前实现了自主创作的角色导入进UE4并成功控制其进行一系列动作,但目前的样子距离基本的游戏架构还差了一个很大的模块:NPC,而这部分是由电脑来进行自动控制,所以,我有一句话不知当讲不当讲(对,我又不满足了( •̀ ω •́ )✧)。由此,我又一次打开了官方文档,开始对UE4中比较难啃的AI模块进行探索。(前方少图,请放心加载(笑))

正文

一.构成

先说一下UE4中AI的构成,一般如果是对玩家有威胁的敌人角色或者是跟随玩家的npc角色,它们的配置一般有:1.行为树;2.黑板;3.AI控制器;4.AI角色;5.相关服务;6.相关修饰器;7.相关任务。本次以类似于《合金装备》里敌兵的AI构建为例,对各个配置进行说明与个人见解。

1.行为树

UE4的AI角色核心,属于决策层配置,大致样貌如下:



如果你有一些程序设计基础,那么大致通过名字就能判断行为树是由类似于if—else一类的决策组成的AI行动方案。并且行为树是一种可以进行类似深度优先遍历操作的数据结构,即比如在某个子树的行为已经运行完成后,状态改变,则此时根据改变的条件选择需要遍历的子树接着进行遍历与运行操作。而组成行为树的节点可并不是类似于普通树状结构中单一仅含有权重的“小圆圈”,行为树一般由以下几种节点组成:Root,Composites和Tasks。接下来分别描述一下三种节点:

a.Root节点

又名根节点,是整个行为树的核心与基础,一但当Agent在场景中的实例化被调用时,那么,Root就是行为树的调用入口,从此处开始AI行为逻辑。由于其固定的性质,所以Root节点不可进行编程。

b.Composites节点

直译过来是“复合体”,根据其节点的作用,又分为Sequence,Selector和Simple Parallel(此节点暂不做叙述),其中,Sequence(队列)是为了让其下的子节点或子树按照顺序标号的顺序进行执行的节点,而Selector则是行为树中最重要的“选择单元”,通过某些“特殊”的“玩意儿”实现对于状态(一般是用整型,浮点,或枚举表示状态)的判断,从而选择相关的子树。与Root同样含有固定的性质,所以不可编程。

c.Tasks节点

又名任务节点,即上述的“相关任务”,是相同的东西,这里具体记载着Agent的行为,当遍历执行到这里时,Agent便会做出行动,比如跑,跳等。由于AI的行为依据具体情况决定,所以在引擎默认创建的几个Tasks节点之外,开发者还可以编写新的Tasks节点,即Tasks节点是可编程的(行为树插图中紫色的部分)。

2.黑板

黑板是用来存储一系列Agent状态变量的一种结构体,比如此时Agent发现了玩家并且向玩家跑过来,所以它此时的状态至少就应该有这么几个:玩家此时的位置,Agent的移动类型(Idle或者Running)以及玩家最后一次出现的位置,这些东西都要用变量存储起来。然而各个任务节点与一系列的服务,修饰器之间是毫无联系且相互独立的,所以他们之间并不能直接修改对方的数据,这时候就要通过黑板里面的数据作为接口实现整个系统之间的通信。并且实际上这些数据并没有保存在黑板里面,黑板只是提供了一种定义方式,行为树会自行创建一个黑板,将所有数据存储在那里面,只是行为树创建的黑板会遵从原黑板的数据格式罢了。真不知道Epic官方是怎么起名的,叫“记忆体”或“数据坞”这种高大上狂拽酷炫屌炸天的名字它不香么?(或许Epic有这种想法的合理性吧,咱对人工智能的基础理论知之甚少,如果有哪位大佬知道,欢迎补充)

3.AI控制器与AI角色

这便是AI在游戏场景中的实例化,也是最终展现给玩家的样貌。由控制器控制角色进行相应的动作,由行为树作为多触手章鱼玩家来操作多个控制器从而控制多个角色。

4.服务

开发人员以及玩家们都希望在做出一系列的举止后(比如制造噪声,向敌人扔个小黄书等),Agent可以根据这种举止做出相应行动,即遵守图灵机的基本定义“输入一定的数据——处理数据——输出相应的处理结果”。试想,如果不接受玩家的输入从而在场景内乱跑,那岂不就与喵星人的扫地座驾以及辣个女人一样么?



所以,服务就是来干这事的。通常,服务一般用来接收此时场景内的情况输入,比如玩家进入视锥,并且玩家并没有躲在墙体后面,这时服务就会获取这些信息的输入,并且通过逻辑处理从而将黑板中的状态数据进行改变并更新。当然,由于一个Agent的行为在不同的游戏类型中(甚至不同关卡中)会接受多种不同的输入,并且黑板上的数据也并不是一定相同的,所以,服务完完全全是可编程的(行为树插图中青色的部分)。

5.修饰器

好的,这时候我们已经获取了环境的信息并改变了Agent的状态,如果我们希望Agent根据此时的状态做出相应的行为,那么就需要Selector进行选择。然而,如何让Selector进行选择,总不能随机选一个?如果是这样,那么Selector以及Agent的状态便毫无意义所以,这便是“那个玩意儿”——修饰器的作用:作为执行其负责的子树部分的判定条件,也就是if—else结构中括号里填写的那个条件,即定义的条件满足后再运行相应子树,若不满足则退回上一节点。一般都使用基于参考黑板数据的修饰器。当然,判定条件也有可能与关卡状态,玩家状态甚至是你的电脑状态等黑板中并没有存储的数据相关,所以,修饰器也是可编程的。(行为树插图中蓝色的部分)

二.联系

接下来以我最喜欢的PS2游戏之一《合金装备2:自由之子》(我绝对不是因为可以在厕所里看海报而喜欢的)其中一个场景进行说明(请结合行为树插图食用更佳),具体场景如下所示:



此时玩家操纵的蛇叔处在A点,他要前往的B点(rush B)附近有敌兵看守,此敌兵假如说就是我们描写的Agent,并且在相应的黑板中创建了这样几个变量State(Agent的状态,枚举类型:Idle,Combat,Searching),Player(准确的说是Agent前往的地点),PlayerMarker(玩家在Agent可视范围消失后最后一次出现的位置);这时,Agent在场景中实例化,所以,引擎会调用Agent所使用的行为树的Root节点,此时行为树开始工作。首先这时Agent面向墙壁,而在行为树中的EnemyTrial_SearchVision服务为Agent正方向创造了一个110度(角度)的视锥,此时玩家并没有在视锥范围内,所以EnemyTrial_SearchVision服务将此时Agent的State设置为Idle,目标前往地点与玩家最后一次的位置设置为空。接下来进行选择,Selector会通过自己所有分支中的修饰器进行选择,既然此时状态为Idle,那么State equal Idle修饰器符合条件,所以接下来执行此修饰器下的子树,然后此时Agent的行为由EnemyTrial_SetWalkSpeed(设置此时Agent的行走速度:巡逻速度)以及EnemyTrial_MoveToRandomPoint(让Agent随机移动到某点)定义并控制Agent执行。在执行的过程中,服务以及修饰器也没闲着,一旦此时Agent随机移动的点在A点附近,Agent需要转身,而此时玩家操作的蛇叔正好探头与Agent对上了眼(进入视锥)。那么,服务会立即改变此时Agent的State为Combat,而且将Player与PlayerMarker设置为此时玩家的位置,修饰器监视到State改变,所以会立即中断自身的行为,并将进度立即返还到Selector,然后由Selector分配给State equal Combat,接着执行Combat对应的Agent行为。但是,如果此时蛇叔打开了光学迷彩(这是不可能的,因为从桥上跳下来时已经摔坏了),在视锥中消失,这时服务将Player设置为空,并会检索黑板中的PlayerMarker,如果PlayerMarker非空,则Agent的Selector将进度交给State equal Searching,总不能Agent看不到敌人就放弃搜索吧(山猫:你已经被开除了),如果PlayerMarker为空,那么Agent的Selector会将进度交给State equal Idle(一般这种情况不可能,除非玩家开了修改器)。接着,当Agent到达PlayerMarker后,在其搜索的时间内如果没有在视锥内发现玩家,那么EnemyTrial_DestroyMarker任务便会清空Player与PlayerMarker,并且将State设置为Idle,这时修饰器监测到了State的改变,所以此时又会将进度返还给Selector,再由Selector将进度交给State equal Idle,实行Agent基础的巡逻状态。

结语

又开了一个坑……我也想好好做个游戏啊%&*#@!¥%%#(因言语过激而被踢出直播间),但是基础不足,身边也没有学习美工与音效的小伙伴,只能自己慢慢摸索了,C++也在补STL方面的基础,不过这倒是充足了网课后的课余时间(笑)。如果我的这篇文章里面的相关名词与解释有不正确或是容易引发歧义的地方,欢迎在评论区指出。而且如果你对于其中的一些解释还有不明白的地方,也欢迎骚扰。当然,老规矩,如果你认为这篇文章会对更多的人有帮助,欢迎转载,只不过请注明转载出处即可,以上。どうもありがとうございました!(都莫,阿里嘎多靠萨依玛希大!)

【摸鱼向】UE4的AI模块探索手记(1)的更多相关文章

  1. python爬虫14 | 就这么说吧,如果你不懂python多线程和线程池,那就去河边摸鱼!

    你知道吗? 在我的心里 你是多么的重要 就像 恩 请允许我来一段 freestyle 你们准备好了妹油 你看 这个碗 它又大又圆 就像 这条面 它又长又宽 你们 在这里 看文章 觉得 很开心 就像 我 ...

  2. 删库吧,Bug浪——我们在同一家摸鱼的公司

    那些口口声声, Bug越来越难写人的,应该盯着你们: 像我一样,我盯着你们,满眼恨意. IT积攒了几十年的漏洞, 所有的死机.溢出.404和超时, 像是专门为你们准备的礼物. 圈复杂度.魔鬼变量.内存 ...

  3. 寒武纪加速平台(MLU200系列) 摸鱼指南(二)--- 模型移植-环境搭建

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  4. 寒武纪加速平台(MLU200系列) 摸鱼指南(四)--- 边缘端实例程序分析

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  5. 【摸鱼神器】UI库秒变LowCode工具——列表篇(一)设计与实现

    内容摘要: 需求分析 定义 interface 定义 json 文件 定义列表控件的 props 基于 el-table 封装,实现依赖 json 渲染 实现内置功能:选择行(单选.多选),格式化.锁 ...

  6. 【转】让Chrome化身成为摸鱼神器,利用Chorme运行布卡漫画以及其他安卓APK应用教程

    下周就是十一了,无论是学生党还是工作党,大家的大概都会有点心不在焉,为了让大家更好的心不在焉,更好的在十一前最后一周愉快的摸鱼,今天就写一个如何让Chrome(google浏览器)运行安卓APK应用的 ...

  7. 菜鸡学C语言之摸鱼村村长

    题目描述 摸鱼村要选村长了! 选村长的规则是村里每个人进行一次投票,票数大于人数一半的成为村长. 然鹅摸鱼村的人都比较懒,你能帮他们写一个程序来找出谁当选村长吗? (每名村民的编号都是一个int范围内 ...

  8. [摸鱼]cdq分治 && 学习笔记

    待我玩会游戏整理下思绪(分明是想摸鱼 cdq分治是一种用于降维和处理对不同子区间有贡献的离线分治算法 对于常见的操作查询题目而言,时间总是有序的,而cdq分治则是耗费\(O(logq)\)的代价使动态 ...

  9. HNOI2018 摸鱼记

    HNOI2018 摸鱼记 今天我又来记流水账啦 Day 0 颓废的一天. 我,球爷和杜教在颓膜膜.io ych看起来在搓碧蓝 鬼知道哥达鸭干了什么 学习氛围只局限在机房的一角 后来全体Oier开会,5 ...

随机推荐

  1. 扫码枪读取条形码数据(vue)

    扫码枪是模拟键盘输入的,所有事件为document.onkeypress = function(){}. 在vue项目中,是没有window.onload的,所以在created钩子函数中做: var ...

  2. js随机背景色 并显示色号

    今天重新看了一般原生js教程,看到一个例子 是点击按钮改变背景色. 我就改进了一下 点击按钮换一个颜色 并把色号给显示出来 <!DOCTYPE html><html><h ...

  3. Python进阶学习之面向对象

    目录 面向对象 私有属性 面向对象   python也有面向对象的编程,它与C++中的类有点相似.它也只是运算符重载,继承. class Test: num=0 def __init__(self): ...

  4. Iconfont-阿里巴巴矢量图标库 登录账户是 github自动登录

    Iconfont-阿里巴巴矢量图标库 登录账户是 github自动登录

  5. iview admin template 基础模板架子

    https://github.com/iview/iview-admin/tree/template

  6. 分布式——吞吐量巨强、Hbase的承载者 LSMT

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是分布式系统的第九篇文章. 今天给大家分享的内容是LSM树,它的英文是Log-structed Merge-tree.看着有些发怵,但其 ...

  7. 【Weiss】【第03章】练习3.16:删除相同元素

    [练习3.16] 假设我们有一个基于数组的表A[0,1...N-1],并且我们想删除所有相同的元素. LastPosition初始值为N-1,但应该随着相同元素被删除而变得越来越小. 考虑图3-61中 ...

  8. 安卓App自动化测试环境

    一.appium安装 1.nodejs依赖 2..net framework 3.Appium桌面程序安装 3.1.安装包获取 3.2.安装过程 二.Java_ jdk安装 1.Java_jdk版本说 ...

  9. Java-迭代器(新手)

    //导入的包.import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;//创建的一个类.pub ...

  10. ngzorro draw 第一次打开 ERROR TypeError: Cannot read property 'overlayElement' of undefined

    at NzDrawerComponent.push../node_modules/ng-zorro-antd/fesm5/ng-zorro-antd.js.NzDrawerComponent.trap ...