45. UE5 RPG 使用元属性(Meta Attributes)以及使用Set by Caller修改伤害

2024-05-03 08:36

本文主要是介绍45. UE5 RPG 使用元属性(Meta Attributes)以及使用Set by Caller修改伤害,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在RPG游戏中,我们是不会直接修改生命值的属性,是因为在修改角色属性时,需要获取角色的属性并进行复杂的计算,所以,我们正常情况下使用元属性(Meta Attributes)作为计算的中间的媒。在服务器上先将属性计算到元属性上面,然后再通过元属性的数值去修改实际属性。
那元属性和普通的属性有什么区别?
普通的Gameplay Attribute:它是经常被复制的,在服务器上面修改,然后复制到每个客户端上面。
元属性:它不会被复制,只做为一个临时缓冲占位符,只在服务器上面计算,然后使用元属性修改实际需求修改的属性,这样就可以避免每个端需要复杂的计算。
比如,我们将实现一个名为IncomingDamage的元属性,然后在属性集里的PostGameplayEffectExecute获取角色属性(是否被格挡,减伤等等)来计算出对角色造成的最终伤害,然后将最终伤害去修改角色的血量值,而这个值再复制给客户端,将大大减少计算量。
所以,这些计算伤害的元属性将有传入的GE去计算,然后属性集去执行所需的计算,并播放对应的效果(比如显示不同颜色的伤害数字)并对目标应用buff(如果有)。

接下来,我们将从一个简单的版本开始实现,然后逐渐让功能符合游戏需求。

创建元属性

在这里插入图片描述
在测试使用了GE里面,我们是直接修改了血量值,我们需要创建一个元属性作为中间媒介。
首先,我们需要先在属性集(AttributeAet)里添加一个属性,用于作为临时占位符使用。原属性不需要赋值,所以不需要赋值函数,但是属性对应的宏还是需要的生成获取和设置的函数使用。

	UPROPERTY(BlueprintReadOnly, Category="Meta Attributes")FGameplayAttributeData IncomingDamage; //处理传入的伤害ATTRIBUTE_ACCESSORS(UAttributeSetBase, IncomingDamage);

接下来,在PostGameplayEffectExecute函数里面,查看修改的是否为元属性

if(Data.EvaluatedData.Attribute == GetIncomingDamageAttribute())

然后我们获取到元属性的值备用,并将属性集上的值设置为0,等待下一次设置。

const float LocalIncomingDamage = GetIncomingDamage();
SetIncomingDamage(0.f);

接下来,判断值是否大于0,如果大于0则传入了伤害

if(LocalIncomingDamage > 0.f)

然后,我们先实现最基础的修改血量,作为基础模板,并且还判断角色是否存活,条件就是血量不为0则为存活,这样基础测试代码就实现了。

	if(Data.EvaluatedData.Attribute == GetIncomingDamageAttribute()){const float LocalIncomingDamage = GetIncomingDamage();SetIncomingDamage(0.f);if(LocalIncomingDamage > 0.f){const float NewHealth = GetHealth() - LocalIncomingDamage;SetHealth(FMath::Clamp(NewHealth, 0.f, GetMaxHealth()));const bool bFatal = NewHealth <= 0.f; //血量小于等于0时,角色将会死亡}}

编译代码,打开UE,在GE里面修改的为IncomingDamage,并设置为25
在这里插入图片描述
就可以运行测试效果
在这里插入图片描述

使用Set by Caller来实现伤害数值的传递

制作到这里,朋友们会有疑问,我们实现GE里面的伤害都是通过固定的数值来造成的伤害,但是如果我们需要通过角色的属性计算呢,该如何实现?
这就需要将属性值修改的Set by Caller去实现
在这里插入图片描述
接下来我们将一步步实现这个。
要使用这种方式去设置,我们需要使用一个标签作为Key,在我们之前c++里添加一个标签

FGameplayTag Damage; //伤害 标签

然后初始化,添加到标签管理器,并缓存下来变量

	GameplayTags.Damage = UGameplayTagsManager::Get().AddNativeGameplayTag(FName("Damage"),FString("伤害标签"));

创建完成这个,我们需要在之前的火球术技能类里面,在生成GESpec时,使用标签设置。
首先获取到标签的单例

const FMyGameplayTags GameplayTags = FMyGameplayTags::Get(); //获取标签单例

然后使用函数库的方法设置,这里有两种方式,一种是FName,另一种是使用标签,对应在GE上获取的两种,由于Name类型容易写错,所以个人推荐使用标签。最后的值则是我们需要对目标造成的伤害,这里方便测试,我们直接写了固定数值,如果这个数值能够起作用,证明我们接下来可以在代码里面计算当前技能造成的伤害。

//UAbilitySystemBlueprintLibrary::AssignSetByCallerMagnitude() //使用DataName设置
UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(SpecHandle, GameplayTags.Damage, 50.f);

然后编译代码,打开GE,将修改数值类型设置为Set by Caller,并在下面设置Tag为Damage,这样,GE将从标签获取对应的数值
在这里插入图片描述

在技能上通过技能等级设置伤害

我们实现了通过代码里面去设置技能造成的伤害,接下来,我们将实现增加配置项在技能上实现对伤害的设置,并且还使用到了曲线表格去编辑伤害。
首先我们在技能基类上面添加一个属性,虽然不是所有的属性都会用到,但是它占用的内存不大,所以我们直接写到基类,需要就用。

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Damage")FScalableFloat Damage;

编译代码打开UE,可以查看到属性面板
在这里插入图片描述
所以,我们需要设置它的曲线表格来实现通过等级设置技能伤害,首先创建一个JSON文件,用来设置属性
在这里插入图片描述
然后导入到UE,生成曲线表格
在这里插入图片描述
设置为曲线表格
在这里插入图片描述
然后可以稍微修改一下表格,让曲线更陡一些
在这里插入图片描述
然后将属性缩放设置为1,选择我们创建的表格,然后设置好使用哪一行
在这里插入图片描述
有了表格以后,我们就需要实现如何通过属性获取到数值。如果你需要获取到整数类型的,我们可以通过Damage.AsInteger(GetAbilityLevel())来获取从表格转换的整数数值。
这里我们使用Damage.GetValueAtLevel获取浮点数来设置,并且将数值打印到窗口

//创建一个GE的实例,并设置给投射物
const UAbilitySystemComponent* SourceASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetAvatarActorFromActorInfo());
const FGameplayEffectSpecHandle SpecHandle = SourceASC->MakeOutgoingSpec(DamageEffectClass, GetAbilityLevel(), SourceASC->MakeEffectContext());const FMyGameplayTags GameplayTags = FMyGameplayTags::Get(); //获取标签单例
const float ScaledDamage = Damage.GetValueAtLevel(GetAbilityLevel()); //根据等级获取技能伤害
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, FString::Printf(TEXT("火球术伤害:%f"), ScaledDamage));
//UAbilitySystemBlueprintLibrary::AssignSetByCallerMagnitude() //使用DataName设置
UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(SpecHandle, GameplayTags.Damage, ScaledDamage);Projectile->DamageEffectHandle = SpecHandle;

编译并运行项目测试
在技能等级没有修改时,值为5,没问题
在这里插入图片描述
由于我们现在还没有实现设置技能等级,所以这里在代码里修改查看20级的数值,是否为我们设置的伤害值

const float ScaledDamage = Damage.GetValueAtLevel(GetAbilityLevel() + 19);

查看效果,没问题
在这里插入图片描述

这篇关于45. UE5 RPG 使用元属性(Meta Attributes)以及使用Set by Caller修改伤害的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/956306

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

sky-take-out项目中Redis的使用示例详解

《sky-take-out项目中Redis的使用示例详解》SpringCache是Spring的缓存抽象层,通过注解简化缓存管理,支持Redis等提供者,适用于方法结果缓存、更新和删除操作,但无法实现... 目录Spring Cache主要特性核心注解1.@Cacheable2.@CachePut3.@Ca