33. UE5 RPG使用增强输入激活GameplayAbility(三)

news2024/11/18 13:29:46

在前面的文章,我们实现了使用GameplayTag和InputAction的对应绑定的数据,并且添加到了增强输入映射的上下文中,实现了通过按键打印对应的GameplayTag,这只是我们基础需要制作的。目的主要是为了实现在GameplayAblity上面设置对应的Tag,在按下对应按键时,可以激活技能。
前面的步骤实现了,接下来,我们将在GA的基类上面增加一个GameplayTag配置属性,然后在给角色应用GA时,将GameplayTag设置给GA的实例,在触发InputAction的时候,通过遍历,找到被应用的GA里面有相同的Tag的GA,然后通过代码去触发。

实现

首先,我们需要再技能的基类上增加一个GameplayTag的配置属性,这样,我们就可以在技能蓝图上设置它所使用的GameplayTag了。

public:

	UPROPERTY(EditDefaultsOnly, Category="Input")
	FGameplayTag StartupInputTag;

在ASC中实现新的激活事件

接下来,我们要实现在运行时,应用GA时,需要在GamplayAbilitySpec身上将设置的GameplayTag存储下来。
DynamicAbilityTags是一个FGameplayTagContainer类型,它也是可以复制到服务器的,并且在创建GameplayAbilitySpec自动生成。
AbilitySpec.Ability是可以从Spec身上去获取实例的技能基类,并且它也是一个常量对象,我们在其身上设置的参数需要再常量身上去获取。

AbilitySpec.DynamicAbilityTags.AddTag(Cast<UGameplayAbilityBase>(AbilitySpec.Ability)->StartupInputTag);

我们修改ASC中添加技能的函数,它接收的参数是一个技能类的列表,然后遍历,我们在遍历里面通过类去创建Spec实例,如果Spec实例能够转换成我们创建的技能基类对象,那么,我们将基类对象身上设置的Tag设置到DynamicAbilityTags里面。
最后,我们将不会直接激活技能,而是只应用技能,然后通过按键触发技能。

void UAbilitySystemComponentBase::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities)
{
	for(const TSubclassOf<UGameplayAbility> AbilityClass : StartupAbilities)
	{
		FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);
		if(const UGameplayAbilityBase* AbilityBase = Cast<UGameplayAbilityBase>(AbilitySpec.Ability))
		{
			AbilitySpec.DynamicAbilityTags.AddTag(AbilityBase->StartupInputTag);
			GiveAbility(AbilitySpec); //只应用不激活
			// GiveAbilityAndActivateOnce(AbilitySpec); //应用技能并激活一次
		}
	}
}

下面,我们将在ASC上面增加两个函数,一个是触发技能的悬停时触发的函数,另一个是触发技能时按键离开时的。这两个函数都需要一个参数Tag去查找需要激活技能。

	void AbilityInputTagHold(const FGameplayTag& InputTag);
	void AbilityInputTagReleased(const FGameplayTag& InputTag);

在函数实现中,我们首先判断传入的InputTag是否可用

if(!InputTag.IsValid()) return;

然后遍历所有已经应用的技能,GetActivatableAbilities()将返回一个可激活技能的列表

for(auto AbilitySpec : GetActivatableAbilities())

然后我们将对Tag进行比对,判断Spec上设置的Tag和传入的Tag是否相同,如果相同,将对技能处理。

if(AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))

在技能悬停事件里面,我们首先调用告知GameplayAbility,此技能被触发按下事件,

AbilitySpecInputPressed(AbilitySpec);

防止技能重复被激活,判断当前技能是否处于激活状态

if(!AbilitySpec.IsActive())

尝试激活技能,这里尝试激活,是因为技能激活有很多限制,你调用了激活,只有在符合条件的情况下,才真正被激活。

TryActivateAbility(AbilitySpec.Handle);

而在Released函数内,我们调用了下面函数,告知技能按键事件被抬起。

AbilitySpecInputReleased(AbilitySpec);

这两个事件会触发技能上面的回调,来实现更多的逻辑,我们可以在技能里面覆盖它来实现

	virtual void InputPressed(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) override;
	virtual void InputReleased(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) override;

下面是在ASC实现的一个激活事件和取消事件的完整代码。

void UAbilitySystemComponentBase::AbilityInputTagHold(const FGameplayTag& InputTag)
{
	if(!InputTag.IsValid()) return;

	for(auto AbilitySpec : GetActivatableAbilities())
	{
		if(AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))
		{
			AbilitySpecInputPressed(AbilitySpec);
			if(!AbilitySpec.IsActive())
			{
				TryActivateAbility(AbilitySpec.Handle);
			}
		}
	}
}

void UAbilitySystemComponentBase::AbilityInputTagReleased(const FGameplayTag& InputTag)
{
	if(!InputTag.IsValid()) return;

	for(auto AbilitySpec : GetActivatableAbilities())
	{
		if(AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))
		{
			AbilitySpecInputReleased(AbilitySpec);
		}
	}
}

在PlayerController中修改并调用ASC的激活事件

接下来,我们将在PlayerController(PC主要储存角色操作的的相关内容的)里,触发操作后,调用ASC身上新创建的函数来触发技能激活。现在,我们还无法在PC身上获取ASC,所以,首先添加一个获取ASC的函数。
我们先创建一个变量存储ASC,然后再增加一个获取ASC的函数。

	UPROPERTY()
	TObjectPtr<UAbilitySystemComponentBase> AbilitySystemComponentBase;

	UAbilitySystemComponentBase* GetASC();

然后在函数实现这里,判断ASC是否被设置,如果没有被设置,将通过GAS的函数库去获取,这个静态函数将通过接口去获取

UAbilitySystemComponentBase* APlayerControllerBase::GetASC()
{
	if(AbilitySystemComponentBase == nullptr)
	{
		AbilitySystemComponentBase = Cast<UAbilitySystemComponentBase>(UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetPawn()));
	}

	return AbilitySystemComponentBase;
}

接着,我们修改之前在PC里面触发的事件的函数,之前实现到了打印Tag,现在我们将其修改掉, 不再打印

void APlayerControllerBase::AbilityInputTagPressed(FGameplayTag InputTag)
{
	GEngine->AddOnScreenDebugMessage(1, 3.f, FColor::Red, *InputTag.ToString());
}

void APlayerControllerBase::AbilityInputTagReleased(FGameplayTag InputTag)
{
	GEngine->AddOnScreenDebugMessage(2, 3.f, FColor::Blue, *InputTag.ToString());
}

void APlayerControllerBase::AbilityInputTagHold(FGameplayTag InputTag)
{
	GEngine->AddOnScreenDebugMessage(3, 3.f, FColor::Yellow, *InputTag.ToString());
}

在函数里,我们需要通过ASC去调用前面实现的激活技能函数,但是我们还无法确保ASC不为空指针,先做一下判断,然后返回。

void APlayerControllerBase::AbilityInputTagPressed(FGameplayTag InputTag)
{
	// GEngine->AddOnScreenDebugMessage(1, 3.f, FColor::Red, *InputTag.ToString());
}

void APlayerControllerBase::AbilityInputTagReleased(FGameplayTag InputTag)
{
	if(GetASC() == nullptr) return;
	GetASC()->AbilityInputTagReleased(InputTag);
}

void APlayerControllerBase::AbilityInputTagHold(FGameplayTag InputTag)
{
	if(GetASC() == nullptr) return;
	GetASC()->AbilityInputTagHold(InputTag);
}

测试

接下来,我们编译代码,解决bug,然后打开UE,找到之前我们做技能测试的蓝图,上面已经可以设置Tag了。
我们设置一个使用鼠标左键触发当前技能
在这里插入图片描述
我们之前测试时,在技能激活时触发ActivateAbility字符串打印,然后在一秒后触发技能关闭,并在屏幕打印技能结束
在这里插入图片描述

编辑运行,正常运行技能将不会被激活,而是在鼠标左键点击时触发
在这里插入图片描述

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

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

相关文章

物联网系统设计 8

1 规划中小型LoRa 中小型分时复用&#xff0c;大型项目需要学习LoRaWAN 1.1 通信记录 1.2 节点能耗 1278芯片 满功率20DMB&#xff0c;增加PA&#xff0c;发送功率 30 DBM 内置天线柔性 棒状 3db 203 休眠、发生、接收 计算链路预算&#xff0c;工作电流&#xff0c;工…

高效编写 kubernetes-YAML文件

1. YAML语法格式 2. kubernetes YAML 字段 3. 得力助手&#xff1a;help,dry-run,explain 4. vscode 工具生成和编写 5. YAML语法检查系统 YAML文件主要是编写 k8s 的一些资源的&#xff0c;对象(资源里面包含对象)&#xff0c;字段等&#xff0c;哪些字段&#xff0c;字段…

出门一笑, “栈” 落江横 (Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

设计模式——组合模式08

组合模式&#xff1a;把类似对象或方法组合成结构为树状的设计思路。 例如部门之间的关系。 设计模式&#xff0c;一定要敲代码理解 抽象组件 /*** author ggbond* date 2024年04月06日 08:54* 部门有&#xff1a;二级部门&#xff08;下面管三级部门&#xff09; 三级部门 &a…

12.自定义的多帧缓存架构

1.简介 在数字图像处理中&#xff0c;经常需要用到的一个架构就是多帧缓存。视频流中需要用到多帧缓存来防止帧撕裂现象&#xff0c;图像处理中也需要帧差法来做移动目标检测。因此一个多帧缓存架构在图像系统的设计中是十分重要的。 2.多帧缓存 在视频流中&#xff0c;通常不…

感染了后缀为.jayy勒索病毒如何应对?数据能够恢复吗?

导言&#xff1a; 在当今数字化的世界中&#xff0c;网络安全已经成为了每个人都需要关注的重要议题。而勒索病毒作为网络安全领域中的一大威胁&#xff0c;不断地演变和升级&#xff0c;给个人和组织带来了严重的损失和困扰。近期&#xff0c;一种名为.jayy的勒索病毒引起了广…

java数据结构与算法刷题-----LeetCode415. 字符串相加

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 模拟小学加法运算 模拟小学加法运算 解题思路&#xff1a;时间复…

【Java设计模式】创建型——工厂方法模式

目录 背景/问题解决方案思路方案 图解简单工厂模式/静态工厂模式工厂方法模式 代码示例&#xff1a;图形工厂意图主要解决何时使用如何解决关键代码 工厂模式的优点工厂模式的缺点使用场景注意事项 背景/问题 在软件设计中&#xff0c;我们经常遇到需要创建不同类型对象的情况…

如何理解模板?

文章目录 1. 泛型编程2.函数模板2.1函数模板概念2.1函数模板格式2.3函数模板的原理2.4函数模板的实例化2.5模板参数的匹配原则 3.类模板3.1类模板的定义格式3.2类模板的实例化 1. 泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right)…

Vue中如何使用Tailwind CSS样式?多次引用不成功?具体步骤怎么做?

一、安装Tailwind CSS和依赖 在你的Vue项目中安装Tailwind CSS及其依赖。你可以使用npm或yarn来安装。 npm install tailwindcsslatest postcsslatest autoprefixerlatest # 或者yarn add tailwindcsslatest postcsslatest autoprefixerlatest 二、初始化Tailwind CSS np…

【事务注解✈️✈️】@Transactional注解在不同参数配置下的功能实现

目录 前言 使用场景 1.单个方法层面 2.类级别使用 3.指定异常回滚 4.跨方法调用事务管理 5.只读事务 ​ 6.设置超时时间&#xff0c;超时则自动回滚 7.隔离级别设置 章末 前言 小伙伴们大家好&#xff0c;ACID&#xff08;原子性&#xff0c;一致性&#xff0c;隔离…

【WEEK6】 【DAY1】DQL查询数据-第一部分【中文版】

2024.4.1 Monday 目录 4.DQL查询数据&#xff08;重点&#xff01;&#xff09;4.1.Data Query Language查询数据语言4.2.SELECT4.2.1.语法4.2.2.实践4.2.2.1.查询字段 SELECT 字段/* FROM 表查询全部的某某查询指定字段 4.2.2.2.给查询结果或者查询的这个表起别名&#xff08…

2024免费Mac苹果解压压缩包软件BetterZip5

在2024年&#xff0c;对于Mac电脑用户来说&#xff0c;如果你想要无需解压就能快速查看压缩文档的内容&#xff0c;BetterZip是一个极佳的选择。这款软件不仅支持多种格式的压缩和解压&#xff0c;如zip、rar、7z、tar等&#xff0c;还具备丰富的功能和设置&#xff0c;包括预览…

【异常解决】Non-terminating decimal expansion; no exact representable decimal result.

Non-terminating decimal expansion; no exact representable decimal result. 一、背景描述二、异常原因三、解决方案四、RoundingMode&#xff08;舍入模式&#xff09;4.1、ROUND_UP4.2、ROUND_DOWN4.3、ROUND_CEILING4.4、ROUND_FLOOR4.5、ROUND_HALF_UP&#xff08;四舍五…

SQL语句的编写

##创建用户-建表建库 #创建一个用户名为 feng&#xff0c;允许从任何主机 % 连接&#xff0c;并使用密码 sc123456 进行身份验证的用户。 rootTENNIS 16:33 scmysql>create user feng% identified by sc123456; Query OK, 0 rows affected (0.04 sec) #创建一个名为fen…

软考113-上午题-【计算机网络】-IPv6、无线网络、Windows命令

一、IPv6 IPv6 具有长达 128 位的地址空间&#xff0c;可以彻底解决 IPv4 地址不足的问题。由于 IPv4 地址是32 位二进制&#xff0c;所能表示的IP 地址个数为 2^32 4 294 967 29640 亿&#xff0c;因而在因特网上约有 40亿个P 地址。 由 32 位的IPv4 升级至 128 位的IPv6&am…

ChromeOS 中自启动 Fcitx5 和托盘 stalonetray

ChromeOS 更新的飞快&#xff0c;旧文章的方法也老是不好用&#xff0c;找遍了也没找到很好的可以开机自启动 Linux VM 和输入法、托盘的方法。 研究了一下&#xff08;不&#xff0c;是很久&#xff09;&#xff0c;终于找到个丑陋的实现。 方法基于 ChromeOS 123.0.6312.94…

域名应该如何实名?域名应该如何备案?域名如何解析到服务器

大家好欢迎来到易极赞&#xff0c;今天我们来跟大家聊一下“域名应该如何实名以及备案”这个话题。 域名实名认证是验证域名所有者身份的过程&#xff0c;以确保域名的合法性&#xff0c;通常需要登录到域名服务商后台&#xff0c;进行域名的注册&#xff0c;注册后创建域名模…

MYSQL 锁机制 与 MVCC多版本并发

MYSQL锁机制与优化以及MVCC底层原理 锁分类 乐观锁&#xff0c;悲观锁 从性能上分为乐观锁&#xff08;版本对比,版本一致就更新&#xff0c;不一致就不更新或CAS机制&#xff09;和悲观锁&#xff08;锁住资源等待&#xff09;&#xff0c;乐观锁适合读比较多的场景&#x…

Unity和Android的交互

Unity和Android的交互 一、前言二、Android导出jar/aar包到Unity2.1 版本说明2.2 拷贝Unity的classes.jar给Android工程2.2.1 classes.jar的位置2.2.2 Android Studio创建module2.2.3 拷贝classes.jar 到 Android工程并启用 2.3 编写Android工程代码2.3.1 创建 MainActivity2.…