【UEC++】AI行为树及其相关蓝图部分在C++中的实现

embedded/2025/3/31 11:22:23/

前言

        在UE开发中,AI逻辑的书写是一个极其重要的部分。在本人于UE的学习过程中,认为AI的逻辑主要由以下几个基本的部分构成:AIController、作为AI的Character、BehaviorTree、Blackboard、Tasks、Service以及装饰器。本文也将主要就这几个部分讲述在C++以及蓝图中如何实现、配合,用于总结记录个人的学习过程。

        首先,假定我们的开发目标为:一个AICharacter在未发现玩家时进行随机移动,在发现玩家后朝着玩家奔跑,并当玩家在AICharacter的攻击范围内时进行攻击。

模块

        想要实现以上所述的功能,必须要先添加"AIModule", "GameplayTasks", "NavigationSystem"这三个模块。AIModule是AI逻辑必须要用的,GameplayTasks是实现任务节点需要用的,NavigationSystem是在AI随机寻路的时候需要用的。

AZombie

        我们创建一个继承自Character的类命名为Zombie作为我们的AI角色。在Zombie类中添加UBehaviorTree类型的变量,用作AI需要运行的行为树,并在蓝图中为其赋值。

        同时需要一个攻击的函数,这里我选择使用播放攻击的蒙太奇动画实现攻击。

AZombieAIController

        该类继承自AIController类。

        为了让AI有视觉感知,需要添加感知组件。这里为什么选择在AIController内添加感知组件而不是在Character类中添加,是因为在AIcontroller类的构造函数中直接设置感知组件,避免更多的麻烦。

        然后需要重写父类的OnPossess函数,该函数在AIController成功控制一个Character时触发,因此可在该函数内实现行为树的运行。

        然后是设置是否看到角色,该逻辑由于是与感知组件挂钩,因此选择写在这里。而感知组件的更新是通过动态委托实现的,因此需要在源码内查看委托签名中函数需要的参数,并在函数前加上UFUNCTION的宏标记。函数内的获取黑板组件来通过名称设置黑板中的黑板键,并将感知的对象判断是否为玩家,赋值给Zombie类。

UBTT_FindRandomLocation

        该类继承自UBTTaskNode,也就是任务节点。

        首先需要一个黑板键选择器变量,用于和UE编辑器中的黑板相匹配。并在构造函数中设置其类型,并且必须要实现父类的InitializeFromAsset函数,主要作用是从指定的资产中加载和初始化任务节点的属性、变量和逻辑,确保任务节点在行为树中能够正确执行对黑板键选择器做出处理。

        然后是寻路逻辑,核心是利用K2_GetRandomLocationInNavigableRadius函数,其中的RandomLocation参数是一个用于保存随机位置结果的参数。并把这个结果设置给黑板键选择器,这样就可以在行为树中将数据传给编辑器中的黑板键了,可用于后续移动到该位置的逻辑。后续两个参数分别代表中心位置和半径。

UBTT_FindPlayerLocation

        然后是寻找玩家位置的任务节点,同样继承自UBTTaskNode。

        要想追击玩家,自然需要一个追击目标或者追击位置,那么这里有两个选择:一个是告诉AI一个Location,另一个是告诉AI一个指向目标的指针。第一种,知道目标Location的话,则可以调用MoveTo来到达位置,但是此方法有一个弊端,就是只有在到达Location的时候才会返回成功,所以会出现玩家已经移动但AI还在前往玩家上一个位置的情况。因此,这里我选择直接传一个指向玩家的指针,所以AI需要接触玩家才会返回成功。然后对黑板键的处理和上面同理。

        然后是在任务开始时,将玩家指针传给黑板键。这里我已经在Zombie类中获取了玩家指针,这里只需要拿到就行。

        接下来直接在行为树中调用自带的MoveTo向目标移动,记得将黑板键设置为创建的Player。

UBTS_CheckDistance

        创建一个服务,该类继承自UBTService。

        有了向玩家移动,那么下一步就是向玩家攻击,而攻击就需要有一个范围判定,判定玩家是否进入了攻击距离,这就是这个类的作用。重写父类的TickNode,用于在tick中检测。函数内检测的核心是利用GetDistanceTo,来计算AI与玩家的距离,若小于指定值,则将黑板键bool值设置为对应值。

UBTT_Attack

        该类继承自UBTTaskNode。

        在检测到进入攻击范围后,就需要进行攻击的行为了。攻击主要方式为播放攻击的蒙太奇动画,至于后期想应用伤害可以通过攻击碰撞的回调去做。

行为树

        在C++各类节点写好后就可以搭建行为树了,如图,在所有逻辑的最上层为一个selector,左侧连接随机寻路,右侧链接追击玩家,因此在发现玩家后,由于黑板键的判断 ,即可走右边。同时selector下面为写好的距离判断。

        至此,完成本文的所有目标逻辑。


http://www.ppmy.cn/embedded/176579.html

相关文章

多条件排序(C# and Lua)

C# 升序排序 OrderBy 按升序对序列的元素进行排序 ThenBy 按升序对序列中的元素执行后续排序 降序排序 OrderByDescending 按降序对序列的元素排序 ThenByDescending 按降序对序列中的元素执行后续排序 public class Fruit {public int id;public string name;publi…

区块链驱动金融第十章——走进另类币与加密货币生态系统:比特币之外的广阔天地

在加密货币的领域中,比特币虽然占据着重要地位,但它并非唯一的主角。随着区块链技术的不断发展,各种各样的另类币如雨后春笋般涌现,共同构建了一个丰富多彩且充满活力的加密货币生态系统。让我们深入第十章的内容,去探寻这一生态系统的奥秘。 另类币:比特币的 “挑战者”…

XSS复现漏洞简单前八关靶场

靶场不需要安装任意环境 链接如下:XSS Game - Learning XSS Made Simple! | Created by PwnFunction 目录 XSS Game 第一关:Ma Spaghet! 第二关:Jefff 第三关:Ugandan Knuckles 第四关:Ricardo Milos 第五关&am…

OpenGL ES ->乒乓缓冲,计算只用两个帧缓冲对象(Frame Buffer Object)+叠加多个滤镜作用后的Bitmap

乒乓缓冲核心思想 不使用乒乓缓冲,如果要每个滤镜作用下的绘制内容,也就是这个滤镜作用下的帧缓冲,需要创建一个Frame Buffer Object加上对应的Frame Buffer Object Texture使用乒乓缓冲,只用两个Frame Buffer Object加上对应的F…

Java医疗知识图谱知识库构建(源码)

基于Java、Neo4j和ElasticSearch构建的医疗知识图谱知识库,是一个融合图数据库技术与搜索引擎的智能化医疗知识管理系统。该系统以Neo4j图数据库为核心,利用其高效的图结构存储能力,将疾病、症状、药品、检查项目、科室等医疗实体抽象为节点&…

Leetcode 刷题笔记 图论part05

卡码网 107 寻找存在的路径 初识并查集 并查集功能: 寻找根节点,函数: find(int u),也就是判断这个节点的祖先节点是哪个将两个节点接入到同一个集合,函数: join(int u, int v),将两个节点连在同一个根节点上判断两…

如何在 React 项目中进行服务器端渲染(SSR),它有什么优势

大白话如何在 React 项目中进行服务器端渲染(SSR),它有什么优势 什么是服务器端渲染(SSR) 在传统的 React 项目里,页面的渲染工作是在浏览器里完成的。也就是当你访问一个网页时,浏览器会先下…

LiteratureReading:[2023] GPT-4: Technical Report

文章目录 一、文献简明(zero)二、快速预览(first)1、标题分析2、作者介绍3、引用数4、摘要分析(1)翻译(2)分析 5、总结分析(1)翻译(2)…