当前位置: 首页 > news >正文

57. UE5 RPG 处理AI敌人转向以及拾取物品的问题

在上一篇文章中,我们实现了使用AI行为树控制敌人进行移动,它们可以一直跟随玩家,虽然现在还未实现攻击。但在移动过程中,我发现了有两个问题,第一个是敌人转向的时候很僵硬,可以说是瞬间转向的,这个原因是角色默认是使用控制器切换朝向造成的。第二个问题是敌人现在也可以拾取药瓶喝药,这个不能忍,造成这个原因是因为药瓶是碰撞触发的,没有对拾取的目标进行一个类型区分。
在这一篇中,我们主要将这两个问题解决一下,然后再继续进行敌人的AI行为树的制作。

处理敌人转向问题

敌人的转向问题很好解决,我们之前就处理过角色身上的转向问题,首先就是先将角色身上的使用控制器控制Yaw给关闭。
在蓝图中,我们可以将 使用控制器旋转Yaw 选项关闭
然后开启 将旋转朝向运动 (角色会朝向运动的方向)
在这里插入图片描述
我们将在c++里面设置,将这个配置写死,保证以后所有的敌人都使用这个配置。
打开敌人基类,在 构造函数中增加以下代码,会有同样的效果

	bUseControllerRotationPitch = false;bUseControllerRotationRoll = false;bUseControllerRotationYaw = false;GetCharacterMovement()->bUseControllerDesiredRotation = true;

这样,就完成了对敌人转向问题的处理。

处理敌人可以拾取的问题

接下来我们处理敌人可以拾取药瓶的问题,比如普通药瓶敌人是无法拾取的,但是火堆的那种,可以实现对敌人的应用,我准备在基类上面增加属性去控制。
首先在基类上面增加属性,这里我额外增加了一个控制销毁的属性,我们之前是在蓝图中实现销毁的,现在,我们将此移动到代码中。

	//Instant和Duration的GE在应用后,此物体是否需要被销毁UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")bool bDestroyOnEffectApplication = true;//敌人是否能够拾取此物体UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")bool bApplyEffectsToEnemies = false;

之前我们实现的时候,是在蓝图中实现的,调用代码实现的函数节点,我们也在蓝图中实现应用GE
在这里插入图片描述
接着,我们修改逻辑,实现在应用效果后删除的逻辑,我们将在应用效果后在非无限时间GE后面,判断是否需要在应用后销毁
在这里插入图片描述
然后就是处理是否敌人可拾取的权限,首先我们需要判断当前是否为敌人,然后再判断敌人是否有权限
如果不是敌人 &&后面的逻辑也不会执行,这个判断直接返回false,如果是敌人,并且敌人无法拾取,变量为false,后面也是true,那么将不会执行后面的逻辑。

if(TargetActor->ActorHasTag("Enemy") && !bApplyEffectsToEnemies) return;

我们需要在OnOverlap(触发开始重叠事件)时判断

void ARPGEffectActor::OnOverlap(AActor* TargetActor)
{//如果触发角色类型为敌人,并且此拾取物设置无法被敌人拾取if(TargetActor->ActorHasTag("Enemy") && !bApplyEffectsToEnemies) return;

针对于一些在OnEndOverlap(结束重叠事件)时也会触发,所以,我们也要在结束时判断

void ARPGEffectActor::OnEndOverlap(AActor* TargetActor)
{//如果触发角色类型为敌人,并且此拾取物设置无法被敌人拾取if(TargetActor->ActorHasTag("Enemy") && !bApplyEffectsToEnemies) return;

接着编译打开蓝图,我们这些配置项就可以有效的利用起来了
我们可以选择应用什么类型的GE,并在接触时触发还是结束重叠时触发,以及对于无限时间的GE,可以选择在离开时是否清楚GE的效果
在这里插入图片描述
OnOverlap和OnEndOverlap两个函数没有在函数中调用,我们可以按需调用,比如只需要调用OnOverlap函数,我们在蓝图中调用即可
在这里插入图片描述
如果是需要在触发结束重叠时触发,那么我们需要将OnEndOverlay调用,但是对于那种无限时间的GE,并且还需要在结束时清除掉,我们就需要两个方法都调用
在这里插入图片描述

源码

RPGEffectActor.h

// 版权归暮志未晚所有。#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GameplayEffectTypes.h"
#include "RPGEffectActor.generated.h"struct FActiveGameplayEffectHandle;
class UAbilitySystemComponent;
class UGameplayEffect;//效果应用状态枚举
UENUM(BlueprintType) 
enum class EEffectApplicationPolicy
{ApplyOnOverlap,ApplyOnEndOverlap,DoNotApply
};//效果移除的状态枚举
UENUM(BlueprintType) 
enum class EEffectRemovalPolicy
{RemoveOnEndOverlap,DoNotRemove
};/*** 在场景中可放置的影响角色属性的物件基类*/
UCLASS()
class AURA_API ARPGEffectActor : public AActor
{GENERATED_BODY()public:	ARPGEffectActor();protected:// 游戏开始或生成对象时回调virtual void BeginPlay() override;//给与目标添加GameplayEffect效果UFUNCTION(BlueprintCallable) void ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass);//在重叠开始时处理效果的添加删除逻辑UFUNCTION(BlueprintCallable) void OnOverlap(AActor* TargetActor);//在重叠结束时处理效果的添加删除逻辑UFUNCTION(BlueprintCallable) void OnEndOverlap(AActor* TargetActor);//Instant和Duration的GE在应用后,此物体是否需要被销毁UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")bool bDestroyOnEffectApplication = true;//敌人是否能够拾取此物体UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")bool bApplyEffectsToEnemies = false;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")TSubclassOf<UGameplayEffect> InstantGameplayEffectClass; //生成GameplayEffect的类UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy InstantEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")TSubclassOf<UGameplayEffect> DurationGameplayEffectClass; //生成具有一定持续时间的GameplayEffect的类UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy DurationEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")TSubclassOf<UGameplayEffect> InfinityGameplayEffectClass; //生成具有一定持续时间的GameplayEffect的类UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectApplicationPolicy InfinityEffectApplicationPolicy = EEffectApplicationPolicy::DoNotApply;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")EEffectRemovalPolicy InfinityEffectRemovalPolicy = EEffectRemovalPolicy::RemoveOnEndOverlap;//用于存储当前已经激活的GameplayEffect的句柄的mapTMap<FActiveGameplayEffectHandle, UAbilitySystemComponent*> ActiveEffectHandles;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Apply Effects")float ActorLevel = 1.f;
};

RPGEffectActor.cpp

// 版权归暮志未晚所有。#include "Actor/RPGEffectActor.h"
#include "ActiveGameplayEffectHandle.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"ARPGEffectActor::ARPGEffectActor()
{// 设置当前对象是否每帧调用Tick()PrimaryActorTick.bCanEverTick = false;SetRootComponent(CreateDefaultSubobject<USceneComponent>("SceneRoot"));
}void ARPGEffectActor::BeginPlay()
{Super::BeginPlay();
}void ARPGEffectActor::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{/*** 默认自己编写从actor身上获取ASC的方式* IAbilitySystemInterface* ASCInterface = Cast<IAbilitySystemInterface>(TargetActor); //判断当前actor是否有技能系统接口if(ASCInterface){UAbilitySystemComponent* TargetASC = ASCInterface->GetAbilitySystemComponent(); }*///获取ASCUAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);if(TargetASC == nullptr) return;check(GameplayEffectClass);//创建Effect的句柄 包含了实例化Effect所需数据FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();//设置创建Effect的对象EffectContextHandle.AddSourceObject(this);//Effect的实例化后的句柄,可以通过此来寻找调用const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, ActorLevel, EffectContextHandle);//从句柄中获取到实例的地址,并被应用。const FActiveGameplayEffectHandle ActiveGameplayEffectHandle = TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());//从句柄中获取到定义的对象,并判断设置的const bool bIsInfinite = EffectSpecHandle.Data.Get()->Def.Get()->DurationPolicy == EGameplayEffectDurationType::Infinite;//在是无限时间效果和需要在结束时清除掉时,将效果句柄添加到mapif(bIsInfinite && InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap){ActiveEffectHandles.Add(ActiveGameplayEffectHandle, TargetASC);}else if(bDestroyOnEffectApplication) //如果设置了应用时删除,除了Infinite的都会自动删除{Destroy();}
}void ARPGEffectActor::OnOverlap(AActor* TargetActor)
{//如果触发角色类型为敌人,并且此拾取物设置无法被敌人拾取if(TargetActor->ActorHasTag("Enemy") && !bApplyEffectsToEnemies) return;if(InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);}if(DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);}if(InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnOverlap){ApplyEffectToTarget(TargetActor, InfinityGameplayEffectClass);}
}void ARPGEffectActor::OnEndOverlap(AActor* TargetActor)
{//如果触发角色类型为敌人,并且此拾取物设置无法被敌人拾取if(TargetActor->ActorHasTag("Enemy") && !bApplyEffectsToEnemies) return;//添加效果if(InstantEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, InstantGameplayEffectClass);}if(DurationEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, DurationGameplayEffectClass);}if(InfinityEffectApplicationPolicy == EEffectApplicationPolicy::ApplyOnEndOverlap){ApplyEffectToTarget(TargetActor, InfinityGameplayEffectClass);}//删除效果if(InfinityEffectRemovalPolicy == EEffectRemovalPolicy::RemoveOnEndOverlap){UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);if(!IsValid(TargetASC)) return;//创建存储需要移除的效果句柄存储Key,用于遍历完成后移除效果TArray<FActiveGameplayEffectHandle> HandlesToRemove;//循环map内存的数据for(TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*> HandlePair : ActiveEffectHandles){//判断是否ASC相同if(TargetASC == HandlePair.Value){//通过句柄将效果移除,注意,有可能有多层效果,不能将其它层的效果也移除掉,所以只移除一层TargetASC->RemoveActiveGameplayEffect(HandlePair.Key, 1);//添加到移除列表HandlesToRemove.Add(HandlePair.Key);}}//遍历完成后,在Map中将移除效果的KeyValue删除for(auto& Handle : HandlesToRemove){ActiveEffectHandles.FindAndRemoveChecked(Handle);}}
}

相关文章:

  • 面向对象-----继承
  • 如何使用Matlab进行三角剖分(自定义函数实现delaunayTriangulation 使用Bowyer-Watson 算法)
  • 【Vue3进阶】- Vite 配置
  • C++质数的那些事(判断指数、区间筛质数、互质等等)
  • Linux-文件或目录权限
  • Vue 2 和 Vue 3 中同步和异步
  • Web Server项目实战3-Web服务器简介及HTTP协议
  • GPT‑4o普通账户也可以免费用
  • java中的Map集合
  • 单向无头链表实现
  • 基于transformers框架实践Bert系列4-文本相似度
  • 反射获取或修改对象属性的值
  • SSH反向代理是什麼?有什麼用?
  • 【kubernetes】多 master 高可用集群架构部署
  • 推荐模型IMSR 复现 (有bug 吧基本不下降)
  • Android系统模拟器绘制实现概述
  • C++入门教程(10):for 语句
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • ESLint简单操作
  • input实现文字超出省略号功能
  • Invalidate和postInvalidate的区别
  • Java到底能干嘛?
  • Joomla 2.x, 3.x useful code cheatsheet
  • Mithril.js 入门介绍
  • node入门
  • ReactNativeweexDeviceOne对比
  • 大型网站性能监测、分析与优化常见问题QA
  • 简单数学运算程序(不定期更新)
  • 配置 PM2 实现代码自动发布
  • 前端面试题总结
  • 前端面试总结(at, md)
  • 什么是Javascript函数节流?
  • 学习JavaScript数据结构与算法 — 树
  • 用 Swift 编写面向协议的视图
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​虚拟化系列介绍(十)
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (11)MSP430F5529 定时器B
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (笔试题)分解质因式
  • (附源码)springboot教学评价 毕业设计 641310
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转) Face-Resources
  • (转)setTimeout 和 setInterval 的区别
  • ..回顾17,展望18
  • .NET : 在VS2008中计算代码度量值
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET 使用 XPath 来读写 XML 文件
  • .NET/C# 获取一个正在运行的进程的命令行参数