Lua向C#逻辑迁移 一期 #13

狐狸移动,技能迁移和完善
This commit is contained in:
2025-10-26 15:46:04 +08:00
parent dab9990b44
commit 8c0623b397
28 changed files with 605 additions and 323 deletions

View File

@ -1,12 +1,314 @@
// local GameplayStatics = import("GameplayStatics")
// local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary")
// local BusyGameplayLibrary = import("BusyGameplayLibrary")
using Level.Role;
using UnrealSharp;
using UnrealSharp.Attributes;
using UnrealSharp.BusyRabbit;
using UnrealSharp.CoreUObject;
using UnrealSharp.Engine;
using UnrealSharp.GameplayAbilities;
using UnrealSharp.GameplayTags;
using UnrealSharp.SpinePlugin;
// --- @class FoxUltimate
// --- @field RecastWindow number
// local FoxUltimate = {}
namespace GameAbilitySystem.Ability.Role.Fox;
[UClass]
public class UFoxUltimate : UBusyGameAbility
{
protected bool bIsEventBinded = false;
protected ABusyFoxRole? Owner = null;
protected UFoxUltimateDataAsset? FoxData = null;
protected UBusyAbilitySystemComponent? ASC = null;
protected FActiveGameplayEffectHandle CastStateHandle;
protected FActiveGameplayEffectHandle SkillStateHandle;
protected FActiveGameplayEffectHandle AccelerateHandle; // 大招移动速度增加的Effect
protected FActiveGameplayEffectHandle SprintHandle; // 大招三阶移速再次增加的Effect
[UFunction()]
protected void OnGamePlayTagAddOrRemove(FGameplayTag tag, int isAdd)
{
if (isAdd == 0 && !IsActive)
{
CommitAbilityCooldown();
}
}
/// <summary>
/// 初始化技能依赖的属性
/// </summary>
/// <returns>false->初始化失败</returns>
protected bool InitAbilityOnce()
{
Owner = OwningActorFromActorInfo as ABusyFoxRole;
if (Owner == null) return false;
FoxData = Data as UFoxUltimateDataAsset;
ASC = AbilitySystemLibrary.GetAbilitySystemComponent(Owner) as UBusyAbilitySystemComponent;
if (FoxData == null || ASC == null) return false;
PrintString("asdafdasdf");
if (bIsEventBinded) return true;
TDelegate<GameplayTagAddOrRemoveDelegate> Delegate = new TDelegate<GameplayTagAddOrRemoveDelegate>();
Delegate.BindUFunction(this, "OnGamePlayTagAddOrRemove");
Owner.BindGameplayTagAddOrRemove(FoxData.SecondStageCastTag, Delegate);
Owner.BindGameplayTagAddOrRemove(FoxData.LastStageCastTag, Delegate);
bIsEventBinded = true;
return true;
}
/// <summary>
/// 获取当前大招的阶段
/// </summary>
/// <returns></returns>
protected int GetCurrentAbilityStage()
{
if (ASC == null || FoxData == null) return 0;
if (ASC.HasMatchingGameplayTag(FoxData.LastStageCastTag))
{
return 3;
}
if (ASC.HasMatchingGameplayTag(FoxData.SecondStageCastTag))
{
return 2;
}
else if (ASC.HasMatchingGameplayTag(FoxData.FirstStageCastTag))
{
return 1;
}
return 0;
}
protected override void ActivateAbilityFromEvent(FGameplayEventData eventData)
{
base.ActivateAbilityFromEvent(eventData);
if (!InitAbilityOnce())
{
EndAbility();
return;
}
if (Owner == null || !CommitAbilityCost(Owner))
{
EndAbility();
return;
}
int stage = GetCurrentAbilityStage();
if (stage != 0)
{
TriggerAbility(stage);
}
else
{
EndAbility();
return;
}
}
/// <summary>
/// 当被授予技能时立刻获得可释放第一段大招的常驻Tag
/// </summary>
/// <param name="actorInfo"></param>
/// <param name="spec"></param>
public override void OnGiveAbility(FGameplayAbilityActorInfo actorInfo, FGameplayAbilitySpec spec)
{
base.OnGiveAbility(actorInfo, spec);
InitAbilityOnce();
if (FoxData == null || ASC == null) return;
UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem<UBusyGameplayEffectSubSystem>();
if (EffectSubSystem == null) return;
UGameplayEffect effect = EffectSubSystem.GetTagGrantEffectWithDuration(
new FGameplayTagContainer(FoxData.FirstStageCastTag),
new FGameplayTagContainer(), 0
);
FGameplayEffectSpecHandle handle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, effect, 1);
ASC.ApplyGameplayEffectSpecToSelf(handle);
}
protected bool ApplayCastEffect(FGameplayTag CastTag)
{
UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem<UBusyGameplayEffectSubSystem>();
if (ASC == null || EffectSubSystem == null || FoxData == null) return false;
ASC.RemoveActiveGameplayEffect(CastStateHandle);
if (CastTag.IsValid)
{
UGameplayEffect cast_effect = EffectSubSystem.GetTagGrantEffectWithDuration(
new FGameplayTagContainer(CastTag),
new FGameplayTagContainer(), FoxData.RecastWindow
);
FGameplayEffectSpecHandle CastSpecHandle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, cast_effect, 1);
CastStateHandle = ASC.ApplyGameplayEffectSpecToSelf(CastSpecHandle);
}
return true;
}
protected bool ApplyEffect(FGameplayTag stateTag, FGameplayTag CastTag)
{
UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem<UBusyGameplayEffectSubSystem>();
if (ASC == null || EffectSubSystem == null || FoxData == null) return false;
ApplayCastEffect(CastTag);
ASC.RemoveActiveGameplayEffect(SkillStateHandle);
UGameplayEffect state_effect = EffectSubSystem.GetTagGrantEffectWithDuration(
new FGameplayTagContainer(stateTag),
new FGameplayTagContainer(), 0
);
FGameplayEffectSpecHandle stateSpecHandle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, state_effect, 1);
SkillStateHandle = ASC.ApplyGameplayEffectSpecToSelf(stateSpecHandle);
return true;
}
protected bool TriggerAbility(int stage)
{
if (FoxData == null) return false;
if (stage == 1)
{
if (!ApplyEffect(FoxData.FirstStageTag, FoxData.SecondStageCastTag)) return false;
}
else if (stage == 2)
{
if (!ApplyEffect(FoxData.SecondStageTag, new FGameplayTag())) return false;
}
else if(stage == 3)
{
if (!ApplyEffect(FoxData.LastStageTag, new FGameplayTag())) return false;
}
PlayAnimation(stage);
return true;
}
protected string GetAnimationName(FVector2D direction, int stage)
{
string animation_name_prefix = "";
if (direction.X >= 0)
{
animation_name_prefix = "Ultimate/Right/";
}
else
{
animation_name_prefix = "Ultimate/Left/";
}
if (stage == 1)
{
return animation_name_prefix + "UltimateStage1";
}
else if (stage == 2)
{
return animation_name_prefix + "UltimateStage2";
}
else if (stage == 3)
{
return animation_name_prefix + "UltimateStage3";
}
return "";
}
[UFunction()]
protected void OnAnimationComplete(UTrackEntry Entry)
{
Entry.AnimationComplete.Remove(OnAnimationComplete);
if (ASC != null)
{
if (ASC.HasMatchingGameplayTag(FoxData.LastStageTag))
{
CommitAbilityCooldown();
}
ASC.RemoveActiveGameplayEffect(SkillStateHandle);
}
EndAbility();
}
[UFunction()]
protected void OnTailBeginOverlay(UPrimitiveComponent OverlappedComponent, AActor OtherActor,
UPrimitiveComponent OtherComp, int OtherBodyIndex, bool bFromSweep, FHitResult SweepResult)
{
if (ASC == null || FoxData == null) return;
bool bIsStage2 = ASC.HasMatchingGameplayTag(FoxData.SecondStageTag);
if (bIsStage2 && !ASC.HasMatchingGameplayTag(FoxData.LastStageCastTag))
{
ApplayCastEffect(FoxData.LastStageCastTag);
}
}
[UFunction()]
protected void OnAnimationEvent(UTrackEntry Entry, FSpineEvent Event)
{
if (ASC == null || FoxData == null || Owner == null) return;
if (Event.Name == "OnSpeedChange")
{
AccelerateHandle = MakeAccelerate(FoxData.LastStageSprintSpeedFactor, 1);
}
else if (Event.Name == "OnSpeedReset")
{
ASC.RemoveActiveGameplayEffect(AccelerateHandle);
}
else if (Event.Name == "OnDamageBegin")
{
Owner.SetTailCollisionEnabled(true);
Owner.FoxTailCollision.OnComponentBeginOverlap.Add(OnTailBeginOverlay);
}
else if (Event.Name == "OnDamageEnd")
{
Owner.SetTailCollisionEnabled(false);
Owner.FoxTailCollision.OnComponentBeginOverlap.Remove(OnTailBeginOverlay);
}
}
protected FActiveGameplayEffectHandle MakeAccelerate(float SpeedFactor, float TotalTime)
{
GetAbilityEffectSpecHandle("Accelerate", ASC, 1, out FGameplayEffectSpecHandle handle);
AbilitySystemLibrary.AssignTagSetByCallerMagnitude(
handle, UBusyGameplayLibrary.RequestGameplayTag("Effect.Factor"), SpeedFactor
);
AbilitySystemLibrary.AssignTagSetByCallerMagnitude(
handle, UBusyGameplayLibrary.RequestGameplayTag("Effect.Duration"), TotalTime
);
return ApplyGameplayEffectSpecToOwner(handle);
}
protected bool PlayAnimation(int stage)
{
FVector2D AbilityDirection = new FVector2D(0, 1);
if (UGameplayStatics.GetPlayerController(0) is ALevelPlayerController PC)
{
PC.GetCursorDirection(out AbilityDirection);
}
string AnimationName = GetAnimationName(AbilityDirection, stage);
if (AnimationName == "") return false;
USpineSkeletonAnimationComponent Animation = Owner.SpineAnimationComponent;
UTrackEntry AnimEntry = Animation.SetAnimation(0, AnimationName, false);
AnimEntry.AnimationEvent.Add(OnAnimationEvent);
AnimEntry.AnimationComplete.Add(OnAnimationComplete);
float TotalTime = AnimEntry.GetAnimationEnd();
if (stage == 1) MakeAccelerate(FoxData.FirstStageSpeedFactor, TotalTime);
else if (stage == 2) MakeAccelerate(FoxData.SecondStageSpeedFactor, TotalTime);
else if (stage == 3) MakeAccelerate(FoxData.LastStageNormalSpeedFactor, TotalTime);
Owner.MovementComponent.ActivateSprint(AbilityDirection, TotalTime);
return true;
}
}
// function FoxUltimate:ctor()
// self.ultimate_phase = 1 -- 大招阶段
// self.active_recast_handle = nil
@ -17,136 +319,6 @@
// end
// function FoxUltimate:K2_ActivateAbilityFromEvent(EventData)
// print("FoxUltimate:K2_ActivateAbilityFromEvent", self.ultimate_phase)
// if not self:K2_CommitAbilityCost(false) then
// return self:K2_EndAbility()
// end
// local owner = self:GetOwningActorFromActorInfo()
// self.movement = owner.MovementComponent
// self.animation = owner.SpineAnimationComponent
// self.asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(owner)
// self.recast_tag = BusyGameplayLibrary.RequestGameplayTag("Ability.Flags.Recast")
// self.owner = owner
// local asc = self.asc
// if self.tag_add_or_remove_delegate == nil then
// self.tag_add_or_remove_delegate = slua.createDelegate(function(tag, is_add)
// if is_add == 0 and not self.bIsActive then
// self.ultimate_phase = 1
// self:K2_CommitAbilityCooldown(false, false)
// end
// end)
// owner:BindGameplayTagAddOrRemove(self.recast_tag, self.tag_add_or_remove_delegate)
// end
// if self.ultimate_phase == 1 or asc:HasMatchingGameplayTag(self.recast_tag) then
// self:TriggerUltimate(asc)
// else
// self:K2_EndAbility()
// end
// end
// function FoxUltimate:TriggerUltimate(asc)
// if self.ultimate_phase == 1 then
// -- 第一次释放大招添加一个可以再次释放的Tag
// local _, recast_effect = self:GetAbilityEffectSpecHandle("Recast", asc, 1, nil)
// self.active_recast_handle = asc:BP_ApplyGameplayEffectSpecToSelf(recast_effect)
// elseif self.ultimate_phase == 2 then
// -- 第二次激活移除可重复释放的tag
// self.asc:RemoveActiveGameplayEffect(self.active_recast_handle, -1)
// elseif self.ultimate_phase == 3 then
// self.asc:RemoveActiveGameplayEffect(self.active_recast_handle, -1)
// end
// -- 播放动画,并监听动画完成的事件
// self:PlayAnimation()
// end
// function FoxUltimate:GetAnimationName(direction)
// local animation_name_prefix
// if direction.X >= 0 then
// animation_name_prefix = "Ultimate/Right/"
// else
// animation_name_prefix = "Ultimate/Left/"
// end
// if self.ultimate_phase == 1 then
// return animation_name_prefix .. "UltimateStage1"
// elseif self.ultimate_phase == 2 then
// return animation_name_prefix .. "UltimateStage2"
// elseif self.ultimate_phase == 3 then
// return animation_name_prefix .. "UltimateStage3"
// end
// return nil
// end
// function FoxUltimate:K2_OnEndAbility(bWasCancelled)
// print("FoxUltimate:K2_OnEndAbility")
// end
// function FoxUltimate:GetSprintSpeedFactor()
// if self.ultimate_phase == 1 then
// return 2.5
// elseif self.ultimate_phase == 2 then
// return 2.8
// elseif self.ultimate_phase == 3 then
// return 3.0
// end
// end
// function FoxUltimate:PlayAnimation()
// local animation = self.animation
// local PC = GameplayStatics.GetPlayerController(self, 0)
// local result, ability_direction = PC:GetCursorDirection(nil) -- 获取技能的朝向
// if not result then
// print("FoxUltimate:TriggerPrimaryPhase can't find direction")
// return
// end
// local anim_name = self:GetAnimationName(ability_direction) -- 获取技能动画名称
// if not anim_name then
// print("FoxUltimate:TriggerPrimaryPhase can't get animation", self.ultimate_phase)
// return
// end
// local anim_entry = animation:SetAnimation(0, anim_name, false)
// anim_entry.AnimationComplete:Add(function(entry) self:OnAnimationComplete(entry) end)
// anim_entry.AnimationEvent:Add(function(entry, event) self:OnAnimationEvent(entry, event) end)
// local anim_total_time = anim_entry:GetAnimationEnd() -- 获取技能动画时长
// -- 附加加速buff
// self:MakeAccelerate(self:GetSprintSpeedFactor(), anim_total_time)
// self.movement:ActivateSprint(ability_direction, anim_total_time)
// end
// function FoxUltimate:MakeAccelerate(speed_factor, total_time)
// local _, accelerate_effect = self:GetAbilityEffectSpecHandle("Accelerate", self.asc, 1, nil)
// AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
// accelerate_effect,
// BusyGameplayLibrary.RequestGameplayTag("Effect.Factor"),
// speed_factor
// )
// AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
// accelerate_effect,
// BusyGameplayLibrary.RequestGameplayTag("Effect.Duration"),
// total_time
// )
// return self.asc:BP_ApplyGameplayEffectSpecToSelf(accelerate_effect)
// end
// function FoxUltimate:OnAnimationComplete(entry)
@ -168,29 +340,4 @@
// self:K2_EndAbility()
// end
// function FoxUltimate:OnAnimationEvent(entry, event)
// if event.Name == "OnSpeedChange" then
// self.active_accelerate_handle = self:MakeAccelerate(8.0, 0.5)
// elseif event.Name == "OnSpeedReset" then
// self.asc:RemoveActiveGameplayEffect(self.active_accelerate_handle, -1)
// elseif event.Name == "OnDamageBegin" then
// local collision = self.owner["TailCollision"]
// collision:SetCollisionEnabled(1)
// self.overlap_delegate_handle = collision.OnComponentBeginOverlap:Add(function()
// if not self.asc:HasMatchingGameplayTag(self.recast_tag) then
// local _, recast_effect = self:GetAbilityEffectSpecHandle("Recast", self.asc, 1, nil)
// self.active_recast_handle = self.asc:BP_ApplyGameplayEffectSpecToSelf(recast_effect)
// end
// end)
// elseif event.Name == "OnDamageEnd" then
// self.owner["TailCollision"]:SetCollisionEnabled(0)
// if self.overlap_delegate_handle ~= nil then
// self.owner["TailCollision"].OnComponentBeginOverlap:Remove(self.overlap_delegate_handle)
// self.overlap_delegate_handle = nil
// end
// end
// end
// return Class(nil, nil, FoxUltimate)