13. UE5 RPG限制Attribute的值的范围以及生成结构体

前面几章,我们实现了通过GameplayEffect对Attribute值的修改,比如血量和蓝量,我们都是有一个最大血量和最大蓝量去限制它的最大值,而且血量和蓝量最小值不会小于零。之前我们是没有实现相关限制的,接下来,我们需要在AttributeSet函数里面实现一下对实际值的范围限制。

实现

首先覆盖父类函数,在PreAttributeChange()函数,这个函数会在AttributeSet里的监听的值发生改变前触发回调

virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;

回调有返回两个参数,一个是Attribute,我们可以通过此值判断哪个属性被修改掉了,另一个是将要修改成的值,接下来,我们打印一下值,看一下结果。

	if(Attribute == GetHealthAttribute()){UE_LOG(LogTemp, Warning, TEXT("Health: %f"), NewValue);}if(Attribute == GetMaxHealthAttribute()){UE_LOG(LogTemp, Warning, TEXT("MaxHealth: %f"), NewValue);}if(Attribute == GetManaAttribute()){UE_LOG(LogTemp, Warning, TEXT("Mana: %f"), NewValue);}if(Attribute == GetMaxManaAttribute()){UE_LOG(LogTemp, Warning, TEXT("MaxMana: %f"), NewValue);}

编译打开UE,点击场景左下角的输出日志
在这里插入图片描述
选择停靠在布局中
在这里插入图片描述
然后让角色去吃药瓶,水晶,以及去踩火堆,看看属性变化,我们会发现所有属性变化,都能够如实的反应在打印上面
在这里插入图片描述
接着使用clamp函数将血量和蓝量数值限制在0到最大血量和蓝量的范围内

NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());

运行UE,再查看,发现数值都被限制在了范围内
在这里插入图片描述

PostGameplayEffectExecute

PostGameplayEffectExecute()函数是在数值变化后触发的,一般只会在Instant类型的GameplayEffect才可以触发(Duration和Infinite类的GameplayEffect如果设置Period也可以触发)。
这个函数的应用场景很多,我们可以做一些逻辑操作,比如死亡,无敌不扣血等等。
使用它我们需要先覆盖父类

virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

它只有一个返回参数就是Data,但是Data里面包含的内容很多

	if(Data.EvaluatedData.Attribute == GetHealthAttribute()){UE_LOG(LogTemp, Warning, TEXT("Health: %f"), GetHealth());UE_LOG(LogTemp, Warning, TEXT("Magnitude: %f"), Data.EvaluatedData.Magnitude);}

打开UE可以查看到,当前的血量,以及这次Effect造成的伤害数值。
在这里插入图片描述
我们打一个断点
在这里插入图片描述
可以看到Data里面有三项数据
在这里插入图片描述
EffectSpec就是效果的实例里面包含很多的数据,我们可以通过它获取到时哪个Actor将此GE应用到目标身上的
EvaluatedData就是修改的数据相关的内容,当前值,修改了多少值,修改的什么属性等等
Target就是目标的ASC
在这里插入图片描述
接下来,我们将从Data中获取到需要的然后封装成一个结构体,方便后续使用。

首先创建一个FEffectProperties的结构体,用于存储施放GE的相关对象和目标的相关对象。这个结构体,将GE的上下文,并将施放者和目标的ASC AvatarActor Controller Character都保存了下来

USTRUCT()
struct FEffectProperties
{GENERATED_BODY()FEffectProperties(){}FGameplayEffectContextHandle EffectContextHandle;UPROPERTY()UAbilitySystemComponent* SourceASC = nullptr;UPROPERTY()AActor* SourceAvatarActor = nullptr;UPROPERTY()AController* SourceController = nullptr;UPROPERTY()ACharacter* SourceCharacter = nullptr;UPROPERTY()UAbilitySystemComponent* TargetASC = nullptr;UPROPERTY()AActor* TargetAvatarActor = nullptr;UPROPERTY()AController* TargetController = nullptr;UPROPERTY()ACharacter* TargetCharacter = nullptr;
};

接下来,创建一个私有函数,我们在这个函数里面去处理生成结构体属性的值。函数接收两个值,一个是PostGameplayEffectExecute()函数返回的Data,另一个是需要填充的结构体。

static void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props);

接着,实现函数,在函数内设置属性,前面将了,可以通过Data获取到相关的属性

void UAttributeSetBase::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props)
{//Source 效果的所有者   Target 效果应用的目标Props.EffectContextHandle = Data.EffectSpec.GetContext();Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent(); //获取效果所有者的ASC//获取效果所有者的相关对象if(IsValid(Props.SourceASC) && Props.SourceASC->AbilityActorInfo.IsValid() && Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid()){Props.SourceAvatarActor = Props.SourceASC->AbilityActorInfo->AvatarActor.Get(); //获取ActorProps.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get(); //获取PlayerControllerif(Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr){if(const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor)){Props.SourceController = Pawn->GetController();}}if(Props.SourceController){Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());}}if(Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid()){Props.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();Props.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();Props.TargetCharacter = Cast<ACharacter>(Props.TargetAvatarActor);Props.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Props.TargetAvatarActor);}
}

接着,只需要在PostGameplayEffectExecute()内创建一个结构体,并调用函数生成内容即可。

void UAttributeSetBase::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{Super::PostGameplayEffectExecute(Data);FEffectProperties Props;SetEffectProperties(Data, Props);}

在使用时,我们就可以通过结构体去获取相应的内容,逻辑更加整洁
在这里插入图片描述

源代码

AttributeSetBase.h

// 版权归暮志未晚所有。#pragma once#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "AttributeSetBase.generated.h"// Uses macros from AttributeSet.h
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)USTRUCT()
struct FEffectProperties
{GENERATED_BODY()FEffectProperties(){}FGameplayEffectContextHandle EffectContextHandle;UPROPERTY()UAbilitySystemComponent* SourceASC = nullptr;UPROPERTY()AActor* SourceAvatarActor = nullptr;UPROPERTY()AController* SourceController = nullptr;UPROPERTY()ACharacter* SourceCharacter = nullptr;UPROPERTY()UAbilitySystemComponent* TargetASC = nullptr;UPROPERTY()AActor* TargetAvatarActor = nullptr;UPROPERTY()AController* TargetController = nullptr;UPROPERTY()ACharacter* TargetCharacter = nullptr;
};/*** 技能系统属性集*/
UCLASS()
class AURA_API UAttributeSetBase : public UAttributeSet
{GENERATED_BODY()public:UAttributeSetBase();virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_Health, Category="Vital Attributes")FGameplayAttributeData Health;ATTRIBUTE_ACCESSORS(UAttributeSetBase, Health);UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_MaxHealth, Category="Vital Attributes")FGameplayAttributeData MaxHealth;ATTRIBUTE_ACCESSORS(UAttributeSetBase, MaxHealth);UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_Mana, Category="Vital Attributes")FGameplayAttributeData Mana;ATTRIBUTE_ACCESSORS(UAttributeSetBase, Mana);UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_MaxMana, Category="Vital Attributes")FGameplayAttributeData MaxMana;ATTRIBUTE_ACCESSORS(UAttributeSetBase, MaxMana);UFUNCTION()void OnRep_Health(const FGameplayAttributeData& OldHealth) const;UFUNCTION()void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const;UFUNCTION()void OnRep_Mana(const FGameplayAttributeData& OldMana) const;UFUNCTION()void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const;private:static void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props);
};

AttributeSetBase.cpp

// 版权归暮志未晚所有。#include "AbilitySystem/AttributeSetBase.h"#include "AbilitySystemBlueprintLibrary.h"
#include "GameplayEffectExtension.h"
#include "GameFramework/Character.h"
#include "Net/UnrealNetwork.h"UAttributeSetBase::UAttributeSetBase()
{InitHealth(30.f);InitMaxHealth(100.f);InitMana(30.f);InitMaxMana(100.f);
}void UAttributeSetBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, Health, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, MaxHealth, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, Mana, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, MaxMana, COND_None, REPNOTIFY_Always);
}void UAttributeSetBase::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{Super::PreAttributeChange(Attribute, NewValue);if(Attribute == GetHealthAttribute()){NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());// UE_LOG(LogTemp, Warning, TEXT("Health: %f"), NewValue);}if(Attribute == GetManaAttribute()){NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());}
}void UAttributeSetBase::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props)
{//Source 效果的所有者   Target 效果应用的目标Props.EffectContextHandle = Data.EffectSpec.GetContext();Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent(); //获取效果所有者的ASC//获取效果所有者的相关对象if(IsValid(Props.SourceASC) && Props.SourceASC->AbilityActorInfo.IsValid() && Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid()){Props.SourceAvatarActor = Props.SourceASC->AbilityActorInfo->AvatarActor.Get(); //获取ActorProps.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get(); //获取PlayerControllerif(Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr){if(const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor)){Props.SourceController = Pawn->GetController();}}if(Props.SourceController){Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());}}if(Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid()){Props.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();Props.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();Props.TargetCharacter = Cast<ACharacter>(Props.TargetAvatarActor);Props.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Props.TargetAvatarActor);}
}void UAttributeSetBase::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{Super::PostGameplayEffectExecute(Data);FEffectProperties Props;SetEffectProperties(Data, Props);
}void UAttributeSetBase::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, Health, OldHealth);
}void UAttributeSetBase::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const
{GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMaxHealth);
}void UAttributeSetBase::OnRep_Mana(const FGameplayAttributeData& OldMana) const
{GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMana);
}void UAttributeSetBase::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const
{GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMaxMana);
}

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

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

相关文章

React实例之完善布局菜单(一)

今天我们来用所学的知识来做一个布局菜单的组件, 针对这个组件我之前写过一个教程 React之布局菜单-CSDN博客&#xff0c;那个呢比较基础&#xff0c;这节课算是对那个教程的一个扩展和补充。这个实例讲完&#xff0c;这个系列就算告一段落了。先看效果 这个教程要求对React知识…

猫头虎分享已解决Bug ‍ || TypeError: Object of type ‘int64‘ is not JSON serializable

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

redis特点

一、redis线程模型有哪些&#xff0c;单线程为什么快&#xff1f; 1、IO模型维度的特征 IO模型使用了多路复用器&#xff0c;在linux系统中使用的是EPOLL 类似netty的BOSS,WORKER使用一个EventLoopGroup(threads1) 单线程的Reactor模型&#xff0c;每次循环取socket中的命令…

一篇文章理解时间复杂度和空间复杂度

今天也是很开心的学到了数据结构&#xff0c;也是打算把我自己对知识的理解给写出来了。第一篇数据结构开始咯。开始之前我们先理解一个概念。 什么是算法效率&#xff1f; 算法效率是指算法执行的速度或完成任务所需的资源&#xff08;如时间和空间&#xff09;的度量。它通…

字节3面真题,LeetCode上hard难度,极具启发性题解

文章目录 &#x1f680;前言&#x1f680;LeetCode&#xff1a;41. 缺失的第一个正整数&#x1f680;思路&#x1f680;整个代码思路串一下&#x1f680;Code &#x1f680;前言 铁子们好啊&#xff01;阿辉来讲道题&#xff0c;这道题据说是23年字节3面真题&#xff0c;LeetC…

jmeter的简单使用

1、打开jmeter 打开Jmeter 安装包&#xff0c;进入\bin 中&#xff0c;找到“ApacheJMeter.jar”或"jmeter.bat", 双击打开即可 2、建立线程组 如下图所示&#xff0c;右击TestPlan&#xff0c;点击ADD->Threads(Users)->ThreadGroup 线程组页面分析&#xf…

数字图像处理实验记录六(图像的傅里叶变换和频域处理)

前言&#xff1a; 一、基础知识 1&#xff0c;傅里叶变换是什么 傅里叶变换是一种线性积分变换&#xff0c;通俗来说&#xff0c;通过傅里叶变换就是把一段信号分解成若干个简谐波。 二、实验要求 1&#xff0e;产生一幅如图所示亮块图像f(x,y)&#xff08;256256 大小、…

【npm】修改npm全局安装包的位置路径

问题 全局安装的默认安装路径为&#xff1a;C:\Users\admin\AppData\Roaming\npm&#xff0c;缓存路径为&#xff1a;C:\Users\admin\AppData\Roaming\npm_cache&#xff08;其中admin为自己的用户名&#xff09;。 由于默认的安装路径在C盘&#xff0c;太浪费C盘内存啦&#…

网络协议与攻击模拟_15FTP协议

了解FTP协议 在Windows操作系统上使用serv-U软件搭建FTP服务 分析FTP流量 一、FTP协议 1、FTP概念 FTP&#xff08;文件传输协议&#xff09;由两部分组成&#xff1a;客户端/服务端&#xff08;C/S架构&#xff09; 应用场景&#xff1a;企业内部存放公司文件、开发网站时利…

[ChatGPT们】ChatGPT 如何辅助编程初探

主页&#xff1a;元存储的博客 全文 9000 字&#xff0c; 原创请勿转载。 我没有写过诗&#xff0c;但有人说我的代码像诗一样优雅 -- 雷军 图片来源&#xff1a;https://www.bilibili.com/video/BV1zL411X7oS/ 1. 引言 作为一个程序员&#xff0c;我们不仅要熟悉各种编程语…

C语言实现memcpy、memmove库函数

目录 引言一、库函数介绍二、库函数详解三、源码实现1.memcpy源码实现2.memmove源码实现 四、测试1.memcpy函数2.memmove函数 五、源码1.memcpy源码2.memmove源码 六、参考文献 引言 关于memcpy和memmove这两个函数&#xff0c;不论是算法竞赛还是找工作面试笔试&#xff0c;对…

百卓Smart管理平台 uploadfile.php 文件上传漏洞【CVE-2024-0939】

百卓Smart管理平台 uploadfile.php 文件上传漏洞【CVE-2024-0939】 一、 产品简介二、 漏洞概述三、 影响范围四、 复现环境五、 漏洞复现手动复现小龙验证Goby验证 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工…

vue3集成bpmn

文章目录 前言一、依赖二、汉化配置1.引入文件2.样式文件 总结 前言 vue3 集成bpmn 配置工作流 一、依赖 "bpmn-js": "^7.3.1", "bpmn-js-properties-panel": "^0.37.2", "bpmn-moddle": "^6.0.0", "camu…

【学网攻】 第(23)节 -- PPP协议

系列文章目录 目录 系列文章目录 文章目录 前言 一、PPP协议是什么&#xff1f; 二、实验 1.引入 实验目的 实验背景你是某公司的网络管理员&#xff0c;现在需要与另一个公司进行通信,需要你配置PPP协议保证双方发送的人是真正的而非黑客 技术原理 实验步骤新建Pack…

专业排版设计软件:QuarkXPress 2024 for mac中文激活版

QuarkXPress 2024 for Mac是一款功能强大、易于使用、高质量输出的专业排版软件。无论您是出版业的专家还是初学者&#xff0c;都可以通过QuarkXPress 2024轻松创建出令人惊叹的出版物。 软件下载&#xff1a;QuarkXPress 2024 for mac中文激活版下载 QuarkXPress 2023 for Mac…

牛客网SQL264:查询每个日期新用户的次日留存率

官网链接&#xff1a; 牛客每个人最近的登录日期(五)_牛客题霸_牛客网牛客每天有很多人登录&#xff0c;请你统计一下牛客每个日期新用户的次日留存率。 有一个登录(login。题目来自【牛客题霸】https://www.nowcoder.com/practice/ea0c56cd700344b590182aad03cc61b8?tpId82 …

前后端数据校验

前端校验内容 前端开发中的必要校验&#xff0c;可以保证用户输入的数据的准确性、合法性和安全性。同时&#xff0c;这些校验也有助于提供良好的用户体验和防止不必要的错误提交到后端。 1、必填字段校验&#xff1a; 对于必填的字段&#xff0c;需确保用户输入了有效的数据…

双非本科准备秋招(19.2)—— 设计模式之保护式暂停

一、wait & notify wait能让线程进入waiting状态&#xff0c;这时候就需要比较一下和sleep的区别了。 sleep vs wait 1) sleep 是 Thread 方法&#xff0c;而 wait 是 Object 的方法 2) sleep 不需要强制和 synchronized 配合使用&#xff0c;但 wait 强制和 s…

Javaweb之SpringBootWeb案例之登录校验功能的详细解析

2. 登录校验 2.1 问题分析 我们已经完成了基础登录功能的开发与测试&#xff0c;在我们登录成功后就可以进入到后台管理系统中进行数据的操作。 但是当我们在浏览器中新的页面上输入地址&#xff1a;http://localhost:9528/#/system/dept&#xff0c;发现没有登录仍然可以进…

【PowerShell】修改Windows网络配置的常用命令

PowerShell&#xff08;PS&#xff09;是一种强大的任务自动化和管理框架&#xff0c;具有丰富的命令和语法&#xff0c;可以用于编写脚本来管理Windows操作系统和其他应用程序。它的开放式架构和跨平台支持使得它成为一个灵活和可扩展的工具。 在网络配置方面&#xff0c;Powe…