28. UE5 RPG同步面板属性(四)

在前面几篇中,我们实现了以下步骤:

  1. 首先我们需要通过c++去实现创建GameplayTag,这样可以在c++和UE里同时获取到Tag
  2. 创建一个DataAsset类,用于设置tag对应的属性和显示内容
  3. 创建AttributeMenuWidgetController实现对应逻辑

上面几步在前几篇文章中,我们都基本实现了,只有AttributeMenuWidgetController对应的逻辑没有实现。

在这一篇里面,我们将实现对应的逻辑,实现对UI数据的同步。

测试委托

在将所有的数据同步之前,我们先创建一个属性进行同步,来测试数据是否能够成功传递。首先,我们先拿力量属性测试。
首先我们从FMyGameplayTags单例里面获取力量的属性标签,然后通过标签获取到DataAsset里面的数据结构体,然后从AS里面获取到力量值,设置给结构体,并广播出去。

	const FGameplayTag& Tag = FMyGameplayTags::Get().Attributes_Primary_Strength;
	FMyAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Tag);
	Info.AttributeValue = AS->GetStrength();
	AttributeInfoDelegate.Broadcast(Info);

这样,结构体内就保存了需要UI显示的初始数据,并且,我们将整个结构体广播了出去。
我们接着在WBP_TextValueRow蓝图里面,增加委托监听,将会返回一个结构体,可以从结构体内获取到四项内容。
在这里插入图片描述
然后我们通过结构体拿到数据,设置UI即可,后面的设置显示名称和数字,直接封装成了函数
在这里插入图片描述
在这里插入图片描述
接着运行项目,打开属性面板,会发现所有属性都换成了对应的名称
在这里插入图片描述
我们需要一个方法去判断是否需要更改,因为现在这种方式只要触发回调就会更新,我们可以为Widget增加一个Tag变量,可以单独去设置对应的变量值
在这里插入图片描述
在委托回调这里,判断标签是否相同,只有是我们设置的相同的标签的情况下,才会更新
在这里插入图片描述
将属性面板的名称修改掉,方便查看
在这里插入图片描述
对每个Widget的属性单独去修改
在这里插入图片描述
接着运行,就会发现,我们设置的那一项才更新了信息。
在这里插入图片描述
我们要将所有的属性都广播出去,我们可以一个个写下去,如下这样,但是这样重复代码多,代码量增加,不好维护,所以我们需要一种新的方式去实现。

void UAttributeMenuWidgetController::BroadcastInitialValues()
{
	const UAttributeSetBase* AS = Cast<UAttributeSetBase>(AttributeSet);

	check(AttributeInfo);

	FMyAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(FMyGameplayTags::Get().Attributes_Primary_Strength);
	Info.AttributeValue = AS->GetStrength();
	AttributeInfoDelegate.Broadcast(Info);

	Info = AttributeInfo->FindAttributeInfoForTag(FMyGameplayTags::Get().Attributes_Primary_Intelligence);
	Info.AttributeValue = AS->GetIntelligence();
	AttributeInfoDelegate.Broadcast(Info);
}

接下来,我们将使用Map并实现对其的遍历实现修改。
在AttributeSetBase.h文件里面增加一个委托宏DECLARE_DELEGATE_RetVal ,这个委托宏和之前的区别是它有返回值。

DECLARE_DELEGATE_RetVal(FGameplayAttribute, FAttributeSignature);

接着,我们给AS添加一个变量属性,类型为Map,key为Tag标签,Value为对应的委托

TMap<FGameplayTag, FAttributeSignature> TagsToAttributes;

在AS的构造函数中,我们创建有返回的委托需要绑定一个函数才可以后续返回对应的值绑定静态函数可以使用BindStatic(),如果非静态函数需要设置成员地址比如BindUObject(this, &MyClass::MyFunction),然后将委托添加到Map中,这里我们先添加两个用于测试。

UAttributeSetBase::UAttributeSetBase()
{
	const FMyGameplayTags& GameplayTags = FMyGameplayTags::Get();

	FAttributeSignature StrengthDelegate;
	StrengthDelegate.BindStatic(GetStrengthAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength, StrengthDelegate);

	FAttributeSignature IntelligenceDelegate;
	IntelligenceDelegate.BindStatic(GetIntelligenceAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Intelligence, IntelligenceDelegate);
}

接着回到AttributeMenuController里面,在controller里面,我们将之前写的代码替换掉,修改为使用对Map的遍历实现对属性值的广播。
首先获取到Key,Map的Key就是属性对应的Tag,通过Tag去获取DataAsset里面存储的属性数据,然后通过value获取到属性,通过属性的GetNumericValue(AS)方法获取到对应值,再将这个属性信息结构体广播出去。

	for (auto& Pair : AS->TagsToAttributes)
	{
		FMyAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
		FGameplayAttribute Attr = Pair.Value.Execute();
		Info.AttributeValue = Attr.GetNumericValue(AS);
		AttributeInfoDelegate.Broadcast(Info);
	}

编译打开UE,查看属性面板
在这里插入图片描述
委托的方式是一种安全的方式,相对来说,创建的委托数量也比较多,我们还有一种相对比较简单的方式。首先我写一个例子
(*attr)代表我们声明了变量名称,前面加星代表我们声明的是函数指针,第二个空()代表这个函数使用时不需要传入参数

	FGameplayAttribute (*attr)();
	attr = GetIntelligenceAttribute;// 隐式转换,函数名被解释为函数指针

	float attv = attr().GetNumericValue(this);

我们将Map的Value类型修改为FGameplayAttribute(*)()

TMap<FGameplayTag, FGameplayAttribute(*)()> TagsToAttributes;

这样,代码就可以优化成,只需要在map添加属性Tag和对应的获取属性的函数即可。

	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength, GetStrengthAttribute);
	TagsToAttributes.Add(GameplayTags.Attributes_Primary_Intelligence, GetIntelligenceAttribute);

在AttributeMenuWidgetController里面,只需要修改成调用函数,即可返回属性对象,然后调用GetNumericValue获取数值设置即可。

	for (auto& Pair : AS->TagsToAttributes)
	{
		FMyAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
		Info.AttributeValue = Pair.Value().GetNumericValue(AS);
		AttributeInfoDelegate.Broadcast(Info);
	}

在这里插入图片描述
接着实现数值变化时,修改属性,在BindCallbacksToDependencies函数内,我们还是需要遍历Map,使用ASC的GetGameplayAttributeValueChangeDelegate监听属性的变化,并绑定匿名函数,注意中括号传入的参数,内部无法获取到外部的地址,需要中括号作为接口传入

void UAttributeMenuWidgetController::BindCallbacksToDependencies()
{
	const UAttributeSetBase* AS = Cast<UAttributeSetBase>(AttributeSet);

	for (auto& Pair : AS->TagsToAttributes)
	{
		AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Pair.Value()).AddLambda(
			[this,Pair,AS](const FOnAttributeChangeData& Data)
			{
				FMyAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
				Info.AttributeValue = Pair.Value().GetNumericValue(AS);
				AttributeInfoDelegate.Broadcast(Info);
			}
		);
	}
}

接着运行项目,看看修改Primary 属性,Secondary属性会不会跟着变化,打开面板
在这里插入图片描述
护甲值和护甲穿透为
在这里插入图片描述

我们之前创建的碰撞盒子会修改它的韧性 +10,当韧性变为32时,护甲值和护甲穿透也跟着增长了。
在这里插入图片描述
大家需要多测试,查看是否有问题。

接下来,再做一个小优化,在初始化数值和绑定委托函数里,有相同的逻辑,我们可以把它抽离出来作为一个新的函数去调用。
在这里插入图片描述
在这里插入图片描述
创建一个私有函数,用于实现上面的功能

private:

	void BroadcastAttributeInfo(const FGameplayTag& AttributeTag, const FGameplayAttribute& Attribute) const;

实现之前的逻辑,主要就是修改一下变量

void UAttributeMenuWidgetController::BroadcastAttributeInfo(const FGameplayTag& AttributeTag, const FGameplayAttribute& Attribute) const
{
	FMyAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(AttributeTag);
	Info.AttributeValue = Attribute.GetNumericValue(AttributeSet);
	AttributeInfoDelegate.Broadcast(Info);
}

接下来就是将上面的逻辑替换为函数即可,记得去ue里面测试功能。

AttibuteMenuWidgetController.h

// 版权归暮志未晚所有。

#pragma once

#include "CoreMinimal.h"
#include "UI/WidgetController/MyWidgetController.h"
#include "AttributeMenuWidgetController.generated.h"

class UAttributeInfo;
struct FMyAttributeInfo;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAttibuteInfoSignature, const FMyAttributeInfo&, Info);

/**
 * 
 */
UCLASS(BlueprintType, Blueprintable)
class AURA_API UAttributeMenuWidgetController : public UMyWidgetController
{
	GENERATED_BODY()

public:

	virtual void BindCallbacksToDependencies() override;
	virtual void BroadcastInitialValues() override;

	UPROPERTY(BlueprintAssignable, Category="GAS|Attributes")
	FAttibuteInfoSignature AttributeInfoDelegate;

protected:

	UPROPERTY(EditDefaultsOnly)
	TObjectPtr<UAttributeInfo> AttributeInfo;

private:

	void BroadcastAttributeInfo(const FGameplayTag& AttributeTag, const FGameplayAttribute& Attribute) const;
};

AttibuteMenuWidgetController.cpp

// 版权归暮志未晚所有。


#include "UI/WidgetController/AttributeMenuWidgetController.h"

#include "MyGameplayTags.h"
#include "AbilitySystem/AttributeSetBase.h"
#include "AbilitySystem/Data/AttributeInfo.h"

void UAttributeMenuWidgetController::BindCallbacksToDependencies()
{
	const UAttributeSetBase* AS = Cast<UAttributeSetBase>(AttributeSet);
	check(AttributeInfo);

	for (auto& Pair : AS->TagsToAttributes)
	{
		AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Pair.Value()).AddLambda(
			[this,Pair](const FOnAttributeChangeData& Data)
			{
				BroadcastAttributeInfo(Pair.Key, Pair.Value());
			}
		);
	}
}

void UAttributeMenuWidgetController::BroadcastInitialValues()
{
	const UAttributeSetBase* AS = Cast<UAttributeSetBase>(AttributeSet);
	check(AttributeInfo);

	for (auto& Pair : AS->TagsToAttributes)
	{
		BroadcastAttributeInfo(Pair.Key, Pair.Value());
	}
}

void UAttributeMenuWidgetController::BroadcastAttributeInfo(const FGameplayTag& AttributeTag, const FGameplayAttribute& Attribute) const
{
	FMyAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(AttributeTag);
	Info.AttributeValue = Attribute.GetNumericValue(AttributeSet);
	AttributeInfoDelegate.Broadcast(Info);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL数据库下,使页面传入的数据与保存的数据编码一致

一、查询当前MySQL数据库的编码 &#xff08;1&#xff09;登录MySQL数据库&#xff08;Windows系统&#xff09;&#xff1a;winR打开命令终端&#xff0c;cd到MySQL的bin目录&#xff0c;输入mysql -u root -p&#xff0c;回车后输入登录密码 &#xff08;2&#xff09;查看…

【C++】C++入门第一课(c++关键字 | 命名空间 | c++输入输出 | 缺省参数)

目录 前言 C关键字 命名空间 1.命名空间的定义 A.标准命名空间定义 B.命名空间允许嵌套定义 C.同名命名空间的合并 2.命名空间的使用 加命名空间名称及作用限定符 使用using将命名空间中某个成员引入 使用using namespace命名空间名称引入 C的输入和输出 缺省参数…

C++类基础5——拷贝构造函数,拷贝赋值运算符(复制构造函数,复制赋值运算符)

拷贝控制操作 当定义一个类时&#xff0c;我们显式地或隐式地指定在此类望的对象拷贝&#xff0c;移动、赋值和销毁时做什么。 一个类通定义五种特殊的成员函数来控制这些操作&#xff0c;包括&#xff1a;拷贝构造函数(copy consinuctor)、拷贝赋值运算符(copy-assignment op…

如何修复开机但不显示任何内容的计算机?这里提供详细步骤

前言​ 计算机“无法开机”的最常见方式是PC实际开机但在显示器上不显示任何内容。你看到电脑机箱上的灯,可能看到里面的风扇在转,甚至可能听到声音,但屏幕上什么也没有显示,请按照我们提供的顺序尝试以下常见修复方法。 测试显示器 在对计算机的其余部分进行更复杂和耗时…

Mac 下安装maven教程

note&#xff1a;网上已经有很多该类型教程了&#xff0c;这边自身保留一份&#xff0c;方便后面使用&#xff1b; 一、安装地址&#xff1a;官网 二、安装步骤 $ tar -xvf apache-maven-3.3.9-bin.tar.gz //mac支持手动点击解压 $ sudo mv -f apache-maven-3.3.9 /usr…

C语言函数递归调用

在C语言中&#xff0c;函数可以直接或间接地调用自身&#xff0c;这种函数调用自身的过程称为递归调用。递归是一种强大的编程技巧&#xff0c;能够简化程序结构、提高代码的可读性和可维护性。本文将介绍C语言函数递归调用的原理、应用场景以及注意事项。 以下是我整理的关于…

HANA中的内存及磁盘使用统计

1. 引言 在实际使用中&#xff0c;通过HANA的admin控制台&#xff0c;确实可以得到很多重要的信息。但有的时候不如人愿&#xff0c;你需要提供相应的SQL语句得到具体的信息。 比如&#xff0c;我要得到所有的行表的内存及磁盘占用信息&#xff1b;我需要得到所有列表的内存及…

[WebGL] 实例化绘制性能测试

实例化绘制&#xff08; Instanced Drawing &#xff09;是 OpenGL / WebGL 等图形 API 中常用的性能优化技术&#xff0c;它适用于同样的模型绘制次数非常多的场景&#xff0c;能够有效的降低显存占用和图形 API 接口调用的次数&#xff0c;达到性能提升的效果。以前我只知道怎…

蓝桥杯 java 承压计算

题目: 思路&#xff1a; 1&#xff1a;其中的数字代表金属块的重量(计量单位较大) 说明每个数字后面不一定有多少个0 2&#xff1a;假设每块原料的重量都十分精确地平均落在下方的两个金属块上&#xff0c;最后&#xff0c;所有的金属块的重量都严格精确地平分落在最底层的电子…

QT 二维坐标系显示坐标点及点与点的连线-通过定时器自动添加随机数据点

QT 二维坐标系显示坐标点及点与点的连线-通过定时器自动添加随机数据点 功能介绍头文件C文件运行过程 功能介绍 上面的代码实现了一个简单的 Qt 应用程序&#xff0c;其功能包括&#xff1a; 创建一个 MainWindow 类&#xff0c;继承自 QMainWindow&#xff0c;作为应用程序的…

物联网学习1、什么是 MQTT?

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级、基于发布-订阅模式的消息传输协议&#xff0c;适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎&#xff0c;能够实现传感器、执行器和其它设备之间的高效通…

FLASH的读取与写入

FLASH的写入 结合HAL库所给参数&#xff1a; 查阅具体使用芯片的参考手册。 就不在详细解释&#xff0c;英文自行翻译。具体代码如下&#xff1a; /*FLASH写入程序*/ void WriteFlashTest(uint32_t L, uint32_t addr, uint32_t *Data,int Page) {int i0;/* 1/4解锁FLASH*/HAL…

揭秘五力模型:轻松掌控企业竞争命脉,决策不再迷茫!

五力分析模型又成为波特五力模型是由著名的管理学者迈克尔波特(Michael Porter)在20世纪80年代初提出的一种理论框架&#xff0c;它对企业营销中的战略制定产生了全球性的深远影响。这一模型被广泛应用于企业竞争战略的分析&#xff0c;可以帮助企业有效地分析企业在营销环境中…

python-pytorch获取FashionMNIST实际图片标签数据集

在查看pytorch官方文档的时候&#xff0c;在这里链接中https://pytorch.org/tutorials/beginner/basics/data_tutorial.html的Creating a Custom Dataset for your files章节&#xff0c;有提到要自定义数据集&#xff0c;需要用到实际的图片和标签。 在网上找了半天没找到&a…

蓝海项目!黑科技引爆全网流量小红书拉新,单日暴力收益7000+,小白也能轻松上手【揭秘】

众所周知&#xff0c;自去年以来&#xff0c;图文作品在各大平台如快手和抖音的流量大增&#xff0c;这得益于这些平台与小红书的竞争。目前&#xff0c;小红书也在积极推广&#xff0c;成功推荐新用户下载应用的奖励高达15元&#xff0c;这一数字几乎是其他平台的几倍。此外&a…

【TypeScript】解决字面量类型推断错误的四种方式

解决字面量类型推断错误的四种方式 方式一&#xff1a;对象属性使用类型断言方式二&#xff1a;传参使用类型断言方式三&#xff1a;对象使用类型断言方式四&#xff1a;对象属性使用变量&#xff0c;变量使用字面量类型参考 declare function handleRequest(url: string, meth…

深入理解HDFS工作原理:大数据存储和容错性机制解析

** 引言&#xff1a; ** 在当今数据爆炸的时代&#xff0c;存储和管理大规模数据成为了许多组织面临的重要挑战。为了解决这一挑战&#xff0c;分布式文件系统应运而生。Hadoop分布式文件系统&#xff08;HDFS&#xff09;作为Apache Hadoop生态系统的核心组件之一&#xff…

Java | Leetcode Java题解之第2题两数相加

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode head null, tail null;int carry 0;while (l1 ! null || l2 ! null) {int n1 l1 ! null ? l1.val : 0;int n2 l2 ! null ? l2.val : 0;int sum…

罗永浩直播阿里云服务器ECS u1性能如何?值得买吗?

罗永浩直播卖阿里云服务器&#xff0c;企业专享云服务器ECS通用算力型u1实例是什么&#xff1f;性能如何&#xff1f;目前阿里云服务器ECS u1实例&#xff0c;2核4G&#xff0c;5M固定带宽&#xff0c;80G ESSD Entry盘&#xff0c;优惠价格199元一年&#xff0c;罗永浩今晚直播…

算法学习16:数论03(容斥原理、博弈论)

算法学习16&#xff1a;数论03&#xff08;容斥原理、博弈论&#xff09; 文章目录 算法学习16&#xff1a;数论03&#xff08;容斥原理、博弈论&#xff09;前言一、容斥原理&#xff1a;求多个集合的并集二、博弈论1.Nim游戏&#xff1a;2.集合N-im游戏 总结 前言 提示&#…