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

UE5多人MOBA+GAS 45、制作冲刺技能

文章目录

  • 添加技能需要的东西
    • 添加本地播放GC
    • 添加冲刺tag
    • 添加一个新的TA用于检测敌方单位
  • 添加冲刺GA
    • 到角色中监听加速移动速度的回调
    • 创建蒙太奇
    • 添加GE
    • 添加到数据表中
    • 添加到角色中
  • 纠错


添加技能需要的东西

添加本地播放GC

UCAbilitySystemStatics中添加

	/*** 在本地触发指定的游戏提示效果(如技能特效、攻击反馈等)* * @param CueTargetActor 触发游戏提示的目标Actor(如角色、技能释放者)* @param HitResult 包含命中位置、法线等碰撞信息的结果对象* @param GameplayCueTag 标识游戏提示类型的GameplayTag(如"Ability.Attack.Basic")*/static void SendLocalGameplayCue(AActor* CueTargetActor, const FHitResult& HitResult, const FGameplayTag& GameplayCueTag);
void UCAbilitySystemStatics::SendLocalGameplayCue(AActor* CueTargetActor, const FHitResult& HitResult,const FGameplayTag& GameplayCueTag)
{FGameplayCueParameters CueParams;CueParams.Location = HitResult.ImpactPoint;CueParams.Normal = HitResult.ImpactNormal;UAbilitySystemGlobals::Get().GetGameplayCueManager()->HandleGameplayCue(CueTargetActor, GameplayCueTag, EGameplayCueEvent::Executed, CueParams);
}

添加冲刺tag

	// 冲刺CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Ability_Dash)CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Ability_Dash_Start)CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Ability_Dash_Cooldown)
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(Ability_Dash, "Ability.Dash", "冲刺技能")UE_DEFINE_GAMEPLAY_TAG_COMMENT(Ability_Dash_Start, "Ability.Dash.Start", "冲刺技能开始")UE_DEFINE_GAMEPLAY_TAG_COMMENT(Ability_Dash_Cooldown, "Ability.Dash.Cooldown", "冲刺技能冷却")

添加一个新的TA用于检测敌方单位

TargetActor_Around
在这里插入图片描述

#pragma once#include "CoreMinimal.h"
#include "GenericTeamAgentInterface.h"
#include "Abilities/GameplayAbilityTargetActor.h"
#include "TargetActor_Around.generated.h"class USphereComponent;
/*** 圆形范围目标检测器,用于检测角色周围的敌对目标* 实现队伍关系接口(IGenericTeamAgentInterface)用于敌我识别*/
UCLASS()
class ATargetActor_Around : public AGameplayAbilityTargetActor, public IGenericTeamAgentInterface
{GENERATED_BODY()
public:ATargetActor_Around();// 配置检测参数:检测半径、队伍ID和本地视觉提示标签void ConfigureDetection(float DetectionRadius, const FGenericTeamId& InTeamId, const FGameplayTag& InLocalGameplayCueTag);/** 实现IGenericTeamAgentInterface接口 - 设置队伍ID */virtual void SetGenericTeamId(const FGenericTeamId& NewTeamID) override;/** 实现IGenericTeamAgentInterface接口 - 获取队伍ID */FORCEINLINE virtual FGenericTeamId GetGenericTeamId() const override { return TeamId; }/** 网络属性复制 */virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;private:UPROPERTY(Replicated)FGenericTeamId TeamId; // 当前检测器的队伍ID(用于敌我识别)// 根组件(用于位置定位)UPROPERTY(VisibleDefaultsOnly, Category = "Comp")TObjectPtr<USceneComponent> RootComp;// 球形碰撞体(用于范围检测)UPROPERTY(VisibleDefaultsOnly, Category = "Targeting")TObjectPtr<USphereComponent> DetectionSphere;// 检测半径(网络同步)UPROPERTY(ReplicatedUsing = OnRep_TargetDetectionRadiusReplicated)float TargetDetectionRadius;// 检测半径复制回调(客户端同步时更新碰撞体大小)UFUNCTION()void OnRep_TargetDetectionRadiusReplicated();// 本地视觉提示标签(命中目标时播放的视觉效果)UPROPERTY(Replicated)FGameplayTag LocalGameplayCueTag;// 碰撞体进入检测范围时的回调UFUNCTION()void ActorInDetectionRange(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
};
#include "TargetActor_Around.h"#include "Abilities/GameplayAbility.h"
#include "Components/SphereComponent.h"
#include "GAS/Core/CAbilitySystemStatics.h"
#include "Net/UnrealNetwork.h"// Sets default values
ATargetActor_Around::ATargetActor_Around()
{PrimaryActorTick.bCanEverTick = true;// 网络设置:在服务器和客户端同步bReplicates = true;// 重要:确保服务器能产生目标数据ShouldProduceTargetDataOnServer = true;// 创建根组件RootComp = CreateDefaultSubobject<USceneComponent>("Root Comp");SetRootComponent(RootComp);// 创建球形碰撞体用于范围检测DetectionSphere = CreateDefaultSubobject<USphereComponent>("Detection Sphere");DetectionSphere->SetupAttachment(GetRootComponent());// 配置碰撞设置:只检测Pawn类型的重叠DetectionSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);DetectionSphere->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);// 绑定重叠开始事件回调DetectionSphere->OnComponentBeginOverlap.AddDynamic(this, &ATargetActor_Around::ActorInDetectionRange);}void ATargetActor_Around::ConfigureDetection(float DetectionRadius, const FGenericTeamId& InTeamId,const FGameplayTag& InLocalGameplayCueTag)
{// 设置队伍关系SetGenericTeamId(InTeamId);// 更新碰撞体大小DetectionSphere->SetSphereRadius(DetectionRadius);// 同步到网络变量TargetDetectionRadius = DetectionRadius;// 设置视觉提示标签LocalGameplayCueTag = InLocalGameplayCueTag;
}void ATargetActor_Around::SetGenericTeamId(const FGenericTeamId& NewTeamID)
{TeamId = NewTeamID;
}void ATargetActor_Around::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);// 注册需要网络同步的属性DOREPLIFETIME(ATargetActor_Around, TeamId);					// 队伍IDDOREPLIFETIME(ATargetActor_Around, LocalGameplayCueTag);	// 视觉标签DOREPLIFETIME(ATargetActor_Around, TargetDetectionRadius);	// 检测半径
}void ATargetActor_Around::OnRep_TargetDetectionRadiusReplicated()
{// 客户端收到半径更新时,同步更新碰撞体大小DetectionSphere->SetSphereRadius(TargetDetectionRadius);
}void ATargetActor_Around::ActorInDetectionRange(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{// 忽略无效Actorif (!OtherActor) return;// 获取能力拥有者(避免检测到自己)AActor* AvatarActor = nullptr;if (OwningAbility){AvatarActor = OwningAbility->GetAvatarActorFromActorInfo();}// 忽略自身和拥有者if (OtherActor == AvatarActor) return;if (OtherActor == this) return;// 队伍关系检查:只处理敌对目标if (GetTeamAttitudeTowards(*OtherActor) != ETeamAttitude::Hostile) return;// 服务器处理目标数据if (HasAuthority()){// 构建目标数据FGameplayAbilityTargetDataHandle TargetDataHandle;FGameplayAbilityTargetData_ActorArray* ActorArray = new FGameplayAbilityTargetData_ActorArray;ActorArray->SetActors(TArray<TWeakObjectPtr<AActor>>{OtherActor});TargetDataHandle.Add(ActorArray);// 通知能力系统目标已就绪TargetDataReadyDelegate.Broadcast(TargetDataHandle);}// 播放GC特效FHitResult HitResult;HitResult.ImpactPoint = OtherActor->GetActorLocation();  // 命中点为目标位置HitResult.ImpactNormal = (OtherActor->GetActorLocation() - GetActorLocation()).GetSafeNormal(); // 命中方向UCAbilitySystemStatics::SendLocalGameplayCue(OtherActor, HitResult, LocalGameplayCueTag);
}

添加冲刺GA

GA_Dash
在这里插入图片描述

#pragma once#include "CoreMinimal.h"
#include "GAS/Core/CGameplayAbility.h"
#include "GA_Dash.generated.h"class UCharacterMovementComponent;
/*** 冲刺能力类,使角色能够向目标方向冲刺并对路径上的敌人造成伤害*/
UCLASS()
class CRUNCH_API UGA_Dash : public UCGameplayAbility
{GENERATED_BODY()
public:// 激活能力时调用virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;// 结束能力时调用virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;private:// 冲刺动作的动画蒙太奇UPROPERTY(EditDefaultsOnly, Category = "Anim")TObjectPtr<UAnimMontage> DashMontage;// 目标检测半径(单位:厘米)UPROPERTY(EditDefaultsOnly, Category = "Targeting")float TargetDetectionRadius = 300.f;// 本地游戏提示标签(用于视觉效果)UPROPERTY(EditDefaultsOnly, Category = "GameplayCue")FGameplayTag LocalGameplayCueTag;// 目标检测器附加的骨骼名称UPROPERTY(EditDefaultsOnly, Category = "Targeting")FName TargetActorAttachSocketName = "TargetDashCenter";// 目标检测器类(圆形范围检测)UPROPERTY(EditDefaultsOnly, Category = "Targeting")TSubclassOf<class ATargetActor_Around> TargetActorClass;// 命中目标后的击退速度UPROPERTY(EditDefaultsOnly, Category = "Effects")float TargetHitPushSpeed = 3000.f;// 命中目标时应用的伤害效果UPROPERTY(EditDefaultsOnly, Category = "Effects")FGenericDamageEffectDef DamageEffect;// 冲刺过程中应用的持续效果UPROPERTY(EditDefaultsOnly, Category = "Effects")TSubclassOf<UGameplayEffect> DashEffect;// 当前激活的冲刺效果句柄FActiveGameplayEffectHandle DashEffectHandle;// 推动角色前进的定时器句柄FTimerHandle PushForwardInputTimerHandle;// 推动角色沿当前方向前进void PushForward();// 缓存角色移动组件UPROPERTY()TObjectPtr<UCharacterMovementComponent> OwnerCharacterMovementComponent;// 动画事件触发时开始冲刺逻辑UFUNCTION()void StartDash(FGameplayEventData Payload);// 目标检测完成回调UFUNCTION()void TargetReceived(const FGameplayAbilityTargetDataHandle& TargetDataHandle);
};
#include "GA_Dash.h"#include "AbilitySystemComponent.h"
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
#include "Abilities/Tasks/AbilityTask_WaitGameplayEvent.h"
#include "Abilities/Tasks/AbilityTask_WaitTargetData.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GAS/TA/TargetActor_Around.h"void UGA_Dash::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{// 检查能力是否可提交(资源消耗等)和动画是否有效if (!K2_CommitAbility() || !DashMontage){// 条件不满足则立即结束能力K2_EndAbility();return;}// 确保在服务端或预测有效时执行if (HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo)){// 创建并播放冲刺动画蒙太奇UAbilityTask_PlayMontageAndWait* PlayDashMontage = UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(this, NAME_None, DashMontage);// 绑定动画结束/中断事件到能力结束PlayDashMontage->OnBlendOut.AddDynamic(this, &UGA_Dash::K2_EndAbility);PlayDashMontage->OnCancelled.AddDynamic(this, &UGA_Dash::K2_EndAbility);PlayDashMontage->OnInterrupted.AddDynamic(this, &UGA_Dash::K2_EndAbility);PlayDashMontage->OnCompleted.AddDynamic(this, &UGA_Dash::K2_EndAbility);PlayDashMontage->ReadyForActivation();// 等待动画中的冲刺开始事件UAbilityTask_WaitGameplayEvent* WaitDashStartEvent = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(this, TGameplayTags::Ability_Dash_Start);WaitDashStartEvent->EventReceived.AddDynamic(this, &UGA_Dash::StartDash);WaitDashStartEvent->ReadyForActivation();}
}void UGA_Dash::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
{// 获取能力系统组件UAbilitySystemComponent* OwnerAbilitySystemComponent = GetAbilitySystemComponentFromActorInfo();// 移除冲刺效果if (OwnerAbilitySystemComponent && DashEffectHandle.IsValid()){OwnerAbilitySystemComponent->RemoveActiveGameplayEffect(DashEffectHandle);}// 清除推进定时器if (PushForwardInputTimerHandle.IsValid()){GetWorld()->GetTimerManager().ClearTimer(PushForwardInputTimerHandle);}Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);
}void UGA_Dash::PushForward()
{// 如果存在移动组件,则沿角色前方持续推动if (OwnerCharacterMovementComponent){// 获取角色前方向量FVector ForwardActor = GetAvatarActorFromActorInfo()->GetActorForwardVector();// 添加移动输入OwnerCharacterMovementComponent->AddInputVector(ForwardActor);// 设置下一帧继续推动(循环递归调用)PushForwardInputTimerHandle = GetWorld()->GetTimerManager().SetTimerForNextTick(this, &UGA_Dash::PushForward);}
}void UGA_Dash::StartDash(FGameplayEventData Payload)
{// 在服务端应用冲刺效果if (K2_HasAuthority()){if (DashEffect){DashEffectHandle = BP_ApplyGameplayEffectToOwner(DashEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));}}// 本地控制角色:启动连续推进if (IsLocallyControlled()){// 缓存移动组件OwnerCharacterMovementComponent = GetAvatarActorFromActorInfo()->GetComponentByClass<UCharacterMovementComponent>();// 启动推进循环PushForwardInputTimerHandle = GetWorld()->GetTimerManager().SetTimerForNextTick(this, &UGA_Dash::PushForward);}// 创建目标检测任务UAbilityTask_WaitTargetData* WaitTargetData = UAbilityTask_WaitTargetData::WaitTargetData(this, NAME_None, EGameplayTargetingConfirmation::CustomMulti,  // 自定义确认方式TargetActorClass);// 绑定目标检测完成回调WaitTargetData->ValidData.AddDynamic(this, &UGA_Dash::TargetReceived);WaitTargetData->ReadyForActivation();// 生成目标检测器AGameplayAbilityTargetActor* TargetActor;WaitTargetData->BeginSpawningActor(this, TargetActorClass, TargetActor);// 配置目标检测器ATargetActor_Around* TargetActorAround = Cast<ATargetActor_Around>(TargetActor);if (TargetActorAround){// 设置检测半径、队伍过滤和视觉提示TargetActorAround->ConfigureDetection(TargetDetectionRadius, GetOwnerTeamId(), LocalGameplayCueTag);}// 完成生成WaitTargetData->FinishSpawningActor(this, TargetActor);// 将检测器附加到角色骨骼if (TargetActorAround){TargetActorAround->AttachToComponent(GetOwningComponentFromActorInfo(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, TargetActorAttachSocketName);}
}void UGA_Dash::TargetReceived(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{// 服务端处理:对目标应用效果if (K2_HasAuthority()){// 应用伤害效果ApplyDamageToTargetDataHandle(TargetDataHandle, DamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));// 击退目标PushTargetsFromOwnerLocation(TargetDataHandle, TargetHitPushSpeed);}
}

到角色中监听加速移动速度的回调

	// 加速移动速度改变回调void MoveSpeedAccelerationUpdated(const FOnAttributeChangeData& Data);
void ACCharacter::BindGASChangeDelegates()
{if (CAbilitySystemComponent){CAbilitySystemComponent->RegisterGameplayTagEvent(TGameplayTags::Stats_Dead).AddUObject(this, &ACCharacter::DeathTagUpdated);CAbilitySystemComponent->RegisterGameplayTagEvent(TGameplayTags::Stats_Stun).AddUObject(this, &ACCharacter::StunTagUpdated);CAbilitySystemComponent->RegisterGameplayTagEvent(TGameplayTags::Stats_Aim).AddUObject(this, &ACCharacter::AimTagUpdated);CAbilitySystemComponent->RegisterGameplayTagEvent(TGameplayTags::Stats_Focus).AddUObject(this, &ACCharacter::FocusTagUpdated);CAbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(CAttributeSet->GetMoveSpeedAttribute()).AddUObject(this, &ACCharacter::MoveSpeedUpdated);CAbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(UCAttributeSet::GetMaxHealthAttribute()).AddUObject(this, &ACCharacter::MaxHealthUpdated);CAbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(UCAttributeSet::GetMaxManaAttribute()).AddUObject(this, &ACCharacter::MaxManaUpdated);CAbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(UCAttributeSet::GetMoveAccelerationAttribute()).AddUObject(this, &ACCharacter::MoveSpeedAccelerationUpdated);}
}void ACCharacter::MoveSpeedAccelerationUpdated(const FOnAttributeChangeData& Data)
{GetCharacterMovement()->MaxAcceleration = Data.NewValue;
}

创建蒙太奇

为其添加一个插槽,用来塞一个TA进去
在这里插入图片描述

添加GE

冲刺的GE
在这里插入图片描述
冷却GE
在这里插入图片描述
伤害GE
在这里插入图片描述
在这里插入图片描述

成本GE
在这里插入图片描述
再创建一个TA塞进去
在这里插入图片描述

添加到数据表中

在这里插入图片描述

添加到角色中

在这里插入图片描述

纠错

这个时候就会又bro发出疑问了,为什么放了冲刺技能后我不能动了呢
因为我们一开始的时候那个加速度没有给他初始化导致的
在这里插入图片描述
那只能创建一个GE来应用一个初始的Value,免得这个无限效果消失的时候变成了默认的0蛋
在这里插入图片描述
角色中的加速度是2048,那我直接应用一个2048吧
在这里插入图片描述
在这里插入图片描述
随后放进英雄资产里等他自己初始化吧
在这里插入图片描述
然后就可以开冲了
在这里插入图片描述

http://www.dtcms.com/a/334492.html

相关文章:

  • Business Magic
  • [创业之路-550]:公司半年度经营分析会 - 解决方案汇总
  • 【Java web】Servlet 详解
  • Linux -- 文件【下】
  • MATLAB R2010b系统环境(二)MATLAB环境的准备
  • 基于Transformer的机器翻译——模型篇
  • 力扣面试150(57/100)
  • 罗技MX Anywhere 2S鼠标修复记录
  • RocketMq面试集合
  • Redis--day6--黑马点评--商户查询缓存
  • 极简工具箱:安卓工具箱合集
  • redis的key过期删除策略和内存淘汰机制
  • Python爬虫实战:研究pygalmesh,构建Thingiverse平台三维网格数据处理系统
  • 记录Linux的指令学习
  • ktg-mes 改造成 Saas 系统
  • 后量子密码算法ML-DSA介绍及开源代码实现
  • 343整数拆分
  • 实例分割-动手学计算机视觉13
  • MQ积压如何处理
  • ABAP AMDP 是一项什么技术?
  • 深入理解Java虚拟机(JVM):架构、内存管理与性能调优
  • MongoDB 聚合提速 3 招:$lookup 管道、部分索引、时间序列集合(含可复现实验与 explain 统计)
  • 片料矫平机·第四篇
  • Element Plus 中 el-input 限制为数值输入的方法
  • 暴雨服务器:以定制化满足算力需求多样化
  • 深入剖析跳表:高效搜索的动态数据结构
  • 【测试工具】OnDo SIP Server--轻松搭建一个语音通话服务器
  • 社保、医保、个税、公积金纵向横向合并 python3
  • 深入理解 Vue Router
  • Centos7.9安装Dante