56. UE5 RPG 给敌人添加AI实现跟随玩家

在这一篇里,我们要实现一下敌人的AI,敌人也需要一系列的行为,比如朝向英雄攻击,移动,在满足条件时施放技能。这些敌人的行为可以通过使用UE的内置的AI系统去实现。
在UE里,只要是基于Character类创建的蓝图,都能够找到相应的AI配置项
在这里插入图片描述
可以自动控制角色的基类为AIController,配合AIController的还有两个类,分别是行为树(Behavior Tree)用于存储角色的行为逻辑以及用于存储AI使用的数据的黑板(Blackboard Data)。
接下来,我们将一步步创建适合RPG项目的AI系统。

创建AIController

首先基于AIController父类创建一个子类
在这里插入图片描述
命名为RPGAIController
在这里插入图片描述
在代码里使用AI系统,我们还需要在Build.cs里面添加AI模块
在这里插入图片描述
在RPGAIController类里面,我们需要初始化黑板和行为树控件,用于后续控制它们的实例
在AIController类里面,已经定义了黑板的控件
在这里插入图片描述
我们在RPGAIController里面再申明行为树控件

protected:UPROPERTY()TObjectPtr<UBehaviorTreeComponent> BehaviorTreeComponent;

记得设置它的构造函数


public:ARPGAIController();

我们在构造函数里进行初始化这两个控件,为了保证不出错,我们需要进行检查,如果出错会抛出错误。

ARPGAIController::ARPGAIController()
{Blackboard = CreateDefaultSubobject<UBlackboardComponent>("BlackboardComponent");check(Blackboard);BehaviorTreeComponent = CreateDefaultSubobject<UBehaviorTreeComponent>("BehaviorTreeComponent");check(BehaviorTreeComponent);
}

在敌人基类实现应用AIController

我们创建了一个自定义的AIController,我们需要应用到角色身上,才能够起作用,首先,我们在代码里增加角色对AIController的处理逻辑。
在RPGAIController里面,我们创建了黑板和行为树的控件,但是没有数据,我们在角色类上面增加一个参数,用于在蓝图中设置使用的行为树,并增加一个参数用于保存转换为RPGAIController实例后的参数。
所以在EnemyBase类里,增加以下参数

	UPROPERTY(EditAnywhere, Category="AI")TObjectPtr<UBehaviorTree> BehaviorTree;UPROPERTY()TObjectPtr<ARPGAIController> RPGAIController;

然后我们要覆写PossessedBy函数,这个函数之前我们在服务器初始化ASC时用过,它将在Pawn被控制器(PlayerController和AIController都行)控制时触发回调

virtual void PossessedBy(AController* NewController) override;

我们在回调里面,首先将控制器转换为RPGAIController并存储起来,然后从我们设置的角色使用的行为树里获取行为树使用的黑板数据初始化,然后调用运行行为树。
这些操作都需要在服务器上面运行,所有的客户端都复制服务器的结果来保证所有的行为统一。

void AEnemyBase::PossessedBy(AController* NewController)
{Super::PossessedBy(NewController);//当前设置只在服务器端运行if(!HasAuthority()) return;//AIController是在服务器端执行的,所以需要在PossessedBy函数回调中获取服务器返回RPGAIController = Cast<ARPGAIController>(NewController);//初始化行为树上设置的黑板RPGAIController->GetBlackboardComponent()->InitializeBlackboard(*BehaviorTree->BlackboardAsset);//运行行为树RPGAIController->RunBehaviorTree(BehaviorTree);
}

接下来我们编译代码打开UE,创建RPGAIController的蓝图类
在这里插入图片描述
顺便也将后面使用黑板和行为树创建
在这里插入图片描述
黑板推荐以BB_为前缀,行为树推荐以BT_为前缀
在这里插入图片描述
打开敌人的蓝图基类,将我们创建的BP_RPGAIController设置上去
在这里插入图片描述
设置行为树
在这里插入图片描述
打开行为树,在细节这里设置使用的黑板
在这里插入图片描述
在行为树上设置简单播放一个哥布林的动画,查看应用效果是否实现。
在这里插入图片描述
如果能够正常播放动画,证明实现了对应的效果。
在这里插入图片描述

实现行为树服务

对AI行为树不大了解的小伙伴可以查看一下之前我写Unreal Engine 5.1 AI行为树基础入门
我们打开行为树,首先在下面增加一个Selector节点。
elector节点主要用于在多个子树之间进行选择。它从左到右执行其下的子项(即子节点),当其中一个子项执行成功时,整个Selector节点即认为成功,并终止后续的子项执行。如果所有的子项都执行失败,那么Selector节点也失败。
在这里插入图片描述
我们可以在运行状态下查看,它在子项运行成功时直接返回,不再判断后续的子项,而是直接返回到Selector,Selector也作为成功返回。由于我们没有设置其它节点,行为树将重新运行,接着再运行第一项子项
在这里插入图片描述
我们右键Selector还可以看到给节点附加装饰器和服务的内容,它们的含义分别是:

  1. 装饰器节点用于控制是否应该执行一个节点。它们可以用来检查某些条件,如是否看到了玩家,或者是否在特定距离内。这些节点可以修改节点的行为,比如限制运行次数或添加延迟。在行为树中,它们通常被连接到任务节点或服务节点,用于在这些节点执行之前或之后添加额外的逻辑或条件判断。
  2. 服务节点不执行实际的行为,而是定期运行,用于设置和维护黑板(Blackboard)上的数据。黑板是一个用于存储AI状态信息的区域,可以被行为树中的其他节点访问和修改。服务节点通常连接到合成节点或任务节点,只要连接的节点被执行,它们就会以定义的频率执行。
    在这里插入图片描述
    为了能够实现对敌人目标的获取,我们下面实现一个自定义的服务类。
    这里我们创建一个新的类,基于BTService_BluePrintBase,这样,我们创建的类,也可以通过蓝图创建使用
    在这里插入图片描述
    我们将其命名为BTService_FindNearestPlayer,用于查找最近的玩家,在后续实现对其的攻击。
    在这里插入图片描述
    打开代码,我们先看一下父类上能够获取的内容,我们发现可以直接从父类获取AIController和AIController控制的Actor
    在这里插入图片描述
    在代码里,我们首先覆写父类的函数,TickNode,这个函数会在一定的时间后重复执行,用于更新数据使用。
protected:virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;

首先在代码里测试是能够获取到那两个参数的值

void UBTService_FindNearestPlayer::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);GEngine->AddOnScreenDebugMessage(1, 1.f, FColor::Red, *AIOwner->GetName());GEngine->AddOnScreenDebugMessage(2, 1.f, FColor::Green, *ActorOwner->GetName());
}

接着编译打开UE,创建一个基于自定义服务类的蓝图
在这里插入图片描述
打开蓝图,左侧我们可以覆写函数,不覆写无法触发对应的函数
在这里插入图片描述
类默认值这里,我们可以设置节点名称,方便在行为树里使用,服务这里为触发Tick事件的时间间隔,可以作为优化的性能点。
在这里插入图片描述
打开行为树,右键可以发现我们创建的两个类,一个是c++类另一个是蓝图类
在这里插入图片描述
选择蓝图类,会发现它会附着到节点上,并显示我们设置的节点名称
在这里插入图片描述
你现在直接运行会发现没有对应的打印,所以我们需要在服务里覆写Tick,来实现行为树对Tick的调用,你会发现接收Tick有两种,一个是普通版,还有一个AI专用的,这里我们覆写AI的
在这里插入图片描述
不需要执行任何操作,直接编译
在这里插入图片描述
运行这样会发现左上角的打印,我们发现两个打印的都是AIController,这代表它的AIController所有者和Actor所有者都是AIController
在这里插入图片描述
接着我们在蓝图中打印可以获取的数据
在这里插入图片描述
可以获取对应的AIController 控制的Pawn 以及更新时间间隔
在这里插入图片描述

在黑板添加属性

到现在了,我们还没使用黑板。黑板是一个比喻,相当于以前上学时候的黑板,而每个同学相当于一个行为树的节点,它们可以实现从黑板获取数据,也可以修改数据,黑板是节点和节点之间交互数据的一个渠道。
设置黑板属性你需要先设置它的类型
在这里插入图片描述
然后再选择它的基类
在这里插入图片描述
如果将实例已同步选中,那么,所有角色从黑板当前值获取的结果都是一样的。
在这里插入图片描述
我们在原有的基础上增加两个属性一个是需要攻击的目标,另一个是和目标的距离
在这里插入图片描述

我们在黑板上设置了属性以后,如何对其填充数据呢,在服务蓝图中,我们创建变量类型需要设置为黑板键选择器
在这里插入图片描述
并且要将右边的眼睛打开
在这里插入图片描述
回到行为树中,你可以选择当前属性需要绑定的黑板属性
在这里插入图片描述
在服务蓝图中,获取属性的值,你需要通过函数Get来获取对应的类型的值
在这里插入图片描述
如果你需要设置,你需要调用对应的Set方法
在这里插入图片描述
比如下面就是将控制的Pawn作为SelfActor设置
在这里插入图片描述

实现获取需要跟随的玩家

上面我们在蓝图中实现了对黑板属性的获取以及设置,这个我们也可以在C++中设置。但是获取到需要跟随的角色如果在蓝图中实现性能消耗比在c++中实现消耗大,所以,我们将在c++中实现对角色的获取。
打开服务类,我们创建两个参数用于记录需要跟随的玩家以及距离

	UPROPERTY(BlueprintReadOnly, EditAnywhere)FBlackboardKeySelector TargetToFollowSelector;UPROPERTY(BlueprintReadOnly, EditAnywhere)FBlackboardKeySelector DistanceToTargetSelector;

在Tick中,我们首先获取到AIController控制的Pawn

APawn* OwningPawn = AIOwner->GetPawn();

然后根据角色设置设置的标签来获取角色敌人是谁,这个标签不是GameplayTag而是FName类型的

const FName TargetTag = OwningPawn->ActorHasTag(FName("Player")) ? FName("Enemy") : FName("Player");

这个标签的设置你需要在蓝图中,找到Actor的配置项,填写即可,可以填写多个进行分类,这有助于提升性能。分别设置好英雄和敌人的标签。
在这里插入图片描述
这样,我们就可以去获取目标标签在场景的所有实例

	TArray<AActor*> ActorsWithTag;UGameplayStatics::GetAllActorsWithTag(OwningPawn, TargetTag, ActorsWithTag);

接下来我们就要遍历获取的实力,比对它们和OwningPawn之间的距离,来获取最短距离的目标。这里我们首先将默认距离设置为浮点数最大值,然后遍历获取每个和OwningPawn之间的距离和距离变量比大小,如果两个角色之间的距离比变量的距离小,证明又发现了一个距离更近的角色,将距离和角色都存储下来。遍历完成后,我们获取到的距离和角色将是当前最小的那个

	//遍历所有的角色获取到最近的角色和距离float ClosestDistance = TNumericLimits<float>::Max(); //默认设置float最大值AActor* ClosestActor = nullptr;for(AActor* Actor : ActorsWithTag){const float Distance = OwningPawn->GetDistanceTo(Actor);if(Distance < ClosestDistance){ClosestDistance = Distance;ClosestActor = Actor;}}

然后我们调用内置方法去设置黑板属性,它们封装在UBTFunctionLibrary内

	//设置黑板数据UBTFunctionLibrary::SetBlackboardValueAsObject(this, TargetToFollowSelector, ClosestActor);UBTFunctionLibrary::SetBlackboardValueAsFloat(this, DistanceToTargetSelector, ClosestDistance);

实现跟随角色

我们编译代码打开UE,在行为树中,绑定对应的属性
在这里插入图片描述
运行你会发现它们被正确赋值
在这里插入图片描述
然后在下面增加一个MoveTo节点
在这里插入图片描述
右侧修改黑板键位TargetToFollow
在这里插入图片描述
运行起来你会发现都会追你
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓绕过限制直接使用Android/data无需授权,支持安卓14(部分)

大家都知道&#xff0c;安卓每次更新都会给权限划分的更细、收的更紧。   早在安卓11的时候还可以直接通过授权Android/data来实现操作其他软件的目录&#xff0c;没有之前安卓11授权的图了&#xff0c;反正都长一个样&#xff0c;就直接贴新图了。   后面到了安卓12~13的…

信息系统项目管理师0128:输出(8项目整合管理—8.6管理项目知识—8.6.3输出)

点击查看专栏目录 文章目录 8.6.3 输出 8.6.3 输出 经验教训登记册 经验教训登记册可以包含执行情况的类别和详细的描述&#xff0c;还可包括与执行情况相关的影响、建议和行动方案。经验教训登记册可以记录遇到的挑战、问题、意识到的风险和机会以及其他适用的内容。经验教训…

Debezium+Kafka:Oracle 11g 数据实时同步至 DolphinDB 解决方案

随着越来越多用户使用 DolphinDB&#xff0c;各式各样的应用场景对 DolphinDB 的数据接入提出了不同的要求。部分用户需要将 Oracle 11g 的数据实时同步到 DolphinDB 中来&#xff0c;以满足在 DolphinDB 中实时使用数据的需求。本篇教程将介绍使用 Debezium 来实时捕获和发布 …

npm介绍、常用命令详解以及什么是全局目录

目录 npm介绍、常用命令详解以及什么是全局目录一、介绍npm的主要功能npm仓库npm的配置npm的版本控制 二、命令1. npm init: 初始化一个新的Node.js项目&#xff0c;创建package.json文件。package.json是一个描述项目信息和依赖关系的文件。2. npm install <package_name&g…

LeetCode算法题:42. 接雨水(Java)

题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3…

基于vue3速学angular

因为工作原因&#xff0c;需要接手新的项目&#xff0c;新的项目是angular框架的&#xff0c;自学下和vue3的区别&#xff0c;写篇博客记录下&#xff1a; 参考&#xff1a;https://zhuanlan.zhihu.com/p/546843290?utm_id0 1.结构上&#xff1a; vue3:一个vue文件&#xff…

python:pycharm虚拟解释器报错环境位置目录为空

目录 解释器分控制台解释器 和 pycharm解释器 控制台解释器切换&#xff1a; pycharm解释器 解释器分控制台解释器 和 pycharm解释器 控制台解释器切换&#xff1a; 切换到解释器下 激活解释器 查看解释器 where python 激活成功 这时在控制台使用python xxx.py 可以…

​​​【收录 Hello 算法】10.1 二分查找

目录 10.1 二分查找 10.1.1 区间表示方法 10.1.2 优点与局限性 10.1 二分查找 二分查找&#xff08;binary search&#xff09;是一种基于分治策略的高效搜索算法。它利用数据的有序性&#xff0c;每轮缩小一半搜索范围&#xff0c;直至找到目标元素或搜索区间为空…

​​​【收录 Hello 算法】第 10 章 搜索

目录 第 10 章 搜索 本章内容 第 10 章 搜索 搜索是一场未知的冒险&#xff0c;我们或许需要走遍神秘空间的每个角落&#xff0c;又或许可以快速锁定目标。 在这场寻觅之旅中&#xff0c;每一次探索都可能得到一个未曾料想的答案。 本章内容 10.1 二分查找10.2 二…

恶劣天候激光雷达点云模拟方法论文整理

恶劣天候点云模拟方法论文整理 模拟雨天点云&#xff1a;【AAAI2024】模拟雪天点云&#xff1a;【CVPR 2022 oral】模拟雾天点云&#xff1a;【ICCV2021】模拟点云恶劣天候的散射现象&#xff1a;【Arxiv 2021】模拟积水地面的水花飞溅点云&#xff1a;【RAL2022】 模拟雨天点云…

蓝桥杯Web开发【模拟题三】15届

1.创意广告牌 在"绮幻山谷"的历史和"梦幻海湾"的繁华交汇之处&#xff0c;一块创意广告牌傲然矗立。它以木质纹理的背景勾勒出古朴氛围&#xff0c;上方倾斜的牌子写着"绮幻山谷的风吹到了梦幻海湾"&#xff0c;瞬间串联了过去与现在&#xff0…

EPIC免费领取《骑士精神2》 IGN9分神作骑士精神2限时免费领

EPIC免费领取《骑士精神2》 IGN9分神作骑士精神2限时免费领 最近Epic一直为玩家们送出各种游戏&#xff0c;从《龙腾世纪审判》到《模拟农场22》&#xff0c;而就在今天&#xff0c;epic又为玩家们送出了IGN评分9分高分的骑士精神2.这款游戏&#xff0c;该游戏是一款由Tripwir…

vue连接mqtt实现收发消息组件超级详细

基本概念&#xff1a; MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种基于发布/订阅模式的轻量级消息传输协议&#xff0c;专为低带宽、高延迟或不稳定的网络环境设计。以下是MQTT实现收发消息的基本原理&#xff1a; 客户端-服务器模型&#xff1a…

数据量较小的表是否有必要添加索引问题分析

目录 前言一、分析前准备1.1、准备测试表和数据1.2、插入测试数据1.3、测试环境说明 二、具体业务分析2.1、单次查询耗时分析2.2、无索引并发查询服务器CPU占用率分析2.3、添加索引并发查询服务器CPU占用率分析 三、总结 前言 在一次节日活动我们系统访问量到达了平时的两倍&am…

【小沐学GIS】GDAL库安装和使用(C++、Python)

文章目录 1、简介2、下载和编译&#xff08;C&#xff09;2.1 二进制构建2.1.1 Conda2.1.2 Vcpkg 2.2 源代码构建2.2.1 nmake.opt方式构建2.2.2 generate_vcxproj.bat方式构建 2.3 命令行测试2.3.1 获取S57海图数据 2.4 代码测试2.4.1 读取tiff信息 3、Python3.1 安装3.2 测试3…

零基础入门篇④ 初识Python(注释、编码规范、关键字...)

Python从入门到精通系列专栏面向零基础以及需要进阶的读者倾心打造,9.9元订阅即可享受付费专栏权益,一个专栏带你吃透Python,专栏分为零基础入门篇、模块篇、网络爬虫篇、Web开发篇、办公自动化篇、数据分析篇…学习不断,持续更新,火热订阅中🔥专栏订阅地址 👉Python从…

C语言 | Leetcode C语言题解之第110题平衡二叉树

题目&#xff1a; 题解&#xff1a; int height(struct TreeNode* root) {if (root NULL) {return 0;}int leftHeight height(root->left);int rightHeight height(root->right);if (leftHeight -1 || rightHeight -1 || fabs(leftHeight - rightHeight) > 1) {…

Android硬件渲染环境初始化

Android硬件渲染环境初始化 一.硬件加速渲染的开启1.ThreadedRenderer的初始化2.RenderProxy的创建 二.RenderProxy中组件的初始化1.RenderThread的创建2.CanvasContext的创建3.DrawFrameTask的初始化 三.RenderThread的启动1.RenderThread中组件的初始化2.RenderThread中任务的…

arXiv AI 综述列表(2024.05.20~2024.05.24)

公众号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 每周末更新&#xff0c;完整版进群获取。 Q 群在群文件&#xff0c;VX 群每周末更新。 目录 1. Beyond Traditional Single Object Tracking: A …

基于yolov2深度学习网络的昆虫检测算法matlab仿真,并输出昆虫数量和大小判决

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022A 3.部分核心程序 .......................................................... for i 1:12 % 遍历结…