45. UE5 RPG 增加角色受击反馈

news2024/12/27 11:17:39

在前面的文章中,我们实现了对敌人的属性的初始化,现在敌人也拥有的自己的属性值,技能击中敌人后,也能够实现血量的减少。
现在还需要的就是在技能击中敌人后,需要敌人进行一些击中反馈,比如敌人被技能击中后,可以播放击中的动画,并且显示伤害值。
我们在这一篇文章中,实现敌人被英雄的技能击中时,会播放受击动画,并且在敌人身上添加一个受击标签,角色在受击时,根据标签判断设置移动速度

设置角色受击标签

首先,我们实现在敌人身上添加标签,我们需要通过GE去添加。
创建一个新的GE
在这里插入图片描述
命名为GE_HitReact
在这里插入图片描述
在里面设置持续时间设置无限时间,我们在技能里面应用它,然后在技能结束是,将其清除
在这里插入图片描述
现在,我们还没有受击对应的标签,在c++里添加一个

FGameplayTag Effects_HitReact; //受击 标签
GameplayTags.Effects_HitReact = UGameplayTagsManager::Get()
	.AddNativeGameplayTag(
		FName("Effects.HitReact"),
		FString("受到攻击时,赋予的标签")
	);

然后在GE里面使用TargetTagsGameplayEffectComponent组件,它可以将标签应用到目标角色身上
在这里插入图片描述

角色监听标签并设置移动速度

我们接下来实现对受击标签的监听,在源码中,受击标签会返回监听的标签和添加标签的个数
在这里插入图片描述
在这里插入图片描述
我们创建一个委托回调函数

void HitReactTagChanged(const FGameplayTag CallbackTag, int32 NewCount);

并创建变量来表示角色是否处于受击状态

UPROPERTY(BlueprintReadOnly, Category="Combat")
bool bHitReacting = false; //当前是否处于被攻击状态

UPROPERTY(BlueprintReadOnly, Category="Combat")
float BaseWalkSpeed = 250.f; //当前角色的最大移动速度

在AEnemyBase::BeginPlay()中,我们设置对监听函数的回调

AbilitySystemComponent->RegisterGameplayTagEvent(FMyGameplayTags::Get().Effects_HitReact, EGameplayTagEventType::NewOrRemoved)
 .AddUObject(this, &ThisClass::HitReactTagChanged);

如果数量大于0,则将其的移动速度设置为0

void AEnemyBase::HitReactTagChanged(const FGameplayTag CallbackTag, int32 NewCount)
{
	bHitReacting = NewCount > 0;
	GetCharacterMovement()->MaxWalkSpeed = bHitReacting ? 0.f : BaseWalkSpeed;
}

创建一个受击技能,并应用GE

接下来,我们创建一个新的技能,用来实现受击,是的,受击也是角色的技能。在角色受到攻击时,将触发角色受击技能来实现受击效果。
在这里插入图片描述
在技能触发时,我们将受击标签添加到角色身上,这样,之前监听角色标签的回调函数将触发,并设置移动速度,我们并将句柄保持,在技能结束时,方便移除GE
在这里插入图片描述

实现设置角色的受击蒙太奇动画

接下来,我们将实现角色受击时播放蒙太奇动画,为了保证通用性,我们将其设置为一个函数,并设置到战斗接口中,这样只需要在战斗接口中获取对应角色的蒙太奇即可。(每个角色的受击动画不一定一样)
首先在战斗接口中实现一个函数,这函数可以在蓝图中被覆写,也可以在蓝图中调用。

UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
UAnimMontage* GetHitReactMontage(); //获取受击蒙太奇动画

然后,我们在角色的基类里,对这个函数进行覆写。

virtual UAnimMontage* GetHitReactMontage_Implementation() override;

并增加一个参数用于设置蒙太奇

UPROPERTY(EditAnywhere, Category="Combat")
TObjectPtr<UAnimMontage> HitReactMontage;

在函数实现这里,直接返回蒙太奇

UAnimMontage* ACharacterBase::GetHitReactMontage_Implementation()
{
	return HitReactMontage;
}

接着在技能里面,将ASC控制的角色转换为战斗接口,从战斗接口调用函数获取到角色设置的蒙太奇进行播放
在这里插入图片描述
接下来就是基于动画创建蒙太奇
在这里插入图片描述
并将蒙太奇设置到角色身上,用于函数返回。
在这里插入图片描述

激活受击技能

接下来,就是我们实现对技能的激活,和上一篇一样,我们创建了一个敌人的DataAsset,我们希望可以将敌人所拥有的初始技能都设置在数据里,并在初始化时使用。
在CharacterClassInfo.h里增加一个参数,用于设置创建敌人时所拥有的初始技能

	UPROPERTY(EditDefaultsOnly, Category="Common Class Defaults")
	TArray<TSubclassOf<UGameplayAbility>> CommonAbilities;

之前英雄角色初始化技能我们创建了一个应用技能的函数
在这里插入图片描述
它是创建技能实例,并给与ASC,我们将给敌人创建一个通用的函数,并放到函数库中
在这里插入图片描述
在函数技能库里新增一个函数用于初始化角色技能

//初始化角色的技能
UFUNCTION(BlueprintCallable, Category="MyAbilitySystemLibrary|CharacterClassDefaults")
static void GiveStartupAbilities(const UObject* WorldContextObject, UAbilitySystemComponent* ASC);

函数实现就是获取到数据资产里面的技能列表,创建实例并给与角色

void UMyAbilitySystemBlueprintLibrary::GiveStartupAbilities(const UObject* WorldContextObject, UAbilitySystemComponent* ASC)
{
	//获取到当前关卡的GameMode实例
	const AMyGameModeBase* GameMode = Cast<AMyGameModeBase>(UGameplayStatics::GetGameMode(WorldContextObject));
	if(GameMode == nullptr) return;

	const AActor* AvatarActor = ASC->GetAvatarActor();

	//从实例获取到关卡角色的配置
	UCharacterClassInfo* CharacterClassInfo = GameMode->CharacterClassInfo;

	//遍历角色拥有的技能数组
	for(const TSubclassOf<UGameplayAbility> AbilityClass : CharacterClassInfo->CommonAbilities)
	{
		FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1); //创建技能实例
		ASC->GiveAbility(AbilitySpec); //只应用不激活
	}
}

在敌人基类里,开始事件时,我们调用函数库的初始化技能函数,将技能应用到角色身上

void AEnemyBase::BeginPlay()
{
	Super::BeginPlay();

	//设置角色的初始移动速度
	GetCharacterMovement()->MaxWalkSpeed = BaseWalkSpeed;

	//初始化角色的ASC
	InitAbilityActorInfo();

	//初始化角色的技能
	UMyAbilitySystemBlueprintLibrary::GiveStartupAbilities(this, AbilitySystemComponent);
	...

方便测试,在PostGameplayEffectExecute函数里,之前设置血量下面有判断,我们在角色没有被击杀时,让其触发受击技能。激活我们是使用的根据标签激活,它需要传入一个FGameplayTagContainer 类型的参数。

	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时,角色将会死亡
			if(!bFatal)
			{
				FGameplayTagContainer TagContainer;
				TagContainer.AddTag(FMyGameplayTags::Get().Effects_HitReact);
				Props.TargetASC->TryActivateAbilitiesByTag(TagContainer); //根据tag标签激活技能
			}
		}
	}

接下来,编译代码,打开UE,将我们之前创建的受击技能设置到数据资产中
在这里插入图片描述
我们将使用标签激活技能,所以,在技能里,还需要将受击标签设置给技能
在这里插入图片描述
我们不需要在每次激活时创建一个新的实例,只需要一个角色生成一个实例重复利用即可。
在这里插入图片描述
由于它一个角色对应一个单例,每次触发都是相同的实例,所以,我们需要在其播放完成后,将其结束,才可以触发,所以,在敌人的受击动画播放完成后,我们需要将敌人身上的受击标签清楚(如果GE添加的,只需要将对应的GE清除,标签也会随着清除)并结束技能。
在这里插入图片描述
接下来,就是测试效果,我们攻击敌人,看看其是否能够播放动画。
在这里插入图片描述

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

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

相关文章

Mac基于Docker-ubuntu构建c/c++编译环境

编译环境安装和使用被充分验证&#xff0c;如有期望补充的内容欢迎留言评论。 目录 前言 Docker desktop下载安装 修改镜像源 选择ubuntu镜像 docker容器启动 参数说明: 宿主机与docker容器文件共享 宿主机与docker容器拷贝文件 为 Ubuntu 配置 ssh、vim、make 相关工…

基于Springboot的校园生活服务平台(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园生活服务平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

Maven 在项目的 pom.xml 文件中 指定 阿里云的景象仓库

配置 在 项目的 pom.xml 文件中添加如下配置即可 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&…

计数排序,基数排序,桶排序

目录 计数排序: 基数排序&#xff1a; 桶排序: 计数排序: 计数排序是一种非比较型整数排序算法&#xff0c;特别适用于一定范围内的整数排序。它的核心思想是使用一个额外的数组&#xff08;称为计数数组&#xff09;来计算每个值的出现次数&#xff0c;然后根据这些计数信…

Nginx 从入门到实践(2)——Rewrite重写

Nginx Rewrite Rewrite重写 Nginx Rewriteurl组成说明Rewrite基本概述Rewrite使⽤场景rewrite优点 Rewrite配置语法location匹配概述 if指令if 判断指令语法nginx以及if 判断可使用的全局变量 set命令return指令 url组成说明 https://cn.bing.com/search?qNginxRewrite&P…

VMware虚拟机忘记密码重置--centos7x

centos7虚拟机重置root密码 操作流程 操作流程 重启虚拟机&#xff0c;在如下页面键入e键&#xff1a; 2. 在如下位置添加&#xff1a;init/bin/sh&#xff0c;添加完成后键入Ctrlx启动 依次键入下列命令&#xff1a; mount -o remount,rw / #重新挂载/目录 passwd root #修改…

【微服务】分布式事务(通过Seata解决分布式事务问题)

分布式事务 分布式事务Seata微服务集成SeataXA模式XA模式使用 AT模式AT模式实现 分布式事务 在分布式系统中&#xff0c;如果一个业务需要多个服务合作完成&#xff0c;而且每一个服务都有事务&#xff0c;多个事务必须同时成功或失败&#xff0c;这样的事务就是分布式事务&am…

选择深度学习框架:TensorFlow 2 vs PyTorch

TensorFlow 2 vs PyTorch 选择深度学习框架&#xff1a;TensorFlow 2 vs PyTorchTensorFlow 2概述TensorFlow 2的优点TensorFlow 2的缺点 PyTorch概述PyTorch的优点PyTorch的缺点 选择建议对于选择困难症的人&#xff0c;我给你们的答案——PyTorch选择理由&#xff1a;结论&am…

Mac 电脑安装 Raptor 流程图软件的方法

0. 安装逻辑 &#xff08;1&#xff09;运行 raptor&#xff0c;本质上需要 mac 能够运行 windows 程序&#xff0c;因此需要安装 .NET Runtime 7.0&#xff0c;这是微软程序运行必须的文件。 &#xff08;2&#xff09;运行 raptor 还需要安装依赖文件 mono-libgdiplus。 &am…

python从0开始学习(三)

目录 前言 1、类型转换 1.1 隐式类型转换 1.2 显式类型转换 2、eval函数 总结 前言 上篇我们讲了python中的变量与常量&#xff0c;以及变量类型。本篇文章将接着往下讲。 1、类型转换 python中的数据类型转换包括两种&#xff1a;隐式类型转换和显式类型转换。 1.1 隐式…

微信IDE vscode插件:获取插件位置,并打开文件

背景 有没有觉得在微信开发工具里面添加一些插件可以很方便。因为微信IDE的编辑本身是依赖vscode开发&#xff0c;所以编写vscode插件自然可以在微信IDE使用。这样做好处就是可以满足到自己一些开发使用习惯。 1.获取插件的目录位置 那么如何获取插件里面的目录&#xff0c;…

分布式领域计算模型及SparkRay实现对比

目录 一、分布式计算领域概览 二、Spark计算模型分析 三、Ray计算模型分析 3.1 需求分析 3.2 系统设计 3.3 系统实现 四、总结 一、分布式计算领域概览 当前分布式计算模型主要分为以下4种&#xff1a; Bulk Synchronous Parallel Model&#xff08;块同步并行模型&…

常用语音识别开源四大工具:Kaldi,PaddleSpeech,WeNet,EspNet

无论是基于成本效益还是社区支持&#xff0c;我都坚决认为开源才是推动一切应用的动力源泉。下面推荐语音识别开源工具&#xff1a;Kaldi&#xff0c;Paddle&#xff0c;WeNet&#xff0c;EspNet。 1、最成熟的Kaldi 一个广受欢迎的开源语音识别工具&#xff0c;由Daniel Pove…

开发体育赛事直播平台,研发技术选型与架构设计实现方案

本文将深入探讨“东莞梦幻网络科技”现成体育直播源码的技术实现方案&#xff0c;如何为用户提供流畅、互动、个性化的观赛体验。 一、技术栈选择&#xff1a;强强联合的基石1、后端开发&#xff1a;采用Java与PHP作为主要开发语言。Java以其强大的企业级应用支持&#xff0c;保…

C++证道之路第十七章输入输出和文件

一、C输入和输出概述 C 提供了丰富的输入/输出&#xff08;I/O&#xff09;功能&#xff0c;这些功能主要通过 <iostream> 头文件中的类和对象来实现。 1.流和缓冲区 C把程序输入和输出看作字节流。输入时&#xff0c;程序从输入流中抽取字节&#xff1b;输出时&#…

使用 FFmpeg 从音视频中提取音频

有时候我们需要从视频文件中提取音频&#xff0c;并保存为一个单独的音频文件&#xff0c;我们可以借助 FFmpeg 来完成这个工作。 一、提取音频&#xff0c;保存为 mp3 文件: 要使用 FFmpeg 从音视频文件中提取音频&#xff0c;并将 ACC 编码的音频转换为 MP3 格式&#xff0…

【数据结构(邓俊辉)学习笔记】列表02——无序列表

文章目录 0.概述1.插入与构造1.1 插入1.1.1 前插入1.1.2后插入1.1.3 复杂度 1.2 基于复制构造1.2.1 copyNodes()1.2.2 基于复制构造1.2.3 复杂度 2.删除与析构2.1 删除2.1.1 实现2.1.2 复杂度 2.2 析构2.2.1 释放资源及清除节点2.2.2 复杂度 3.查找3.1 实现3.2 复杂度 4.唯一化…

FFmpeg学习记录(四)——SDL音视频渲染实战

1.SDL使用的基本步骤 SDL Init/sDL _Quit()SDL_CreateWindow()/SDL_DestoryWindow()SDL CreateRender() SDL_Windows *windows NULL;SDL_Init(SDL_INIT_VIDEO);window SDL_CreateWindow("SDL2 Windows",200,200, 640,480,SDL_WINDOW_SHOWN);if(!window) {printf(&…

【C语言回顾】数据在内存中的存储

前言1. 概述2. 大小端字节序和字节序判断2.1 大端字节序&#xff08;Big-Endian&#xff09;2.2 小端字节序&#xff08;Little-Endian&#xff09;2.3 判断字节序的示例 3. 数据在内存中的存储3.1 整数在内存中的存储3.2 浮点数在内存中的存储 结语 ↓ 上期回顾: 【C语言回顾】…

STM32 01

1、编码环境 1.1 安装keil5 1.2 安装STM32CubeMX 使用STM32CubeMX可以通过界面的方式&#xff0c;快速生成工程文件 安装包可以从官网下载&#xff1a;https://www.st.com/zh/development-tools/stm32cubemx.html#overview 安装完要注意更新一下固件包的位置&#xff0c;因为…