97. UE5 GAS RPG 实现闪电链技能(二)

书接上回,如果没有查看上一篇文章的同学推荐先看上一章,我们接着实现闪电链技能。
在上一章最后,我们实现了闪电链的第一条链,能够正确显示特效,接下来,我们先实现它的音效和一些bug修复。

在这里插入图片描述
我们在多端网络里,只能查看到角色播放了闪电链开始攻击,但是没有持续攻击动画,原因是因为在角色身上的变量没有设置可复制,我们修改一下即可。

添加音效

接下来,我们添加在持续释放闪电链时播放的音效,我们在设置Niagara 系统之后,附加一个音效节点,设置其不会被自动销毁,并将其生成的组件作为变量保存下来,并在取消技能时方便销毁。
在这里插入图片描述
接着就是在停止闪电链技能时,设置销毁
在这里插入图片描述
我们还可以使用fadeOut来实现声音慢慢变小停止
在这里插入图片描述
使用这个时,注意自动销毁要开启,它会在音频停止时自动销毁组件
在这里插入图片描述

为技能增加新通道

我们为了将移动和技能拾取分开,所以增加一个新的通道
在引擎-碰撞这里增加一个新通道
在这里插入图片描述
默认设置阻挡
在这里插入图片描述
它是第二个,所以我们可以在代码中获取
在这里插入图片描述
代码中设置默认通道就是18个,和我们 可以自定义18个匹配
在这里插入图片描述
在鼠标拾取这里,修改为新建的通道
在这里插入图片描述
记得将一些不可让技能拾取的对象相应关掉
在这里插入图片描述
还有我们之前的碰撞拾取溶解效果的问题,会出现来回闪的问题,我们可以通过添加简易碰撞,并设置项目默认来解决。
在这里插入图片描述
项目默认是在引擎-物理这里修改
在这里插入图片描述

设置获取第一个闪电命中

接下来,我们实现获取第一个命中结果,因为鼠标选中的中间有可能被阻挡,我们需要考虑这个因素,所以,将其判断出来,如果鼠标拾取和武器发射位置中间有其它敌人被阻挡,那么,我们将更新它的目标位置。
首先我们在闪电链技能里增加一个新的函数,用于获取闪电链命中的第一个敌人

	/*** 拾取闪电链命中的第一个目标* @param BeamTargetLocation 鼠标点击目标位置* @note 有可能中间会被阻挡,拾取的目标不是鼠标选中的目标*/UFUNCTION(BlueprintCallable)void TraceFirstTarget(const FVector& BeamTargetLocation);

接着,我们实现此函数

void URPGBeamSpell::TraceFirstTarget(const FVector& BeamTargetLocation)
{//确保所有者继承了战斗接口if(OwnerCharacter && OwnerCharacter->Implements<UCombatInterface>()){//获取到武器if(USkeletalMeshComponent* Weapon = ICombatInterface::Execute_GetWeapon(OwnerCharacter)){TArray<AActor*> ActorsToIgnore; //当前需要忽略的对象数组ActorsToIgnore.Add(OwnerCharacter);// 将自身忽略掉const FVector SocketLocation = Weapon->GetSocketLocation(FName("TipSocket")); //获取技能发射位置FHitResult HitResult; //命中结果的纯粹对象//通过武器发射位置和命中位置生成一条球形线,获取第一个命中的结果UKismetSystemLibrary::SphereTraceSingle(OwnerCharacter,SocketLocation,BeamTargetLocation,10.f,TraceTypeQuery1,false,ActorsToIgnore,EDrawDebugTrace::ForDuration, //如果需要debug,将其设置ForDuration,如果关闭设置为NoneHitResult,true);//如果有命中的结果,修改拾取结果if(HitResult.bBlockingHit){MouseHitLocation = HitResult.ImpactPoint;MouseHitActor = HitResult.GetActor();}}}
}

我们将生成闪电链的函数折叠为了一个函数,在调用GameplayCue之前,调用此函数
在这里插入图片描述
然后查看效果
在这里插入图片描述
接下来,我们想实现如果命中的是角色,我们让闪电链结束的位置是目标角色的位置,这样可以放置发生偏斜。
我们修改技能的生成闪电链的逻辑代码,先将GameplayCue的代码创建出来,然后判断命中的第一个actor是否继承战斗接口。
如果继承战斗接口,那么目标就是敌人,我们将GameplayCue的所有者设置为敌人,在敌人死亡时,Cue也会被销毁。如果不是,那就是目标是场景,我们还是使用技能的所有者。
在这里插入图片描述
接着修改技能结束时,我们需要销毁掉GameplayCue,由于根据目标是否继承战斗接口,GameplayCue的所有者也不同,所以我们要通过所有者和配置项进行删除。
这里我们上面将是否继承战斗接口的布尔值给保存了下来,如果继承,就从敌人身上删除,如果不是,我们将从所有者身上删除。
在这里插入图片描述
接着,我们修改GC,在GC里,我们在While Active里首先从配置项里获取到所需的资源。
在这里插入图片描述
然后我们生成粒子系统
在这里插入图片描述
接着对SourceObject进行判断,在技能里,如果目标是敌人,SourceObject就是敌人,如果不是它就没有继承战斗接口,我们可以以此为依据,来设置闪电链特效的终点位置。
在这里插入图片描述
至此,完成了对目标的修改。运行查看,如果攻击到目标,闪电链能准确的攻击敌人的位置
在这里插入图片描述

实现获取附近最近的几个目标

要实现闪电链,我们要获取到攻击目标最近的几个目标,然后再生成闪电链,所以,我们要增加一个函数来获取。
我们增加一个蓝图可调用函数,来获取返回获取到的目标

	/*** 通过技能命中目标获取扩散的敌人目标* @param OutAdditionalTargets 返回获取到的最近的目标数组*/UFUNCTION(BlueprintCallable)void StoreAdditionalTargets(TArray<AActor*>& OutAdditionalTargets);

定义闪电链最多可以攻击的敌人数量

	UPROPERTY(EditDefaultsOnly, Category="FireBolt")int32 MaxNumShockTargets = 5; //最大散射的闪电链数

我们在函数里,通过内置函数,来获取范围内的所有目标,然后再遍历这些目标,获取到最近的几个,这里我设置的调试代码

void URPGBeamSpell::StoreAdditionalTargets(TArray<AActor*>& OutAdditionalTargets)
{TArray<AActor*> ActorsToIgnore; //遍历时忽略的数组ActorsToIgnore.Add(GetAvatarActorFromActorInfo()); //忽略自身ActorsToIgnore.Add(MouseHitActor); //忽略鼠标命中的的敌人TArray<AActor*> OverlappingActors; //存放遍历结果的数组//通过封装的函数获取到技能范围内散射的目标URPGAbilitySystemLibrary::GetLivePlayersWithinRadius(GetAvatarActorFromActorInfo(),OverlappingActors,ActorsToIgnore,850.f,MouseHitActor->GetActorLocation());//int32 NumAdditionalTargets = FMath::Min(GetAbilityLevel() - 1, MaxNumShockTargets);int32 NumAdditionalTargets = 5;//通过自定义函数来获取最近的几个目标URPGAbilitySystemLibrary::GetClosestTargets(NumAdditionalTargets, OverlappingActors, OutAdditionalTargets, MouseHitActor->GetActorLocation());
}

获取最近目标的函数是我封装在函数库里的函数

	/*** 获取距离目标位置最近的几个目标* @param MaxTargets 获取最大目标的数量* @param Actors 需要计算的目标数组* @param OutClosestTargets 返回获取到的最近的目标* @param Origin 计算的位置*/UFUNCTION(BlueprintCallable, Category="RPGAbilitySystemLibrary|GameplayMechanics")static void GetClosestTargets(int32 MaxTargets, const TArray<AActor*>& Actors, TArray<AActor*>& OutClosestTargets, const FVector& Origin);

它通过使用一个while循环,直到获取到所有的所需的目标停止

void URPGAbilitySystemLibrary::GetClosestTargets(int32 MaxTargets, const TArray<AActor*>& Actors, TArray<AActor*>& OutClosestTargets, const FVector& Origin)
{//如果数量过于少,直接返回原数组if(Actors.Num() <= MaxTargets){OutClosestTargets = Actors;return;}TArray<AActor*> ActorsToCheck = Actors; //没有引用就是复制,复制一份用于遍历int32 NumTargetFound = 0; //当前已经遍历出最近距离的个数//循环遍历,直到获得足够数量的目标时停止while (NumTargetFound < MaxTargets){if(ActorsToCheck.Num() == 0) break; //如果没有可遍历内容,将跳出循环double ClosestDistance = TNumericLimits<double>::Max(); //记录中心于目标的位置,如果有更小的将被替换,默认是最大AActor* ClosestActor; //缓存当前最近距离的目标for(AActor* PotentialTarget : ActorsToCheck){//获取目标和中心的距离const double Distance = (PotentialTarget->GetActorLocation() - Origin).Length();//比对当前计算的位置是否小于缓存的位置if(Distance < ClosestDistance){//如果小于,将替换对应信息ClosestDistance = Distance;ClosestActor = PotentialTarget;}}ActorsToCheck.Remove(ClosestActor); //从遍历数组中删除缓存的对象OutClosestTargets.AddUnique(ClosestActor); //添加到返回的数组中++ NumTargetFound; //递增数量}
}

接着,我们编译打开蓝图,在技能结束时,通过节点获取附近的目标,并打印它的位置
在这里插入图片描述
正确显示
在这里插入图片描述
接着,我们在结束时,打印拾取的范围,并增加敌人数量
在这里插入图片描述
然后查看是否能够正确查找到目标
在这里插入图片描述

实现闪电弧效果

我们先实现闪电链的第一形态,闪电弧,在生成闪电链的函数里,我们设置完成命中目标的以后,先对命中目标判断,如果命中的是场景,将不实现扩散效果。然后去获取最近的几个目标,生成扩展的链
在这里插入图片描述

AddShockLoopCueToAdditionalTarget函数是我们将获取的每个目标生成和命中目标的一条闪电链,在节点函数里,我们创建一个Map将目标和配置项存储起来,方便技能结束时清除
在这里插入图片描述
在函数里,我们将创建配置项,并添加到映射中,并生成GameplayCue
在这里插入图片描述
在技能结束之前,我们将通过目标和配置项将GameplayCue清除,并在最后清空Map映射
在这里插入图片描述
RemoveAdditionalCue函数里,我们用到了之前保存的数组,并在Map映射里找到对应的配置项,进行清除。
在这里插入图片描述
接着运行查看效果,发现攻击到敌人时,能够正确生成闪电弧
在这里插入图片描述
在攻击地面时,也能正确表现
在这里插入图片描述

设置伤害和消耗冷却

我们实现了闪电弧的效果,接下来,我们将设置技能的相关伤害,技能蓝量消耗和冷却
首先我们在技能伤害数据表里增加一条闪电链的伤害
在这里插入图片描述
设置到技能上,并设置好伤害类型
在这里插入图片描述
然后创建两个GameplayEffect
在这里插入图片描述
设置给技能
在这里插入图片描述
在消耗这里,我们设置修改蓝量消耗,并设置对应的表格对蓝量进行消耗
在这里插入图片描述
在表格中增加不同等级的蓝量消耗
在这里插入图片描述
添加对应的冷却标签
在这里插入图片描述
这个标签在激活技能时,应用到释放者身上。
在这里插入图片描述

处理消耗冷却和角色死亡时的bug

接下来,我们要实现正确触发技能冷却,并在每次造成伤害时,扣除角色的蓝量。并在目标死亡时,让特效也能够正常显示。我们将在技能的类里,增加两个回调,可以监听角色在死亡时,对不同的角色死亡进行处理。
我们之前实现了对角色死亡时,会触发死亡委托,在释放技能时,我们绑定对应的委托即可。
在这里插入图片描述
然后在RPGBeamSpell中,增加两个函数回调,在蓝图里可以去实现对应的函数,为什么区分两个函数,因为鼠标命中的主要敌人死亡后,无法将技能分散出去,而额外的角色死亡,我们只需要将其相关的处理即可。

	/*** 鼠标命中的敌人死亡处理* @param DeadActor 命中敌人*/UFUNCTION(BlueprintImplementableEvent)void PrimaryTargetDied(AActor* DeadActor);/*** 额外的敌人死亡处理* @param DeadActor 额外敌人 */UFUNCTION(BlueprintImplementableEvent)void AdditionalTargetDied(AActor* DeadActor);

然后在技能命中的第一个角色身上,我们绑定主要角色的死亡回调,这里时通过战斗接口判断,并判断当前是否绑定了对应的
在这里插入图片描述
额外的目标逻辑相同,一样绑定对应的死亡回调
在这里插入图片描述
我们还需要增加一个技能结束时,取消绑定,因为技能结束后,不能再进行对应的函数回调触发。我们增加一个函数,由于额外的目标没有保存,我们调用时需要传入额外的目标

	/*** 技能结束时调用*/UFUNCTION(BlueprintCallable)void OnEndAbility(TArray<AActor*> AdditionalTargets);

在函数里,我们实现对主要目标和额外的目标的死亡委托的取消绑定

void URPGBeamSpell::OnEndAbility(TArray<AActor*> AdditionalTargets)
{//取消主要目标的死亡回调if(ICombatInterface* CombatInterface = Cast<ICombatInterface>(MouseHitActor)){CombatInterface->GetOnDeathDelegate().RemoveDynamic(this, &URPGBeamSpell::PrimaryTargetDied);}//取消额外目标的死亡回调for(AActor* TargetActor : AdditionalTargets){if(ICombatInterface* CombatInterface = Cast<ICombatInterface>(TargetActor)){CombatInterface->GetOnDeathDelegate().RemoveDynamic(this, &URPGBeamSpell::AdditionalTargetDied);}}
}

我们在蓝图中实现对应目标死亡回调,主要目标死亡,我们直接结束技能
在这里插入图片描述
在额外目标死亡时,我们清除对应的表现效果即可,目标死亡后,将无法对其角色进行应用GE
在这里插入图片描述
完成以后,我们将修改闪电链的蓝图。
在触发闪电链时,我们增加对目标是否已死亡的判断,如果角色已经死亡,将结束技能,场景的目标则没有这个问题。如果目标没有死亡,我们将在技能持续阶段,通过定时器,在一定时间一直造成伤害。
在这里插入图片描述
在应用伤害时,分别对主要目标和额外目标进行调用
在这里插入图片描述
然后通过创建GE实例应用给目标,这里对ASC判断,是因为有时目标的ASC不存在会报错。
在这里插入图片描述
接下来就是技能结束时,我们需要设置技能进入冷却,并清除定时器
在这里插入图片描述
在函数PrepareToEndAbility中,我们将角色设置为可移动,并取消角色死亡绑定(要不然技能结束,目标死亡时,也会触发对应回调),并将目标身上的GameplayCue给清除,清除效果表现,并将对应数组清空。
在这里插入图片描述

实现技能延迟结束

如果我们直接释放技能并松开时,技能还没有播放就结束,所以,这里我们将实现保证技能最短时间,在技能播放完成攻击并播放特效后结束。
所以,我们增加一个变量,来设置技能最小执行时间
在这里插入图片描述
然后在技能释放健抬起时,我们能够获取到抬起时间,通过和最小时间比对,如果时间没到,我们将延迟到最小时间,再结束技能。
在这里插入图片描述

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

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

相关文章

cnn突破四(生成卷积核与固定核对比)

cnn突破三中生成四个卷积核&#xff0c;训练6万次&#xff0c;91分&#xff0c;再训练6万次&#xff0c;95分&#xff0c;不是很满意&#xff0c;但又找不到问题点&#xff0c;所以就想了个办法&#xff0c;使用三个固定核&#xff0c;加上三层bpnet神经网络&#xff0c;看看效…

双十一狂欢派对 五款市面上获得好评的好物

一年一度的双十一购物狂欢派对即将到来&#xff0c;这一天不仅是广大消费者的福利日&#xff0c;也是各大品牌展示实力的战场。随着市场的不断发展与消费者需求的多样化&#xff0c;双十一已经不仅仅是降价促销的代名词&#xff0c;更是品质与创新的竞技场。在琳琅满目的商品中…

产品经理产出的原型设计 - 需求文档应该怎么制作?

需求文档&#xff0c;产品经理最终产出的文档&#xff0c;也是产品设计最终的表述形式。本次分享呢&#xff0c;就是介绍如何写好一份需求文档。 所有元件均可复用&#xff0c;可作为管理端原型设计模板&#xff0c;按照实际项目需求进行功能拓展。有需要的话可分享源文件。 …

ChatGPT Canvas:交互式对话编辑器

自两年前 ChatGPT 发布以来&#xff0c;主流 AI 均以对话形式进行交互。传统的对话式界面可以直观看到反馈结果&#xff0c;但在需要深度编辑和协作的项目中就略显局限。为了解决此问题&#xff0c;几个月前 Claude 就发布过 Artifacts 功能&#xff0c;用来拓展原有对话。而现…

django华业社区电子政务管理系统-计算机毕业设计源码33448

目录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 系统总体设…

【Java】Java面试题笔试

[赠送]面试视频指导简历面试题 Java面试笔试题题库华为 java笔试面试题2014.files 就业相关java 面试题 面试题库 视频笔记 java笔试题大集合及答案 java面试书籍源码 java算法大全源码包8张图解 java.docx25个经典的Spring面试问答.docx 25个经典的Spring面试问答.docx 100家大…

【hot100-java】【删除链表的倒数第 N 个结点】

链表篇 思路&#xff1a; 先走一遍记录链表长度 再走到对应的点&#xff0c;然后删除 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode…

【LLM】OpenAI o1模型和相关技术

Note OpenAI o1 模型中推理过程的工作原理 1、o1模型引入了reasoning tokens。这些token用于"思考"&#xff0c;帮助模型分解对提示的理解&#xff0c;并考虑生成回应的多种方法。2、在生成推理token后&#xff0c;模型会产生一个可见的完成token作为答案&#xff0…

Redis:zset类型

Redis&#xff1a;zset类型 zset命令ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZREVRANGEBYSCOREZPOPMAXBZPOPMAXZPOPMINBZPOPMINZRANKZREVRANKZSCOREZREMZREMRANGEBYRANKZREMRANGEBYSCOREZINCRBY 集合间操作ZINRERSTOREZUNIONSTORE 内部编码ziplistskiplist 在Redis中&…

【AIGC】ChatGPT提示词Prompt助力自媒体内容创作升级

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;高效仿写专家级文章提示词使用方法 &#x1f4af;CSDN博主账号分析提示词使用方法 &#x1f4af;自媒体爆款文案优化助手提示词使用方法 &#x1f4af;小结 &#x1f4af…

02基础篇:667的大题题型与应对策略

通过本节&#xff0c;你将学习到&#xff1a; 667分析题的考查方向与基本题型667分析题的两种解决策略 667分析题的三大基本题型 首先&#xff0c;通过回顾667科目分析题的真题&#xff08;2021-2024年&#xff09;&#xff0c;我根据题目特点将其归纳为三个主要类别。这样的…

【JavaWeb】javaweb目录结构简介【转】

以上图说明&#xff1a; bbs目录代表一个web应用bbs目录下的html,jsp文件可以直接被浏览器访问WEB-INF目录下的资源是不能直接被浏览器访问的web.xml文件是web程序的主要配置文件所有的classes文件都放在classes目录下jar文件放在lib目录下

Linux Cent7 已安装MySQL5.7.X,再安装MYSQL8.4.2

一、 下载安装 检查Linux系统的glibc版本rpm -qa | grep glibc结果&#xff1a;glibc-common-2.17-260.el7_6.6.x86_64 glibc-2.17-260.el7_6.6.x86_64 glibc-headers-2.17-260.el7_6.6.x86_64 glibc-devel-2.17-260.el7_6.6.x86_64访问MySQL官网&#xff0c;下载对应版本数据…

华为 HCIP-Datacom H12-821 题库 (32)

&#x1f423;博客最下方微信公众号回复题库,领取题库和教学资源 &#x1f424;诚挚欢迎IT交流有兴趣的公众号回复交流群 &#x1f998;公众号会持续更新网络小知识&#x1f63c; 1.当一个运行 MSTP 协议的交换设备端口收到一个配置BPDU 时&#xff0c;会与设备保存的全局配…

CF D. Minimize the Difference

原题链接&#xff1a;Problem - D - Codeforces 题意&#xff1a;给你长度为n的数组&#xff0c;可以无限次的让i位置的数-1&#xff0c;让i1的位置的数1。问最大值-最小值的最小值是多少&#xff1f; 思路&#xff1a;可以观察出&#xff0c;操作的真正意义是让i位置的数减少…

数字乡村智慧乡镇整体规划设计解决方案

1. 数字乡村的重要性 数字乡镇作为乡村振兴战略的一部分&#xff0c;通过信息化手段提高农业农村现代化水平&#xff0c;是建设数字中国的重要内容&#xff0c;对保障扶贫成果、促进乡村治理体系和治理能力现代化具有基础支撑作用。 2. 乡镇政府和农户面临的问题 乡镇政府和…

Linux 之 安装软件、GCC编译器、Linux 操作系统基础

安装软件、GCC编译器、Linux 操作系统基础 学习任务&#xff1a; 安装 Vmware虚拟机、掌握Ubuntu 系统的使用认识 Ubuntu 操作系统的终端和 Shell掌握软件安装、文件系统、掌握磁盘管理与解压缩掌握 VIM 编辑器、Makefile 基本语法熟悉 Linux 常见指令操作 安装好开发软件&…

电源管理芯片PMIC

一、简介 电源管理芯片&#xff08;Power Management Integrated Circuits&#xff0c;简称PMIC&#xff09;是一种集成电路&#xff0c;它的主要功能是在电子设备系统中对电能进行管理和控制&#xff0c;包括但不限于以下几点&#xff1a; 电压转换&#xff1a;将电源电压转换…

IndexTree、AC自动机

一、引言。 IndexTree和线段树有一些联系&#xff0c;这里我们再重新解释一下线段树用来解决什么样的一个问题&#xff0c;线段树解决的是一个区间查询和区间更新的一个问题&#xff0c;比如说我有一个数组在 L....R 上统一加上V&#xff0c;或者在L.....R上&#xff0c;统一所…

硬件设计-利用环路设计优化PLL的输出性能

目录 前言 问题描述 问题分析步骤 杂散源头排查 245.76M 参考相噪&#xff1a; 30.72M VCXO的相噪性能测试如下: 解决方案 前言 LMK04832是TI 新发布的低抖动双环去抖模拟时钟&#xff0c; 其最高输出频率可以到达3250MHz&#xff0c; 输出抖动极低&#xff0c;3200MHz…