80. UE5 RPG 实现UI显示技能冷却进度功能

在上一篇文章里,我们实现了通过GE给技能增加资源消耗和技能冷却功能。UI也能够显示角色能够使用的技能的UI,现在还有一个问题,我们希望在技能释放进去冷却时,技能变成灰色,并在技能冷却完成,技能可以再次使用。
为了实现这个功能,我们首先要实现一个能够监听技能进入冷却的方法,然后在技能被使用后,将UI的颜色修改,并在技能冷却完成后,将技能UI恢复到可释放状态。

创建异步任务来监听技能冷却

为了实现能够监听,我们创建一个新的类用来监听技能冷却。
我们创建一个新的c++类,继承至BlueprintAsyncActionBase类
在这里插入图片描述
修改命名,我们将其命名为监听冷却修改
在这里插入图片描述
接下来,我们将实现类,如果不想看实现过程,请略过,实现完成,我会贴上完整的实现代码。

首先我们创建一个委托宏,用于设置委托类型,返回一个参数

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCooldownChangeSignature, float, TimeRemaining);

在类里创建两个委托,用于触发在技能进入冷却时触发,然后在技能冷却时触发

	UPROPERTY(BlueprintAssignable)FCooldownChangeSignature CooldownStart; //冷却触发开始委托UPROPERTY(BlueprintAssignable)FCooldownChangeSignature CooldownEnd; //冷却结束委托

然后创建两个保护性的变量参数,用于实例类时,存储ASC和需要监听的冷却标签

protected:UPROPERTY()TObjectPtr<UAbilitySystemComponent> ASC;FGameplayTag CooldownTag; //记录监听的冷却标签

接着我们创建一个实例函数,用于创建类的实例设置meta=(BlueprintInternalUseOnly=“true”)为了防止开发mod或者玩家能够使用到此函数。

	UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true"))static UListenCooldownChange* ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayTag& CooldownTag);

然后增加一个函数,用于结束任务,防止内存泄露

	UFUNCTION(BlueprintCallable)void EndTask();

在创建实例函数中,我们首先实例化类,并将参数设置上去

UListenCooldownChange* UListenCooldownChange::ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayTag& InCooldownTag)
{UListenCooldownChange* ListenCooldownChange = NewObject<UListenCooldownChange>();ListenCooldownChange->ASC = AbilitySystemComponent;ListenCooldownChange->CooldownTag = InCooldownTag;

然后判断传入的两个参数是否存在,如果未存在,将结束此任务

	//如果参数有一项未设置,我们将结束此任务if(!IsValid(AbilitySystemComponent) || !InCooldownTag.IsValid()){ListenCooldownChange->EndTask();return nullptr;}

我们接下来增加两个回调函数,用于实现对技能冷却的开始和结束的广播

	//监听冷却标签回调函数void CooldownTagChanged(const FGameplayTag InCooldownTag, int32 NewCount);//监听ASC激活GE的回调void OnActiveEffectAdded(UAbilitySystemComponent* TargetASC, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveEffectHandle);

使用对标签的监听来实现技能冷却结束的监听

	//监听冷却标签的变动,并绑定回调,用于获取冷却结束AbilitySystemComponent->RegisterGameplayTagEvent(InCooldownTag, EGameplayTagEventType::NewOrRemoved).AddUObject(ListenCooldownChange, &UListenCooldownChange::CooldownTagChanged);

对于技能进入冷却状态,我们采用监听应用冷却GE实现

	//监听GE应用回调,获取冷却激活,用于获取技能开始进入冷却AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(ListenCooldownChange, &UListenCooldownChange::OnActiveEffectAdded);

对于冷却的开始的参数设置,我们可以查看ASC源码,这个可以在客户端和服务器都获取到对应的委托回调来监听有时效性的GE
在这里插入图片描述
宏的定义时,是传入了三个参数
在这里插入图片描述
设置完成后,我们就可以返回,每次调用,我们可以创建一个监听实例

return ListenCooldownChange;

为了防止内存泄露,我们需要实现EndTask函数,在实例不需要时,对其进行销毁,并进行资源回收。AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf是由ASC创建的,所以不需要我们去对其进行销毁

void UListenCooldownChange::EndTask()
{//判断ASC是否存在if(!IsValid(ASC)) return;//取消对冷却标签的变动监听ASC->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved).RemoveAll(this);SetReadyToDestroy(); //设置此对象可以被销毁,如果此对象不再被引用,将可以被销毁掉MarkAsGarbage(); //标记此实例为垃圾资源,可以被回收
}

接着,我们还需要实现两个广播的处理,首先是对冷却结束的广播,我们对冷却标签进行获取,如果标签数量小于1,那么,技能将不处于冷却状态,我们广播冷却结束即可

void UListenCooldownChange::CooldownTagChanged(const FGameplayTag InCooldownTag, int32 NewCount) const
{//如果计数为0,代表冷却标签已经不存在,技能不处于冷却状态if(NewCount == 0){//广播冷却结束委托CooldownEnd.Broadcast(0.f);}
}

然后就是进入冷却的广播函数广播,我们首先获取这个应用的GE是否为设置了冷却标签,为了防止设置错误,我们获取了设置自身和设置给Actor的标签容器,判断容器内是否拥有我们设置的冷却标签。然后创建查询冷却标签的查询器对象,通过此对象去查找剩余的冷却时间,从中获取到最大冷却时间将时间广播出去。

void UListenCooldownChange::OnActiveEffectAdded(UAbilitySystemComponent* TargetASC, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveEffectHandle) const
{//获取设置到自身的所有标签FGameplayTagContainer AssetTags;SpecApplied.GetAllAssetTags(AssetTags);//获取到GE设置给Actor的标签FGameplayTagContainer GrantedTags;SpecApplied.GetAllGrantedTags(GrantedTags);//判断应用的GE是否设置了此冷却标签if(AssetTags.HasTagExact(CooldownTag) || GrantedTags.HasTagExact(CooldownTag)){//创建一个查询对象,用于查询包含所有标签容器标签的GEFGameplayEffectQuery GameplayEffectQuery = FGameplayEffectQuery::MakeQuery_MatchAllOwningTags(CooldownTag.GetSingleTagContainer());//返回查询到的所有包含此冷却GE的剩余时间的GETArray<float> TimesRemaining = ASC->GetActiveEffectsTimeRemaining(GameplayEffectQuery);if(TimesRemaining.Num() > 0){//获取最高的冷却时间float TimeRemaining = TimesRemaining[0];for(int32 i=0; i<TimesRemaining.Num(); i++){if(TimeRemaining < TimesRemaining[i]) TimeRemaining = TimesRemaining[i];}//广播初始时间CooldownStart.Broadcast(TimeRemaining);}}
}

接下来就是完整代码,不想看代码解析的,自己复制代码去修改名称运行即可
ListenCooldownChange.h

// 版权归暮志未晚所有。#pragma once#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "AbilitySystemComponent.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "ListenCooldownChange.generated.h"struct FGameplayAbilitySpec;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCooldownChangeSignature, float, TimeRemaining);/*** */
UCLASS(BlueprintType, meta = (ExposedAsyncProxy="AsyncTask"))
class RPG_API UListenCooldownChange : public UBlueprintAsyncActionBase
{GENERATED_BODY()public:UPROPERTY(BlueprintAssignable)FCooldownChangeSignature CooldownStart; //冷却触发开始委托UPROPERTY(BlueprintAssignable)FCooldownChangeSignature CooldownEnd; //冷却结束委托UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true"))static UListenCooldownChange* ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayTag& InCooldownTag);UFUNCTION(BlueprintCallable)void EndTask();protected:UPROPERTY()TObjectPtr<UAbilitySystemComponent> ASC;FGameplayTag CooldownTag; //记录监听的冷却标签//监听冷却标签回调函数void CooldownTagChanged(const FGameplayTag InCooldownTag, int32 NewCount) const;//监听ASC激活GE的回调void OnActiveEffectAdded(UAbilitySystemComponent* TargetASC, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveEffectHandle) const;
};

ListenCooldownChange.cpp

// 版权归暮志未晚所有。#include "AbilitySystem/AsyncTasks/ListenCooldownChange.h"#include "AbilitySystemComponent.h"UListenCooldownChange* UListenCooldownChange::ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayTag& InCooldownTag)
{UListenCooldownChange* ListenCooldownChange = NewObject<UListenCooldownChange>();ListenCooldownChange->ASC = AbilitySystemComponent;ListenCooldownChange->CooldownTag = InCooldownTag;//如果参数有一项未设置,我们将结束此任务if(!IsValid(AbilitySystemComponent) || !InCooldownTag.IsValid()){ListenCooldownChange->EndTask();return nullptr;}//监听冷却标签的变动,并绑定回调,用于获取冷却结束AbilitySystemComponent->RegisterGameplayTagEvent(InCooldownTag, EGameplayTagEventType::NewOrRemoved).AddUObject(ListenCooldownChange, &UListenCooldownChange::CooldownTagChanged);//监听GE应用回调,获取冷却激活,用于获取技能开始进入冷却AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(ListenCooldownChange, &UListenCooldownChange::OnActiveEffectAdded);return ListenCooldownChange;
}void UListenCooldownChange::EndTask()
{//判断ASC是否存在if(!IsValid(ASC)) return;//取消对冷却标签的变动监听ASC->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved).RemoveAll(this);SetReadyToDestroy(); //设置此对象可以被销毁,如果此对象不再被引用,将可以被销毁掉MarkAsGarbage(); //标记此实例为垃圾资源,可以被回收
}void UListenCooldownChange::CooldownTagChanged(const FGameplayTag InCooldownTag, int32 NewCount) const
{//如果计数为0,代表冷却标签已经不存在,技能不处于冷却状态if(NewCount == 0){//广播冷却结束委托CooldownEnd.Broadcast(0.f);}
}void UListenCooldownChange::OnActiveEffectAdded(UAbilitySystemComponent* TargetASC, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveEffectHandle) const
{//获取设置到自身的所有标签FGameplayTagContainer AssetTags;SpecApplied.GetAllAssetTags(AssetTags);//获取到GE设置给Actor的标签FGameplayTagContainer GrantedTags;SpecApplied.GetAllGrantedTags(GrantedTags);//判断应用的GE是否设置了此冷却标签if(AssetTags.HasTagExact(CooldownTag) || GrantedTags.HasTagExact(CooldownTag)){//创建一个查询对象,用于查询包含所有标签容器标签的GEFGameplayEffectQuery GameplayEffectQuery = FGameplayEffectQuery::MakeQuery_MatchAllOwningTags(CooldownTag.GetSingleTagContainer());//返回查询到的所有包含此冷却GE的剩余时间的GETArray<float> TimesRemaining = ASC->GetActiveEffectsTimeRemaining(GameplayEffectQuery);if(TimesRemaining.Num() > 0){//获取最高的冷却时间float TimeRemaining = TimesRemaining[0];for(int32 i=0; i<TimesRemaining.Num(); i++){if(TimeRemaining < TimesRemaining[i]) TimeRemaining = TimesRemaining[i];}//广播初始时间CooldownStart.Broadcast(TimeRemaining);}}
}

接着,我们在UI的事件图标中搜索名称,查看是否能够找到对应的节点
在这里插入图片描述
注意,我们搜索的名称是函数名称
在这里插入图片描述

测试代码

上面我们编写了对应的代码,首先做的就是快速测试一下,防止出现问题。
我们快速连一套测试节点,用来检测是否能够获取到对应事件
在这里插入图片描述
查看打印,发现事件确实成功触发,也有一些问题,比如触发了多次。触发多次的原因是因为所有的技能UI都是在监听这一个冷却标签
在这里插入图片描述

处理无法在蓝图调用的问题

我们当前无法在蓝图中获取对象进行调用销毁事件,所以需要一个方法,获取对象,我们在头文件设置,将其作为一个可获取参数,并设置命名"AsyncTask"

UCLASS(BlueprintType, meta = (ExposedAsyncProxy="AsyncTask"))

编译运行,可以查看到对象类型
在这里插入图片描述
我们可以将其设置为变量,避免没有销毁掉
在这里插入图片描述

设置冷却标签

我们需要记录技能的冷却标签,有一个比较好的方法就是在技能数据结构体增加一个配置项
在这里插入图片描述
在数据资产中配置上
在这里插入图片描述
接着我们修改ui的蓝图,在应用了技能数据后,对其绑定技能的回调,为了保证内存泄露,现进行销毁,防止频繁切换ui显示的技能导致频繁触发回调。
在这里插入图片描述
在ui被销毁时,也需要调用
在这里插入图片描述
接着编写代码测试
在这里插入图片描述
经过测试,发现还是有问题,原来是没有判断是否为当前需要监听的技能
和之前的技能一样,我们通过标签判断是否需要执行后续
在这里插入图片描述
这样就实现了事件监听
在这里插入图片描述

创建UI冷却效果

上面,我们实现了技能的冷却进入和退出。
我们接下来,要将冷却效果表现到UI上面,让玩家能够清晰的了解到技能已经进入冷却,无法释放。
我们增加两个函数节点,一个是设置技能UI变暗,并将冷却时间显示出来
在这里插入图片描述
另一个则是恢复默认状态,将冷却节点隐藏,并将技能图标颜色恢复默认
在这里插入图片描述
我们在监听到技能进入冷却后,将冷却时间保存为变量,方便后续使用,并进入冷却状态
在这里插入图片描述
然后我们设置一个定时器,在定时器里面对显示剩余时间进行更新,Time为多次时间更新一次,Looping选中,定时器将循环更新,不勾选将只触发一次。
在这里插入图片描述
并将定时器的引用保存下来,方便在冷却结束后,将其销毁
在这里插入图片描述
然后在自定义事件里面,减去每次调用时间,更新冷却时间,并显示到UI上面
在这里插入图片描述
为了防止出现负数,我们将其限制在最小值为0
在这里插入图片描述

在技能冷却结束后,我们将定时器清除,并恢复默认状态
在这里插入图片描述
接下来运行查看效果
在这里插入图片描述
在技能冷却完成,也能恢复默认
在这里插入图片描述
接下来,截取一张完整的蓝图
在这里插入图片描述

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

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

相关文章

Spring Boot 框架知识汇总

1、什么是SpringBoot&#xff1f; 通过Spring Boot&#xff0c;可以轻松地创建独立的&#xff0c;基于生产级别的Spring的应用程序&#xff0c;您可以“运行"它们。大多数Spring Boot应用程序需要最少的Spring配置&#xff0c;集成了大量常用的第三方库配置&#xff0c;使…

React有哪些应用场景

React 是一个由 Facebook 开发并广泛使用的 JavaScript 库&#xff0c;专门用于构建用户界面。由于其灵活性和强大的生态系统&#xff0c;React 被广泛应用于多种场景。以下是一些 React 的主要应用场景&#xff1a; 1. 单页面应用&#xff08;SPA&#xff09; React 的组件化…

在Anaconda环境中安装TensorFlow+启动jupyter notebook

1.打开cmd&#xff0c;输入C:\Users\xy>conda create -n tensorflow python3.7 这是在环境中创建了一个名为tensorflow的环境&#xff0c;具体会显示以下信息&#xff1a; C:\Users\xy>conda create -n tensorflow python3.7 Retrieving notices: ...working... done Co…

springboot把 EXCEL 文件以流的形式返回给前端

1.controller层 GetMapping(ReviewUrls.API_DOWNLOAD_REVIEW_RESULT)public Response<Void> downloadReviewResult(HttpServletResponse response) {resultService.downloadReviewResult(response);return Response.ok();}2.service层 public void downloadReviewResult(…

海豚调度器执行impla工作流成功但没跑出数据原因和解决方案

在海豚调度器(DolphinScheduler)中执行Impala离线脚本时出现执行状态成功但实际上未产出数据&#xff0c;之后重跑又能成功的情况&#xff0c;可能是由多种因素引起的。下面是一些可能的原因及对应的解决方案&#xff1a; 可能原因及解决方案 资源限制或并发冲突 原因&#x…

Python实战Elasticsearch的核心技巧详解

概要 Elasticsearch 是一个分布式的搜索引擎,可以用于全文搜索、结构化搜索、分析等多种场景。它基于Lucene构建,提供了强大的搜索功能和数据分析能力。本文将详细介绍如何使用Python实现与Elasticsearch的交互,包括安装、配置、基本操作和实际应用示例。 安装和配置 安装…

centos单机配置多个内网IP地址

centos单机配置多个内网IP地址 引配置1. 查看当前网络IP配置2. 打开网络配置目录3. 设置静态IP4. 编辑ifcfg-eno1:15. 重启网络配置 引 同一个局域网&#xff0c;但是对接的多个子系统使用了不同的网段&#xff0c;如一个系统主机IP地址是192.168.10.1&#xff0c;另一个系统主…

基于B站视频评论的文本分析,采用包括文本聚类分析、LDA主题分析、网络语义分析

研究主题 本研究旨在通过对B站视频评论数据进行文本分析&#xff0c;揭示用户评论的主题、情感倾向和语义结构&#xff0c;助力商业决策。主要技术手段包括Python爬虫、LDA主题分析、聚类分析和语义网络分析。首先&#xff0c;利用Python爬虫采集大量评论数据并进行预处理。运…

license系统模型设计使用django models

User (用户)License (许可证)Product (产品)LicenseAssignment (许可证分配) 简单的模型定义&#xff1a; from django.db import models from django.contrib.auth.models import Userclass Product(models.Model):name models.CharField(max_length255)description model…

npm发布的包如何快速在cnpm上使用

npm发布的包如何快速在cnpm上使用 解决方案 前往淘宝npm镜像官网 搜索插件库并点击同步 等待一分钟即可查看最新版本

linux进程周边知识——内核对硬件的管理——计算机世界的管理

前言&#xff1a;本节主要讲解内核也就是操作系统对于硬件的管理&#xff0c; 本节内容同样为进程的周边知识。 主要是关于软件方面&#xff0c; 和我的上一篇——冯诺依曼体系结构可以说是兄弟文章&#xff0c; 这篇文章主要是关于硬件方面。 两篇文章都是为学习进程做准备。但…

小程序创建与项目初始化(构建 npm + 集成 Sass)

一、打开微信开发者工具 确认 左侧导航栏是否选中的 小程序点击 【】创建小程序 二、创建小程序 三、初始化 清空 app.wxss、app.js 去掉 rendererOptions 和 componentFramework 不需要最新的搜索引擎 留下以下文件 四、自定义构建 npm 集成 Sass 首先 先把小程序源…

Go 高效Web开发框架 Echo

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

QT获得本地IP以及MAC地址

getIPSttring():连接的ip以及端口号来返回本地的ip地址 getMacString() : 通过本地的ip地址获得该IP地址关联的网络接口的MAC地址 QString getIpString(QString ip, QString port) {QTcpSocket socket;int t_port port.toInt();socket.connectToHost(ip, t_port);if (socket…

WEB前端01-HTML5基础(01)

一.WEB相关概念 软件架构 C/S: Client/Server &#xff08;客户端/服务器端&#xff09;&#xff1a;在用户本地有一个客户端程序&#xff0c;在远程有一个服务器端程序 优点&#xff1a;用户体验好 缺点&#xff1a;开发、安装&#xff0c;部署&#xff0c;维护麻烦 B/S: Br…

Qt Qml编程 基础部分 认识qml

学习目标&#xff1a;认识Qml编程 学习内容 qml介绍 Qt QML 是一个用来设计和开发Qt应用程序用户界面的声明性语言。QML 是 Qt 的元对象语言(Meta-Object Language)的缩写。它与 C 一起使用,来为 Qt 应用程序创建用户界面。 QML 是一个标记语言,它允许开发人员使用类似 HTM…

Chapter 1:数据结构前言

在数字化的世界里&#xff0c;我们每天都在与数据打交道。然而&#xff0c;你是否曾想过&#xff0c;这些数据是如何被组织、存储和处理的&#xff1f;这就是数据结构的魅力所在。 数据结构&#xff0c;简单来说&#xff0c;就是数据的组织方式。它决定了我们如何高效地访问和操…

一文学会鉴别“套壳”ChatGPT模型

一文学会鉴别“套壳”ChatGPT模型 随着ChatGPT等明星模型的诞生&#xff0c;市场上也开始出现一些“套壳”现象&#xff0c;即部分模型表面标榜原创或先进&#xff0c;实则在核心算法上与知名模型高度相似。作为技术探索者&#xff0c;如何拨开迷雾&#xff0c;识别这些“李鬼…

/EtherCATInfo/Descriptions/Devices/Device/SubDevice/@Hideable

SubDevice/Hideable 属性 /EtherCATInfo/Descriptions/Devices/Device/SubDevice/Hideable 出现次数&#xff1a;可选 (0…1)数据类型&#xff1a;布尔值 该属性仅应在列出所有子设备的主设备的 ESI 文件中使用。该属性表示配置工具是否可以隐藏相应的子设备。只有不需要配置…

sublime text中的配置好用的报错插件,代码检查插件sublimelinter,cppcheck,对C++的环境进行配置-2024.7.13版

文章目录 一&#xff0c;sublimelinter能实现什么&#xff1f;二、sublimelinter 的安装教程配置sublime text 的基础环境配置cppcheck的环境变量配置sublimelinter的配置文件 一&#xff0c;sublimelinter能实现什么&#xff1f; 因为sublime 不自带任何的代码检查工具&#…