当前位置: 首页 > news >正文

UE5多人MOBA+GAS 21、给升龙添加连段攻击,从角色的按下事件中传递事件给GA

文章目录

  • 给升龙制作可连段
    • 缓存下一连段
    • 用普攻键来触发升龙后续的连段
      • 在角色中发送按下普攻标签事件
      • 在升龙中接收按下事件,触发连段以及伤害和力量的传递
    • 最后在蓝图中设置一下
  • 升龙技能的完整代码


给升龙制作可连段

给升龙技能添加一些连段
在这里插入图片描述

缓存下一连段

缓存下一连段的名称

	// 处理连招阶段切换事件UFUNCTION()void HandleComboChangeEvent(FGameplayEventData EventData);// 下一个连招阶段的名称FName NextComboName;
UUpperCut::UUpperCut()
{// 阻止带有Ability_BasicAttack标签的技能激活BlockAbilitiesWithTag.AddTag(TGameplayTags::Ability_BasicAttack);
}void UUpperCut::StartLaunching(FGameplayEventData EventData)
{if (K2_HasAuthority()){// 推动自己向上PushTarget(GetAvatarActorFromActorInfo(), FVector::UpVector * UpperCutLaunchSpeed);// 获取命中目标的数量int HitResultCount = UAbilitySystemBlueprintLibrary::GetDataCountFromTargetData(EventData.TargetData);// 对所有命中的目标执行击飞和伤害for (int i = 0; i < HitResultCount; i++){FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(EventData.TargetData, i);PushTarget(HitResult.GetActor(), FVector::UpVector * UpperCutLaunchSpeed);ApplyGameplayEffectToHitResultActor(HitResult, LaunchDamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));}}// 监听连招切换、提交、伤害等事件UAbilityTask_WaitGameplayEvent* WaitComboChangeEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_Combo_Change, nullptr, false, false);WaitComboChangeEvent->EventReceived.AddDynamic(this, &UUpperCut::HandleComboChangeEvent);WaitComboChangeEvent->ReadyForActivation();
}
void UUpperCut::HandleComboChangeEvent(FGameplayEventData EventData)
{// 获取事件标签FGameplayTag EventTag = EventData.EventTag;if (EventTag == TGameplayTags::Ability_Combo_Change_End){// 下一个连招名称置空NextComboName = NAME_None;UE_LOG(LogTemp, Warning, TEXT("清除连招"))return;}// 获取下一个连段的名称TArray<FName> TagNames;UGameplayTagsManager::Get().SplitGameplayTagFName(EventTag, TagNames);// Tag最后一段的名称比如Combo02,03,04等NextComboName = TagNames.Last();UE_LOG(LogTemp, Warning, TEXT("下一个Combo:%s"), *NextComboName.ToString())
}

用普攻键来触发升龙后续的连段

主要就是升龙期间,阻止普通技能的触发,在升龙添加阻挡标签的目的就是这个,然后需要在角色中发送按键按下事件,让升龙GA接收,然后触发切换到下一个蒙太奇。

在角色中发送按下普攻标签事件

添加两个Tag,用来将普攻按下和抬起的信息发送出去

	// 按下普通攻击CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Ability_BasicAttack_Pressed)// 抬起CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Ability_BasicAttack_Released)
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Ability_BasicAttack_Pressed, "Ability.BasicAttack.Pressed", "按下普通攻击")UE_DEFINE_GAMEPLAY_TAG_COMMENT(Ability_BasicAttack_Released, "Ability.BasicAttack.Released", "释放普通攻击键")	

因为角色的输入只是发生在客户端,服务器并不知道角色的输入,因此在CCharacter中创建服务器发送事件

#pragma region GAS组件相关
public:virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;// 在服务器端向自身发送游戏事件UFUNCTION(Server, Reliable, WithValidation)void Server_SendGameplayEventToSelf(const FGameplayTag& EventTag, const FGameplayEventData& EventData);
void ACCharacter::Server_SendGameplayEventToSelf_Implementation(const FGameplayTag& EventTag,const FGameplayEventData& EventData)
{UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(this, EventTag, EventData);
}/*** @brief 验证在服务器端向自身发送游戏事件的操作是否有效*/
bool ACCharacter::Server_SendGameplayEventToSelf_Validate(const FGameplayTag& EventTag,const FGameplayEventData& EventData)
{// 返回 true,表示操作有效return true;
}

在玩家角色CPlayerCharacter输入中检测按键的按下,发送游戏事件

void ACPlayerCharacter::HandleAbilityInput(const FInputActionValue& InputActionValue, ECAbilityInputID InputID)
{bool bPressed = InputActionValue.Get<bool>();// 按下if (bPressed){GetAbilitySystemComponent()->AbilityLocalInputPressed(static_cast<int32>(InputID));}else{GetAbilitySystemComponent()->AbilityLocalInputReleased(static_cast<int32>(InputID));}// 按下的是普攻键if (InputID == ECAbilityInputID::BasicAttack){FGameplayTag BasicAttackTag = bPressed ? TGameplayTags::Ability_BasicAttack_Pressed : TGameplayTags::Ability_BasicAttack_Released;// 1. 本地直接广播(触发客户端即时反馈)// 2. 服务器RPC广播(确保权威状态同步)UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(this, BasicAttackTag, FGameplayEventData());Server_SendGameplayEventToSelf(BasicAttackTag, FGameplayEventData());}
}

在升龙中接收按下事件,触发连段以及伤害和力量的传递

CGameplayAbilityTypes创建一个伤害效果的结构体,用来存储GE以及触发的力度大小

// 伤害效果定义
USTRUCT(BlueprintType)
struct FGenericDamageEffectDef
{GENERATED_BODY()public:FGenericDamageEffectDef();UPROPERTY(EditAnywhere)TSubclassOf<UGameplayEffect> DamageEffect;UPROPERTY(EditAnywhere)FVector PushVelocity;
};
FGenericDamageEffectDef::FGenericDamageEffectDef():DamageEffect{nullptr},PushVelocity{0.f}
{
}

回到升龙函数中补全代码,像之前做Combo一样,设置下一个蒙太奇片段,获取当前片段的伤害,在应用伤害的时候,保持一下自己也在空中,对方也在空中,所有创建了上面的这个结构体。

private:// 连招阶段对应的伤害效果定义表UPROPERTY(EditDefaultsOnly, Category = "Combo")TMap<FName, FGenericDamageEffectDef> ComboDamageMap;// 空中连招的力UPROPERTY(EditDefaultsOnly, Category = "Launch")float UpperComboHoldSpeed = 100.f;// 获取当前连招阶段的伤害效果定义const FGenericDamageEffectDef* GetDamageEffectDefForCurrentCombo() const;// 处理连招提交事件UFUNCTION()void HandleComboCommitEvent(FGameplayEventData EventData);// 处理连招伤害事件UFUNCTION()void HandleComboDamageEvent(FGameplayEventData EventData);
const FGenericDamageEffectDef* UUpperCut::GetDamageEffectDefForCurrentCombo() const
{UAnimInstance* OwnerAnimInstance = GetOwnerAnimInstance();if (OwnerAnimInstance){// 获取当前片段名称FName CurrentComboName = OwnerAnimInstance->Montage_GetCurrentSection(UpperCutMontage);// 获取当前片段对应的伤害效果const FGenericDamageEffectDef* EffectDef = ComboDamageMap.Find(CurrentComboName);if (EffectDef){return EffectDef;}}// 没找到返回一个空结构return nullptr;
}void UUpperCut::StartLaunching(FGameplayEventData EventData)
{if (K2_HasAuthority()){// 推动自己向上PushTarget(GetAvatarActorFromActorInfo(), FVector::UpVector * UpperCutLaunchSpeed);// 获取命中目标的数量int HitResultCount = UAbilitySystemBlueprintLibrary::GetDataCountFromTargetData(EventData.TargetData);// 对所有命中的目标执行击飞和伤害for (int i = 0; i < HitResultCount; i++){FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(EventData.TargetData, i);PushTarget(HitResult.GetActor(), FVector::UpVector * UpperCutLaunchSpeed);ApplyGameplayEffectToHitResultActor(HitResult, LaunchDamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));}}// 监听连招切换、提交、伤害等事件UAbilityTask_WaitGameplayEvent* WaitComboChangeEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_Combo_Change, nullptr, false, false);WaitComboChangeEvent->EventReceived.AddDynamic(this, &UUpperCut::HandleComboChangeEvent);WaitComboChangeEvent->ReadyForActivation();UAbilityTask_WaitGameplayEvent* WaitComboCommitEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_BasicAttack_Pressed);WaitComboCommitEvent->EventReceived.AddDynamic(this, &UUpperCut::HandleComboCommitEvent);WaitComboCommitEvent->ReadyForActivation();UAbilityTask_WaitGameplayEvent* WaitComboDamageEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_Combo_Damage);WaitComboDamageEvent->EventReceived.AddDynamic(this, &UUpperCut::HandleComboDamageEvent);WaitComboDamageEvent->ReadyForActivation();
}void UUpperCut::HandleComboCommitEvent(FGameplayEventData EventData)
{// 按晚了if (NextComboName == NAME_None) return;UAnimInstance* OwnerAnimInstance = GetOwnerAnimInstance();if (!OwnerAnimInstance) return;OwnerAnimInstance->Montage_SetNextSection(OwnerAnimInstance->Montage_GetCurrentSection(UpperCutMontage), NextComboName, UpperCutMontage);
}void UUpperCut::HandleComboDamageEvent(FGameplayEventData EventData)
{if (K2_HasAuthority()){// 击飞一下自己,免得掉下去了PushTarget(GetAvatarActorFromActorInfo(), FVector::UpVector * UpperComboHoldSpeed);// 获取当前片段对应的伤害效果const FGenericDamageEffectDef* EffectDef = GetDamageEffectDefForCurrentCombo();if (!EffectDef){return;}int HitResultCount = UAbilitySystemBlueprintLibrary::GetDataCountFromTargetData(EventData.TargetData);for (int32 i = 0; i < HitResultCount; i++){FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(EventData.TargetData, i);// 计算推力方向(根据自身朝向变换推力向量)FVector PushVel = GetAvatarActorFromActorInfo()->GetActorTransform().TransformVector(EffectDef->PushVelocity);// 推动目标PushTarget(HitResult.GetActor(), PushVel);// 对目标应用伤害效果ApplyGameplayEffectToHitResultActor(HitResult, EffectDef->DamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));}}
}

最后在蓝图中设置一下

修正一下
在这里插入图片描述
添加一些Combo以及End,还有伤害的传递
在这里插入图片描述
创建Combo的GE,复制GE_UpperCut_Launch_Damage改一下数字
在这里插入图片描述
以及最后击的GE
在这里插入图片描述
最后放进GA的Map里
在这里插入图片描述
注释掉这两个,关闭运动似乎会让尸体在空中滞留(不确定,反正这个也没啥用了)
在这里插入图片描述

升龙技能的完整代码

// 幻雨喜欢小猫咪#pragma once#include "CoreMinimal.h"
#include "GAS/Core/CGameplayAbility.h"
#include "GAS/Core/CGameplayAbilityTypes.h"
#include "UpperCut.generated.h"/*** */
UCLASS()
class CRUNCH_API UUpperCut : public UCGameplayAbility
{GENERATED_BODY()
public:	UUpperCut();// TODO: 可能在这里添加手动结束任务的逻辑// virtual void K2_EndAbility() override;// 激活技能时调用virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
private:// 连招阶段对应的伤害效果定义表UPROPERTY(EditDefaultsOnly, Category = "Combo")TMap<FName, FGenericDamageEffectDef> ComboDamageMap;// 上勾拳击飞阶段的伤害效果UPROPERTY(EditDefaultsOnly, Category = "Launch")TSubclassOf<UGameplayEffect> LaunchDamageEffect;// 上勾拳击飞速度UPROPERTY(EditDefaultsOnly, Category = "Launch", meta = (DisplayName = "击飞力的大小"))float UpperCutLaunchSpeed = 1000.f;// 空中连招的力UPROPERTY(EditDefaultsOnly, Category = "Launch")float UpperComboHoldSpeed = 100.f;// 上勾拳动画MontageUPROPERTY(EditDefaultsOnly, Category = "Animation")TObjectPtr<UAnimMontage> UpperCutMontage;// 获取当前连招阶段的伤害效果定义const FGenericDamageEffectDef* GetDamageEffectDefForCurrentCombo() const;// 启动击飞效果UFUNCTION()void StartLaunching(FGameplayEventData EventData);// 处理连招阶段切换事件UFUNCTION()void HandleComboChangeEvent(FGameplayEventData EventData);// 处理连招提交事件UFUNCTION()void HandleComboCommitEvent(FGameplayEventData EventData);// 处理连招伤害事件UFUNCTION()void HandleComboDamageEvent(FGameplayEventData EventData);// 下一个连招阶段的名称FName NextComboName;
};
// 幻雨喜欢小猫咪#include "UpperCut.h"#include "AbilitySystemBlueprintLibrary.h"
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
#include "Abilities/Tasks/AbilityTask_WaitGameplayEvent.h"
#include "GAS/Core/TGameplayTags.h"UUpperCut::UUpperCut()
{// 阻止带有Ability_BasicAttack标签的技能激活BlockAbilitiesWithTag.AddTag(TGameplayTags::Ability_BasicAttack);
}void UUpperCut::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{if (!K2_CommitAbility()){K2_EndAbility();return;}// 服务器执行if (HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo)){UAbilityTask_PlayMontageAndWait* PlayUpperCutMontageTask = UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(this, NAME_None, UpperCutMontage);PlayUpperCutMontageTask->OnBlendOut.AddDynamic(this, &UUpperCut::K2_EndAbility);PlayUpperCutMontageTask->OnCancelled.AddDynamic(this, &UUpperCut::K2_EndAbility);PlayUpperCutMontageTask->OnCompleted.AddDynamic(this, &UUpperCut::K2_EndAbility);PlayUpperCutMontageTask->OnInterrupted.AddDynamic(this, &UUpperCut::K2_EndAbility);PlayUpperCutMontageTask->ReadyForActivation();UAbilityTask_WaitGameplayEvent* WaitLaunchEventTask = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_Uppercut_Launch);WaitLaunchEventTask->EventReceived.AddDynamic(this, &UUpperCut::StartLaunching);WaitLaunchEventTask->ReadyForActivation();}NextComboName = NAME_None;
}const FGenericDamageEffectDef* UUpperCut::GetDamageEffectDefForCurrentCombo() const
{UAnimInstance* OwnerAnimInstance = GetOwnerAnimInstance();if (OwnerAnimInstance){// 获取当前片段名称FName CurrentComboName = OwnerAnimInstance->Montage_GetCurrentSection(UpperCutMontage);// 获取当前片段对应的伤害效果const FGenericDamageEffectDef* EffectDef = ComboDamageMap.Find(CurrentComboName);if (EffectDef){return EffectDef;}}// 没找到返回一个空结构return nullptr;
}void UUpperCut::StartLaunching(FGameplayEventData EventData)
{if (K2_HasAuthority()){// 推动自己向上PushTarget(GetAvatarActorFromActorInfo(), FVector::UpVector * UpperCutLaunchSpeed);// 获取命中目标的数量int HitResultCount = UAbilitySystemBlueprintLibrary::GetDataCountFromTargetData(EventData.TargetData);// 对所有命中的目标执行击飞和伤害for (int i = 0; i < HitResultCount; i++){FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(EventData.TargetData, i);PushTarget(HitResult.GetActor(), FVector::UpVector * UpperCutLaunchSpeed);ApplyGameplayEffectToHitResultActor(HitResult, LaunchDamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));}}// 监听连招切换、提交、伤害等事件UAbilityTask_WaitGameplayEvent* WaitComboChangeEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_Combo_Change, nullptr, false, false);WaitComboChangeEvent->EventReceived.AddDynamic(this, &UUpperCut::HandleComboChangeEvent);WaitComboChangeEvent->ReadyForActivation();UAbilityTask_WaitGameplayEvent* WaitComboCommitEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_BasicAttack_Pressed);WaitComboCommitEvent->EventReceived.AddDynamic(this, &UUpperCut::HandleComboCommitEvent);WaitComboCommitEvent->ReadyForActivation();UAbilityTask_WaitGameplayEvent* WaitComboDamageEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_Combo_Damage);WaitComboDamageEvent->EventReceived.AddDynamic(this, &UUpperCut::HandleComboDamageEvent);WaitComboDamageEvent->ReadyForActivation();
}void UUpperCut::HandleComboChangeEvent(FGameplayEventData EventData)
{// 获取事件标签FGameplayTag EventTag = EventData.EventTag;if (EventTag == TGameplayTags::Ability_Combo_Change_End){// 下一个连招名称置空NextComboName = NAME_None;UE_LOG(LogTemp, Warning, TEXT("清除连招"))return;}// 获取下一个连段的名称TArray<FName> TagNames;UGameplayTagsManager::Get().SplitGameplayTagFName(EventTag, TagNames);// Tag最后一段的名称比如Combo02,03,04等NextComboName = TagNames.Last();UE_LOG(LogTemp, Warning, TEXT("下一个Combo:%s"), *NextComboName.ToString())
}void UUpperCut::HandleComboCommitEvent(FGameplayEventData EventData)
{// 按晚了if (NextComboName == NAME_None) return;UAnimInstance* OwnerAnimInstance = GetOwnerAnimInstance();if (!OwnerAnimInstance) return;OwnerAnimInstance->Montage_SetNextSection(OwnerAnimInstance->Montage_GetCurrentSection(UpperCutMontage), NextComboName, UpperCutMontage);UE_LOG(LogTemp, Warning, TEXT("触发连招:%s"), *NextComboName.ToString())
}void UUpperCut::HandleComboDamageEvent(FGameplayEventData EventData)
{if (K2_HasAuthority()){// 击飞一下自己,免得掉下去了PushTarget(GetAvatarActorFromActorInfo(), FVector::UpVector * UpperComboHoldSpeed);// 获取当前片段对应的伤害效果const FGenericDamageEffectDef* EffectDef = GetDamageEffectDefForCurrentCombo();if (!EffectDef){return;}int HitResultCount = UAbilitySystemBlueprintLibrary::GetDataCountFromTargetData(EventData.TargetData);for (int32 i = 0; i < HitResultCount; i++){FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(EventData.TargetData, i);// 计算推力方向(根据自身朝向变换推力向量)FVector PushVel = GetAvatarActorFromActorInfo()->GetActorTransform().TransformVector(EffectDef->PushVelocity);// 推动目标PushTarget(HitResult.GetActor(), PushVel);// 对目标应用伤害效果ApplyGameplayEffectToHitResultActor(HitResult, EffectDef->DamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));}}
}
http://www.dtcms.com/a/276861.html

相关文章:

  • Action-Agnostic Point-Level Supervision for Temporal Action Detection
  • 一扇门铃,万向感应——用 eventfd 实现零延迟通信
  • QCustomPlot绘图保存成PDF文件
  • 网络安全的基本练习
  • 北京-4年功能测试2年空窗-报培训班学测开-第四十九天
  • 行测速算之假设分配法
  • ROS2中的QoS(Quality of Service)详解
  • v-show和v-if的区别
  • 算法复杂度分析:大O表示法详解
  • 婚后才明白,原来结婚真需要一点冲动!
  • 编程与数学 03-001 计算机组成原理 04_非数值数据表示与校验码
  • 解码冯・诺依曼:操作系统是如何为进程 “铺路” 的?
  • 002_Claude模型与定价
  • java进阶(二)+学习笔记
  • Qt 3D模块加载复杂模型
  • Cesium初探-CallbackProperty
  • 开发语言中关于面向对象和面向过程的笔记
  • 打造你的专属智能生活:鸿蒙系统自定义场景开发全流程详解
  • VISUALBERT:一个简单且高效的视觉与语言基线模型
  • 微信小程序案例 - 本地生活(首页)
  • 代码随想录|图论|15并查集理论基础
  • 算法学习笔记:18.拉斯维加斯算法 ——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • RFCOMM协议详解:串口仿真与TCP/IP协议栈移植技术——面试高频考点与真题解析
  • 1.2.3_2 TCP/IP模型
  • Java小白-设计模式
  • 动态规划理论基础,LeetCode 509. 斐波那契数
  • 012_PDF处理与文档分析
  • jenkins使用Jenkinsfile部署springboot+docker项目
  • 011_视觉能力与图像处理
  • Docker 搭建本地Harbor私有镜像仓库