104. UE5 GAS RPG 实现技能火焰爆炸

这一篇文章我们再实现一个技能火焰爆炸,由于我们之前已经实现了三个玩家技能,这一个技能有一些总结的味道,对于创建技能相同的部分,长话短说,我们过一遍。

准备工作

我们需要一个技能类,继承于伤害技能基类
在这里插入图片描述
主要在里面覆写一下技能描述
在这里插入图片描述
接下来主要是实现

FString URPGFireBlast::GetDescriptionAtLevel(const int32 Level, const FString& Title)
{const int32 Damage = GetDamageByDamageType(Level, FRPGGameplayTags::Get().Damage_Fire);const float ManaCost = GetManaCost(Level);const float Cooldown = GetCooldown(Level);return FString::Printf(TEXT(// 标题"<Title>%s</>\n"// 细节"<Small>等级:</> <Level>%i</>\n""<Small>技能冷却:</> <Cooldown>%.1f</>\n""<Small>蓝量消耗:</> <ManaCost>%.1f</>\n\n"//%.1f会四舍五入到小数点后一位// 技能描述"<Default>向四面八方发射 %i 颗火球,每颗火球会在返回时发生爆炸,并造成</> <Damage>%i</> <Default>点径向火焰伤害,并有一定几率触发燃烧。</>"),// 动态修改值*Title,Level,Cooldown,-ManaCost,NumFireBalls,Damage);
}

然后,创建一个蓝图类,用于实现技能逻辑,技能逻辑在下面再实现,我们将装配,伤害,等相关的实现。
在这里插入图片描述
技能需要创建两个标签,一个是技能的标识标签,通过标签可以获取到此技能,另一个就是技能对应的冷却标签,我们直接通过标签管理器创建即可。
在这里插入图片描述
技能的标识标签需要在代码中获取,我们需要在代码中创建
在这里插入图片描述
有了技能蓝图和标签,我们再技能数据资产将数据添加,后续可以通过此来获取数据,显示到ui,等。
在这里插入图片描述

在技能面板的技能按钮,将需要显示此技能的按钮的技能tag设置为对应技能tag
在这里插入图片描述
接下来,就是实现技能的伤害,冷却和消耗,对于伤害和消耗,我们需要在对应的图表CT_Damage和CT_SpellCost里增加对应的表格内容。
在这里插入图片描述
在技能蓝图里,设置对应的技能伤害GE,这个我们是通用的,然后引用伤害
在这里插入图片描述
并将标签设置
在这里插入图片描述
接着创建两个GE,实现冷却和消耗
在这里插入图片描述
冷却还是之前思路,添加标签实现
在这里插入图片描述
消耗去修改属性,这种也不是必须的,我们在技能里调用CommitAbility之前可以设置,或者实现一种自动计算的方式都可以。
在这里插入图片描述
然后设置给技能
在这里插入图片描述

接下来就是运行测试效果是否符合预期
在这里插入图片描述
为了方便后续测试,我们将技能直接放置到技能栏,首先设置技能的输入标签
在这里插入图片描述
然后在初始技能数组里添加对应的技能
在这里插入图片描述

添加火球

接下来,我们实现技能的表现效果,技能会平均角度,向角色的四面八方移动,然后移动到一定距离,自动返回并发生爆炸。实现这个效果,我们无法通过使用内置的方法,需要使用时间轴来实现效果。
基于之前的火球术的实现,我们创建一个对应的火球的子类
在这里插入图片描述
命名一下
在这里插入图片描述
在类里,我们覆写beginPlay函数,并添加一个蓝图实现

/*** 火焰爆发使用的火球类*/
UCLASS()
class RPG_API ARPGFireBall : public AProjectile
{GENERATED_BODY()public://执行蓝图时间轴事件,需要在蓝图中实现此事件UFUNCTION(BlueprintImplementableEvent)void StartOutgoingTimeline();UPROPERTY(BlueprintReadOnly) //当前火球返回的目标角色,默认是技能的释放者,在创建火球是创建TObjectPtr<AActor> ReturnToActor;
protected:virtual void BeginPlay() override;

在游戏开始事件里调用时间轴事件

void ARPGFireBall::BeginPlay()
{Super::BeginPlay();StartOutgoingTimeline(); //调用开始时间线修改
}

编译打开UE创建一个对应的蓝图类
在这里插入图片描述
添加一个Niagara组件,用于显示粒子效果
在这里插入图片描述
设置爆炸效果和音效配置
在这里插入图片描述
因为我们需要使用时间轴实现,内置的自动移动的相关可以关闭
在这里插入图片描述
关闭帧更新
在这里插入图片描述
我们也不需要自动激活
在这里插入图片描述
在火球蓝图里,我们实现时间轴事件,首先获取到初始位置和火球移动的最远目标位置
在这里插入图片描述
在后面,我们首先实现火球从初始位置移动到终点位置,通过时间轴实现
在这里插入图片描述
时间轴里面设置了一个值,这个值采用现快后慢的方式,这样火球有一种减速的效果。值是0-1,我们可以通过插值的方式实现位置从起点到终点。
在这里插入图片描述
在上一个时间轴执行完成之后,我们再运行一个时间轴,这个事件轴是实现角色返回到角色的当前位置,所以,我们修改为了从终点位置向玩家角色位置插值,这里将当前玩家的位置进行了保存,方便后续使用
在这里插入图片描述
这个时间轴的线是先慢后快
在这里插入图片描述
最后,我们在返回更新时,如果火球和角色的距离小于某个阈值,那么将自我销毁,防止火球攻击自身
在这里插入图片描述
对于这种相乘的我们可以转换类型
在这里插入图片描述
这是转换成浮点类型的效果
在这里插入图片描述

修改技能类实现表现效果

接着,我们修改技能实现效果,我们在技能里设置一个参数,用于设置火球类

private:UPROPERTY(EditDefaultsOnly, Category="FireBlast") //生成火球使用的类TSubclassOf<ARPGFireBall> FireBallClass;

编译,在技能蓝图类里设置我们创建的火球蓝图类
在这里插入图片描述
接着,我们在技能类里创建一个生成火球的函数,这个函数里,可以生成技能所需的火球

	/*** 生成技能所需的火球* @return NumFireBalls个数火球的数组*/UFUNCTION(BlueprintCallable)TArray<ARPGFireBall*> SpawnFireBall();

在代码实现里,我们获取到角色的位置和朝向,通过之前创建的函数,获取到每个火球的旋转值,并通过旋转值创建火球,生成所需的参数。

TArray<ARPGFireBall*> URPGFireBlast::SpawnFireBall()
{//获取到角色朝向和位置const FVector Forward = GetAvatarActorFromActorInfo()->GetActorForwardVector();const FVector Location = GetAvatarActorFromActorInfo()->GetActorLocation();//通过函数获取到每个需要生成的火球的旋转TArray<FRotator> Rotators = URPGAbilitySystemLibrary::EvenlySpacedRotators(Forward, FVector::UpVector, 360.f, NumFireBalls);TArray<ARPGFireBall*> FireBalls; //生成所需的火球数组for(const FRotator& Rotator : Rotators){//创建变换FTransform SpawnTransform;SpawnTransform.SetLocation(Location);SpawnTransform.SetRotation(Rotator.Quaternion());//创建火球 使用 SpawnActorDeferred 来生成对象时,UE 会延迟实际的对象生成过程,这样你有机会在完全初始化对象之前进行自定义配置。ARPGFireBall* FireBall = GetWorld()->SpawnActorDeferred<ARPGFireBall>(FireBallClass,SpawnTransform,GetOwningActorFromActorInfo(),CurrentActorInfo->PlayerController->GetPawn(),ESpawnActorCollisionHandlingMethod::AlwaysSpawn);//设置火球的伤害配置FireBall->DamageEffectParams = MakeDamageEffectParamsFromClassDefaults();FireBall->ReturnToActor = GetAvatarActorFromActorInfo();FireBalls.Add(FireBall);//在配置完成火球配置后,调用FinishSpawning将火球正式添加到场景中FireBall->FinishSpawning(SpawnTransform);}return FireBalls;
}

然后在技能蓝图里调用函数
在这里插入图片描述
接下来就是运行查看效果
在这里插入图片描述

实现伤害

接下来,我们实现技能的伤害,伤害分为两种,一种是火球在行进当中与敌人触碰造成的伤害,另一种是在火球靠近释放者一定范围后,销毁时产生的爆炸。

我们首先实现行进中与敌人产生碰撞造成的伤害。
首先,我们配置技能的蓝图的配置,设置对应的伤害以及伤害类型。
在这里插入图片描述
接着,我们要在c++中,覆写OnSphereOverlap函数,实现在移动过程中造成的伤害。这里,我们基于ARPGFireBlot重写,去掉了与敌人产生重叠后的销毁火球的事件,而是应用一个伤害GE,由于火球没有伤害击退效果,这里我们去掉了相关代码。

void ARPGFireBall::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{if(GetInstigator() == OtherActor) return; //判断和碰撞体接触的目标是否为自身//如果不是敌人,将不执行后续if(!URPGAbilitySystemLibrary::IsNotFriend(GetInstigator(), OtherActor)) return;//目标未继承战斗接口,返回if(!OtherActor->Implements<UCombatInterface>()) return;//播放击中特效 当前服务器端未调用销毁时,直接播放if(!bHit) PlayImpact();//在重叠后,销毁自身if(HasAuthority()) //是否为服务器,如果服务器端,将执行应用GE,并通过GE的自动同步到客户端{//为目标应用GEif(UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(OtherActor)){//死亡冲击的力度和方向DamageEffectParams.DeathImpulse = GetActorForwardVector() * DamageEffectParams.DeathImpulseMagnitude;//通过配置项应用给目标ASCDamageEffectParams.TargetAbilitySystemComponent = TargetASC;URPGAbilitySystemLibrary::ApplyDamageEffect(DamageEffectParams);}}
}

接下来则是实现火球移动结束后的爆炸效果,这个效果实现,我们需要修改伤害配置项,将其修改为范围伤害,这里采用的是增加一些修改对应配置的函数,然后在蓝图调用实现配置项的修改,然后应用给目标。
这里,我们在函数库里增加了四个函数,用于修改伤害配置项的范围伤害参数,击退,死亡时的击退以及攻击敌人的ASC的函数

	/*** 修改伤害配置项,将其设置为具有范围伤害的配置项* @param DamageEffectParams 需要修改的配置项* @param bIsRadial 设置是否为范围伤害* @param InnerRadius 内半径* @param OutRadius 外半径* @param Origin 伤害中心*/UFUNCTION(BlueprintCallable, Category="RPGAbilitySystemLibrary|GameplayEffects")static void SetIsRadialDamageEffectParams(UPARAM(ref) FDamageEffectParams& DamageEffectParams, bool bIsRadial, float InnerRadius, float OutRadius, FVector Origin);/*** 修改伤害的冲击力的方向* @param DamageEffectParams 需要修改的伤害配置项* @param KnockbackDirection 攻击时触发击退的方向*/UFUNCTION(BlueprintCallable, Category="RPGAbilitySystemLibrary|GameplayEffects")static void SetKnockbackDirection(UPARAM(ref) FDamageEffectParams& DamageEffectParams, FVector KnockbackDirection, float Magnitude = 0.f);/*** 修改伤害的冲击力的方向* @param DamageEffectParams 需要修改的伤害配置项* @param ImpulseDirection 死亡时触发击退的方向*/UFUNCTION(BlueprintCallable, Category="RPGAbilitySystemLibrary|GameplayEffects")static void SetDeathImpulseDirection(UPARAM(ref) FDamageEffectParams& DamageEffectParams, FVector ImpulseDirection, float Magnitude = 0.f);/*** 设置伤害配置应用目标ASC* @param DamageEffectParams 需要修改的伤害配置 * @param InASC 应用目标ASC*/UFUNCTION(BlueprintCallable, Category="RPGAbilitySystemLibrary|GameplayEffects")static void SetEffectParamsTargetASC(UPARAM(ref) FDamageEffectParams& DamageEffectParams, UAbilitySystemComponent* InASC);

接着,我们实现对配置项的修改

void URPGAbilitySystemLibrary::SetIsRadialDamageEffectParams(FDamageEffectParams& DamageEffectParams, bool bIsRadial, float InnerRadius, float OutRadius, FVector Origin)
{DamageEffectParams.bIsRadialDamage = bIsRadial;DamageEffectParams.RadialDamageInnerRadius = InnerRadius;DamageEffectParams.RadialDamageOuterRadius = OutRadius;DamageEffectParams.RadialDamageOrigin = Origin;
}void URPGAbilitySystemLibrary::SetKnockbackDirection(FDamageEffectParams& DamageEffectParams, FVector KnockbackDirection, float Magnitude)
{KnockbackDirection.Normalize();if(Magnitude == 0.f){DamageEffectParams.KnockbackForce = KnockbackDirection * DamageEffectParams.KnockbackForceMagnitude;}else{DamageEffectParams.KnockbackForce = KnockbackDirection * Magnitude;}
}void URPGAbilitySystemLibrary::SetDeathImpulseDirection(FDamageEffectParams& DamageEffectParams, FVector ImpulseDirection, float Magnitude)
{ImpulseDirection.Normalize();if(Magnitude == 0.f){DamageEffectParams.DeathImpulse = ImpulseDirection * DamageEffectParams.DeathImpulseMagnitude;}else{DamageEffectParams.DeathImpulse = ImpulseDirection * Magnitude;}
}void URPGAbilitySystemLibrary::SetEffectParamsTargetASC(FDamageEffectParams& DamageEffectParams, UAbilitySystemComponent* InASC)
{DamageEffectParams.TargetAbilitySystemComponent = InASC;
}

接着,我们编译代码,打开火球蓝图,在触发火球爆炸后,实现对应逻辑
在这里插入图片描述
我们将后面的逻辑封装为了一个函数,这个函数内主要逻辑是设置技能造成的范围伤害相关参数,以及获取到需要应用伤害的目标,然后调用函数应用,销毁自身。
在这里插入图片描述
应用伤害的函数看似很长,其实主要就是遍历伤害数组,然后修改应用目标的ASC,以及击退相关参数,这里对每个目标的值都不一样。最后调用函数库函数应用即可。
在这里插入图片描述

修改爆炸使用GameplayCue实现

我们实现了伤害,这里再修改爆炸时的爆炸效果,我们采用通过c++调用,然后使用GameplayCue实现。
我们在c++里增加一个新的标签,这个火焰爆炸的GameplayCue可以通过此标签调用

FGameplayTag GameplayCue_FireBlast; //火焰爆炸火球爆炸时的表现效果
	GameplayTags.GameplayCue_FireBlast = UGameplayTagsManager::Get().AddNativeGameplayTag(FName("GameplayCue.FireBlast"),FString("火焰爆炸表现效果标签"));

我们需要覆写RPGFireBall的PlayImpact函数

virtual void PlayImpact() override;

实现这里,我们将通过UGameplayCueManager去调用GameplayCue,而不是之前的方式。

void ARPGFireBall::PlayImpact()
{if(GetOwner()){//设置GameplayCue播放位置FGameplayCueParameters Parameters;Parameters.Location = GetActorLocation();UGameplayCueManager::ExecuteGameplayCue_NonReplicated(GetOwner(), FRPGGameplayTags::Get().GameplayCue_FireBlast, Parameters);}//将音乐停止后会自动销毁if(LoopingSoundComponent){//循环组件暂停并销毁LoopingSoundComponent->Stop();LoopingSoundComponent->DestroyComponent();}bHit = true;
}

接着编译打开蓝图,创建一个对应的GameplayCue
在这里插入图片描述
设置应用标签
在这里插入图片描述
然后设置粒子系统和爆炸音效。
在这里插入图片描述

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

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

相关文章

【C语言】动态内存开辟

写在前面 C语言中有不少开辟空间的办法&#xff0c;但是在堆上开辟的方法也就只有动态内存开辟&#xff0c;其访问特性与数组相似&#xff0c;但最大区别是数组是开辟在栈上&#xff0c;而动态内存开辟是开辟在堆上的。这篇笔记就让不才娓娓道来。 PS:本篇没有目录实在抱歉CSD…

Excel:vba实现插入图片

实现的效果&#xff1a; 实现的代码&#xff1a; Sub InsertImageNamesAndPictures()Dim PicPath As StringDim PicName As StringDim PicFullPath As StringDim RowNum As IntegerDim Pic As ObjectDim Name As String 防止表格里面有脏数据Cells.Clear 遍历工作表中的每个图…

6.FreeRTOS之任务通知

什么是任务通知&#xff1f; FreeRTOS 从版本 V8.2.0 开始提供任务通知这个功能&#xff0c;每个任务都有一个 32 位的通知值。按照 FreeRTOS 官方的说法&#xff0c;使用消息通知比通过二进制信号量方式解除阻塞任务快 45% &#xff0c; 并且更加 省内存&#xff08;无需创…

前端之html(一)

HTML定义: HTML 超文本标记语言 (1)骨架: HTML:整个网页 head:网页头部 boby:网页主体 title:网页标题 (2)标签关系: 1.嵌套 2.并列 (3)注释 语法:<!-- ... --> 基础: (4) 标签:双标签:<> ... </> 单标签:<> <br> …

书生第四期实训营基础岛——L1G3000浦语提示词工程实践

基础任务 任务要求 背景问题&#xff1a;近期相关研究指出&#xff0c;在处理特定文本分析任务时&#xff0c;语言模型的表现有时会遇到挑战&#xff0c;例如在分析单词内部的具体字母数量时可能会出现错误。任务要求&#xff1a;利用对提示词的精确设计&#xff0c;引导语言…

Android启动流程_SystemServer阶段

前言 上一篇文档我们描述了在 Android 启动流程中 Zygote 部分的内容&#xff0c;从 Zygote 的配置、启动、初始化等内容展开&#xff0c;描述了 Zygote 在 Android 启动中的功能逻辑。本篇文档将会继续 Android 启动流程的描述&#xff0c;从 SystemServer 进程的内容展开&am…

Flutter CustomScrollView 效果-顶栏透明与标签栏吸顶

CustomScrollView 效果 1. 关键组件 CustomScrollView, SliverOverlapAbsorber, SliverPersistentHeader 2. 关键内容 TLDR SliverOverlapAbsorber 包住 pinned为 true 的组件 可以被CustomScrollView 忽略高度。 以下的全部内容的都为了阐述上面这句话。初阶 Flutter 开发知…

Litctf-web

Litctf-web exx xxe&#xff0c; <?xml version"1.0" encoding"utf-8"?> <!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "file:///flag" >]><user><username>&xxe;</username> …

线程模型介绍

线程模型的介绍 线程有三种模型&#xff1a;N:1用户线程模型&#xff0c;1:1核心线程模式&#xff0c;N:M混合线程模型 POSIX: Portable Operating System Interface(可移值操作系统接口) N&#xff1a;1用户线程模型 线程的实现建立在进程控制的机制之上&#xff0c;有用户…

2024 Rust现代实用教程:1.3获取rust的库国内源以及windows下的操作

文章目录 一、使用Cargo第三方库1.直接修改Cargo.toml2.使用cargo-edit插件3.设置国内源4.与windows下面的rust不同点 参考 一、使用Cargo第三方库 1.直接修改Cargo.toml rust语言的库&#xff1a;crate 黏贴至Cargo.toml 保存完毕之后&#xff0c;自动下载依赖 拷贝crat…

ML 系列:第 18 部 - 高级概率论:条件概率、随机变量和概率分布

文章目录 一、说明二、关于条件概率2.1 为什么我们说条件概率&#xff1f;2.2 为什么条件概率在统计学中很重要 三、 随机变量的定义3.1 定义3.2 条件概率中的随机变量 四、概率分布的定义五、结论 一、说明 条件概率是极其重要的概率概念&#xff0c;它是因果关系的数学表述&…

基于springboot的社区团购系统设计与实现

一、项目背景 网络交易&#xff08;Electronic Commerce&#xff09;&#xff1a;是指实现整个贸易过程中各阶段的贸易活动的电子化。网络交易是一种多技术的集合体。其业务可包括&#xff1a;信息交换、售后服务、销售、电子支付、运输、组建虚拟企业、公司和贸易伙伴可以共同…

一文读懂系列:SSL加密流量检测技术详解

SSL加密流量检测功能的主要目的是为了对加密流量做解密处理&#xff0c;并对解密后的流量做内容安全检查&#xff08;比如反病毒、入侵防御、URL远程查询、内容过滤、文件过滤和邮件过滤等&#xff09;和审计&#xff08;防止信息泄露&#xff09;。接下来我们详细介绍SSL加密流…

【C++】关联式容器

1.Set和Map 1.1 set的介绍 set是一个常用的关联式容器&#xff0c;它存储唯一的元素&#xff0c;这些元素默认情况下按照升序排序。其底层是一种自平衡的二叉搜索树(红黑树)。 set元素的键值就是实值&#xff0c;实值就是键值。set的元素允许插入删除但是不允许修改(具有const…

荣誉证书PSD素材(59套免费)

本作品提供荣誉证书PSD素材下载&#xff0c;格式为PSD&#xff1b; 请使用软件Photoshop进行编辑&#xff0c;作品中文字及图均可以通过软件修改和编辑&#xff1b; 点击下载: 荣誉证书PSD素材

第T6周:Tensorflow实现好莱坞明星识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目标 具体实现 &#xff08;一&#xff09;环境 语言环境&#xff1a;Python 3.10 编 译 器: PyCharm 框 架: &#xff08;二&#xff09;具体步骤 1.查询…

Spring6框架搭建(自用)

一、什么是Spring 众所不周知&#xff0c;Spring就是爪哇人的春天&#xff0c;但是在框架程序设计之前都绕不开javaWeb 1.javaWeb框架发展史 1、ServletJSPJavaBean(跳转页面、业务逻辑判断、数据库查询) 2、MVC三层架构(M Model pojo(User)V-view(USP)C-(controller-servl…

linux-UART

参考博客 https://blog.csdn.net/m0_38106923/article/details/126024970?sharetypeblog&shareId126024970&sharereferAPP&sharesourceweixin_40933496&sharefromlink 1.串口 UART的全称是Universal Asynchronous Receiver and Transmitter&#xff0c;即异步…

大数据治理:策略、技术与挑战

随着信息技术的飞速发展&#xff0c;大数据已经成为现代企业运营和决策的重要基础。然而&#xff0c;大数据的复杂性、多样性和规模性给数据管理带来了前所未有的挑战。因此&#xff0c;大数据治理应运而生&#xff0c;成为确保数据质量、合规性、安全性和可用性的关键手段。本…

vue插件清除 所有console.log()

一、作用 1、提升性能console.log() 语句会消耗一定的性能&#xff0c;尤其是在频繁调用的情况下。在生产环境中移除这些语句可以提高应用的运行效率。 2、减少信息泄露console.log() 可以输出敏感信息&#xff08;如用户数据、API 响应等&#xff09;。在生产环境中&#xf…