---@class UGCPlayerPawn_C:BP_UGCPlayerPawn_C ---@field P_HookFire_R UParticleSystemComponent ---@field P_HookFire_L UParticleSystemComponent ---@field P_HookFly_R UParticleSystemComponent ---@field P_HookFly_L UParticleSystemComponent ---@field SM_Gear_R UStaticMeshComponent ---@field SM_Gear_L UStaticMeshComponent --Edit Below-- ---@type UGCPlayerPawn_C local UGCPlayerPawn = { ---@field ModifyDamageDelegation fun(DamageAmount:float,DamageEvent:FDamageEvent,EventInstigator:AController,DamageCauser:AActor):float ModifyDamageDelegation = {}; -- MechanismEnergy = 0; -- 玩家拥有的能量 CachedSTCharacterMovementGravityScale = 1.0; BaseCapsuleHalfHeight = 88.0; BaseCapsuleRadius = 40; CachedSTCharacterMovementGravityScale = 1.; DashDuration = -1; VelocityClampBase = 1200; VelocityClamp = 1200; bCanActiveSkill = false; BaseJumpZVelocity = 443.0; }; function UGCPlayerPawn:GetReplicatedProperties() return "DashImpulseEnergy", "HookEnergy", "LaunchEnergy" end -- 关闭盒子掉落 function UGCPlayerPawn:IsSkipSpawnDeadTombBox(EventInstigater) return true end function UGCPlayerPawn:ReceiveBeginPlay() self.SuperClass.ReceiveBeginPlay(self); --- 设置翻墙功能 self.bVaultIsOpen = true --- 设置滑铲功能 self.IsOpenShovelAbility = true self.CachedSTCharacterMovementGravityScale = self.STCharacterMovement.GravityScale; UGCEventSystem.SendEvent(EventEnum.PlayerBeginPlay, self) --- 获取初始胶囊体信息 self.BaseCapsuleHalfHeight = self.CapsuleComponent.CapsuleHalfHeight self.BaseCapsuleRadius = self.CapsuleComponent.CapsuleRadius self.BaseJumpZVelocity = UGCPawnAttrSystem.GetJumpZVelocity(self) if self:HasAuthority() then self:AddEvent() self:InitParam() --- 循环判断当前武器配置是否正确,多则删、少则补 if UGCGameSystem.GameState:GetGameStateType() == CustomEnum.EGameState.Playing then -- self.LoopCheckGradientWeaponHandle = UGCEventSystem.SetTimerLoop(self, self.CheckGradientWeapon, 1.) --- 循环判断是否给予初始近战武器,有则移除Handle,没有则进行循环 -- self.AddDefaultMeleeWeaponHandle = UGCEventSystem.SetTimerLoop(self, self.AddDefaultMeleeWeapon, 1.) end if UE.IsValid(self:GetController()) then self:ReceivePossessed(self:GetController()) UGCLogSystem.Log("[UGCPlayerPawn_ReceiveBeginPlay] Controller Is Valid") end --- 技能的初始化 self:SkillInit() else end end function UGCPlayerPawn:ReceiveEndPlay() self:RemoveEvent() self:SkillEndPlay() self.SuperClass.ReceiveEndPlay(self); end function UGCPlayerPawn:CheckGradientWeapon() WeaponGradientManager.UpdatePlayerGradientWeaponMatching( self.PlayerKey, UGCGameSystem.GameState:GetPlayerWeaponGrade(self.PlayerKey), UGCGameSystem.GameState:GetPlayerDefaultMeleeWeaponByPlayerKey(self.PlayerKey) ) end function UGCPlayerPawn:AddDefaultMeleeWeapon() local MeleeWeaponID = UGCGameSystem.GameState:GetPlayerDefaultMeleeWeaponByPlayerKey(self.PlayerKey) if UGCBackPackSystem.GetItemCount(self, MeleeWeaponID) > 0 then UGCEventSystem.StopTimer(self.AddDefaultMeleeWeaponHandle) self.AddDefaultMeleeWeaponHandle = nil else UGCBackPackSystem.AddItem(self, MeleeWeaponID, 1) end end function UGCPlayerPawn:InitParam() -- self:SetMechanismEnergy(GlobalConfigs.GameSetting.InitEnergy) end function UGCPlayerPawn:ReceiveTick(DeltaTime) self.SuperClass.ReceiveTick(self, DeltaTime); self:TickSkill(DeltaTime) if not UGCGameSystem.IsServer() then self:ClientMustBeExeBeginPlay() end self.CharacterMovement.Velocity = KismetMathLibrary.ClampVectorSize(self.CharacterMovement.Velocity, 0, self:GetVelocityClamp()) end function UGCPlayerPawn:GetVelocityClamp() return self.VelocityClamp end function UGCPlayerPawn:SetVelocityClamp(NewVelocityClamp) self.VelocityClamp = NewVelocityClamp end --- 客户端必定执行的BeginPlay function UGCPlayerPawn:ClientMustBeExeBeginPlay() if self.DoOnceMustBeExeBeginPlay then return end self.DoOnceMustBeExeBeginPlay = true UGCEventSystem.SendEvent(EventEnum.PlayerPossessed) --- 技能的初始化 self:SkillInit() UGCPawnAttrSystem.SetCanSwitchFPP(self, true) end function UGCPlayerPawn:AddEvent() if self:HasAuthority() then self.DeadNotifyDelegate:Add(self.PlayerDeadCallBack, self) self.DamageNotifyDelegate:Add(self.PlayerInjury, self) else end end function UGCPlayerPawn:RemoveEvent() if self:HasAuthority() then self.DeadNotifyDelegate:Remove(self.PlayerDeadCallBack, self) self.DamageNotifyDelegate:Remove(self.PlayerInjury, self) if self.LoopCheckGradientWeaponHandle then UGCEventSystem.StopTimer(self.LoopCheckGradientWeaponHandle) self.LoopCheckGradientWeaponHandle = nil end if self.AddDefaultMeleeWeaponHandle then UGCEventSystem.StopTimer(self.AddDefaultMeleeWeaponHandle) self.AddDefaultMeleeWeaponHandle = nil end else end end function UGCPlayerPawn:ReceivePossessed(NewController) self.SuperClass.ReceivePossessed(self, NewController); UGCLogSystem.Log("[UGCPlayerPawn_ReceivePossessed] PlayerKey:%s", tostring(NewController.PlayerKey)) UGCEventSystem.SendEvent(EventEnum.PlayerPossessed, NewController.PlayerKey) -- UGCSendRPCSystem.RPCEvent(NewController.PlayerKey, EventEnum.PlayerPossessed, NewController.PlayerKey) if GlobalConfigs.GameSetting.ReadyCanNotMove and UGCGameSystem.GameState:GetReadyTime() > 0 then UGCLogSystem.Log("[UGCPlayerPawn_ReceivePossessed] Set SpeedScale") self:SetCanActionable(false) else self:SetCanActionable(true) end -- UGCSendRPCSystem.ActorRPCNotify(nil, self, "InitHook", NewController.PlayerKey) end function UGCPlayerPawn:SetCanActionable(IsActionable) self:SetCanActiveSkill(IsActionable) --local SpeedScale = (IsActionable and 1. or 0.01) --UGCPawnAttrSystem.SetSpeedScale(self, SpeedScale) -- UGCPawnSystem.DisabledPawnState(self, EPawnState.Move, not IsActionable); UGCSystemLibrary.SetPlayerPawnMoveable(self, IsActionable) end function UGCPlayerPawn:SetCanActiveSkill(IsActive) self.bCanActiveSkill = IsActive end -------------------------------------------------- Delegate -------------------------------------------------- ---@param DamageInfo FDamageInfoCollection ---@return VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue uint, uint, int, EDamageType, bool, float, float function UGCPlayerPawn:GetDamageInfoCollectionInfo(DamageInfo) local CauserController = DamageInfo.Instigator local WeaponID = -1 local CauserKey = CauserController and CauserController.PlayerKey or -1 local VictimKey = self.PlayerKey local CauserItemID = DamageInfo.CauserItemID --- 近战投掷、投掷手雷 if CauserItemID then WeaponID = CauserItemID end UGCLogSystem.Log("[UGCPlayerPawn_GetDamageInfoCollectionInfo] WeaponID:%d", WeaponID) local Distance = 0. if CauserController and CauserController.Pawn then Distance = VectorHelper.GetDistance(self:K2_GetActorLocation(), CauserController.Pawn:K2_GetActorLocation()) end local IsHeadShotDamage = (DamageInfo.Hit.BoneName == "head") return VictimKey, CauserKey, WeaponID, DamageInfo.DamageType, IsHeadShotDamage, Distance, DamageInfo.Damage end ---@param DamageInfo FDamageInfoCollection function UGCPlayerPawn:PlayerDeadCallBack(DamageInfo) local VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue = self:GetDamageInfoCollectionInfo(DamageInfo) local DeadPS = UGCGameSystem.GetPlayerStateByPlayerKey(VictimKey) local Assister = -1 if DeadPS then Assister = DeadPS:GetAssister(CauserKey, GlobalConfigs.GameSetting.AssistDamage) end UGCSendRPCSystem.RPCEvent(nil, EventEnum.PlayerDeathInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue, Assister) UGCEventSystem.SendEvent(EventEnum.PlayerDeathInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue, Assister) end ---@param DamageInfo FDamageInfoCollection ---@param ReturnValue float function UGCPlayerPawn:PlayerInjury(DamageInfo) local VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue = self:GetDamageInfoCollectionInfo(DamageInfo) self.PlayerState:UpdatePlayerInjuryInfo(VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue) UGCEventSystem.SendEvent(EventEnum.PlayerInjuryInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue) UGCSendRPCSystem.RPCEvent(CauserKey, EventEnum.PlayerInjuryInfo, VictimKey, CauserKey, WeaponID, DamageType, IsHeadShotDamage, Distance, DamageValue) end ------------------------------------------------ Delegate End ------------------------------------------------ function UGCPlayerPawn:AddMechanismEnergy(InEnergy) self:SetMechanismEnergy(self:GetMechanismEnergy() + InEnergy) end function UGCPlayerPawn:GetMechanismEnergy() return self.MechanismEnergy end function UGCPlayerPawn:SetMechanismEnergy(NewEnergy) self.MechanismEnergy = (NewEnergy > 0 and NewEnergy or 0) end ------------------------------------------------ ModifyDamage ------------------------------------------------ function UGCPlayerPawn:UGC_TakeDamageOverrideEvent(Damage, DamageType, EventInstigator, DamageCauser, Hit) local DamageAmount = Damage UGCLogSystem.Log("[UGCPlayerPawn_UGC_TakeDamageOverrideEvent] InDamageAmount:%s", tostring(DamageAmount)) if EventInstigator and EventInstigator.PlayerKey then local CauserTeamID = UGCPlayerStateSystem.GetTeamID(EventInstigator.PlayerKey) local SelfTeamID = UGCPlayerStateSystem.GetTeamID(self.PlayerKey) if DamageType == EDamageType.UGCPointDamage then DamageAmount = (CauserTeamID == SelfTeamID and MechanismConfig.MechanismFriendlyInjuryRatio * DamageAmount or DamageAmount) else if EventInstigator.PlayerKey == self.PlayerKey then --- 对自己的伤害 if GlobalConfigs.GameSetting.bEnableSelfHarm then DamageAmount = GlobalConfigs.GameSetting.SelfHarmInjuryRatio * DamageAmount else DamageAmount = 0 end else --- 伤害设置(友方、敌方) DamageAmount = (CauserTeamID == SelfTeamID and GlobalConfigs.GameSetting.FriendlyInjuryRatio * DamageAmount or DamageAmount) end end elseif DamageCauser and DamageCauser:GetOwner() then UGCLogSystem.Log("[UGCPlayerPawn_UGC_TakeDamageOverrideEvent] DamageCauser:GetOwner():%s", KismetSystemLibrary.GetObjectName(DamageCauser:GetOwner())) local TargetPlayerKey = DamageCauser:GetOwner().PlayerKey if TargetPlayerKey then local CauserTeamID = UGCPlayerStateSystem.GetTeamID(TargetPlayerKey) local SelfTeamID = UGCPlayerStateSystem.GetTeamID(self.PlayerKey) DamageAmount = (CauserTeamID == SelfTeamID and GlobalConfigs.GameSetting.FriendlyInjuryRatio * DamageAmount or DamageAmount) end else --- 掉落伤害 DamageAmount = GlobalConfigs.GameSetting.bEnableDropDamage and DamageAmount or 0. end UGCLogSystem.Log("[UGCPlayerPawn_UGC_TakeDamageOverrideEvent] ModifyDamageAmount:%s", tostring(DamageAmount)) return DamageAmount end ---------------------------------------------- ModifyDamage End ---------------------------------------------- function UGCPlayerPawn:ScalePlayer(NewScale) if UGCGameSystem.IsServer() then self:SetPlayerScale_N(NewScale) UGCLogSystem.Log("[UGCPlayerPawn_ScalePlayer]") UGCSendRPCSystem.ActorRPCNotify(nil, self, "SetPlayerScale_N", NewScale) UGCLogSystem.Log("[UGCPlayerPawn_ScalePlayer] Finish") end end function UGCPlayerPawn:SetPlayerScale_N(NewScale) UGCLogSystem.Log("[UGCPlayerPawn_SetPlayerScale_N]") local HalfHeight = self.BaseCapsuleHalfHeight * NewScale self.Mesh:SetWorldScale3D({X = NewScale, Y = NewScale, Z = NewScale}) self.CapsuleComponent:SetCapsuleHalfHeight(HalfHeight, true) self.CapsuleComponent:SetCapsuleRadius(self.BaseCapsuleRadius * NewScale, true) self.Mesh:K2_SetRelativeLocation({X = 0, Y = 0, Z = HalfHeight}) UGCLogSystem.Log("[UGCPlayerPawn_SetPlayerScale_N] Finish") end ---------------------------------------------------------- TurnOffGravityScale ---------------------------------------------------------- --- 关闭重力影响 ---@param On bool function UGCPlayerPawn:TurnOffGravityScale(On) if On then -- self:SetGravityScaleAuthorized(0.01); -- 参考钩爪技能内部实现 self.STCharacterMovement.GravityScale = 0; --self.CharacterMovement:SetMovementMode(EMovementMode.MOVE_Flying); else -- self:SetGravityScaleAuthorized(self.CachedGravityScaleAuthorized); -- ,不能用这个函数,底层恢复有问题 self.STCharacterMovement.GravityScale = self.CachedSTCharacterMovementGravityScale; --self.CharacterMovement:SetMovementMode(EMovementMode.MOVE_Falling); end end -------------------------------------------------------- TurnOffGravityScale End -------------------------------------------------------- ------------------------------------------------------- LaunchSkill ------------------------------------------------------- ----------------------------------------------------- LaunchSkill End ----------------------------------------------------- UGCPlayerPawn.LaunchZSpeed = 2000 --- Launch的消耗限制 UGCPlayerPawn.LaunchEnergy = 0. UGCPlayerPawn.LaunchEnergyCost = 100. UGCPlayerPawn.LaunchEnergyRecoverySpeed = 20. UGCPlayerPawn.LaunchMaxEnergy = 200 UGCPlayerPawn.bJumpingOnTheGround = false function UGCPlayerPawn:LaunchSkill() if UGCGameSystem.IsServer() then if not self.bCanActiveSkill then return end end if not GlobalConfigs.IsDebug then if self:CheckLaunch() then if self.bJumpingOnTheGround and self.CharacterMovement.MovementMode ~= EMovementMode.MOVE_Walking then UGCSendRPCSystem.RPCEvent(self.PlayerKey, EventEnum.AddTip, TipConfig.TipType.LaunchFailure) return end self.LaunchEnergy = self.LaunchEnergy - self.LaunchEnergyCost else return end end -- Test -- self.CharacterMovement.Velocity = VectorHelper.VectorZero() -- TestEnd local AddSpeed = {X = 0, Y = 0, Z = self.LaunchZSpeed} --if self.CharacterMovement.Velocity.Z < 0 then -- AddSpeed = Vector.New(0, 0, self.LaunchZSpeed - self.CharacterMovement.Velocity.Z) -- self.CharacterMovement:AddImpulse(AddSpeed, true) --elseif self.CharacterMovement.Velocity.Z == 0 then -- self.CharacterMovement:AddImpulse(AddSpeed, true) --else -- self.CharacterMovement:AddImpulse(AddSpeed, true) --end -- 和平在移动方面做了处理,无法全部使用AddImpulse或者直接设置速度,因此采用增加最大跳跃次数和初次跳跃采用设置速度的方式进行。 local IsWalking = false if self.CharacterMovement.MovementMode == EMovementMode.MOVE_Walking then IsWalking = true self.CharacterMovement.MovementMode = EMovementMode.MOVE_Falling self.CharacterMovement.Velocity = { X = self.CharacterMovement.Velocity.X, Y = self.CharacterMovement.Velocity.Y, Z = self.LaunchZSpeed } else if self.JumpCurrentCount == self.JumpMaxCount then self.JumpMaxCount = self.JumpMaxCount + 1 end UGCPawnAttrSystem.SetJumpZVelocity(self, self.LaunchZSpeed) self:Jump() UGCEventSystem.SetTimer(self, function() UGCPawnAttrSystem.SetJumpZVelocity(self, self.BaseJumpZVelocity) end, 0.01) end UGCSendRPCSystem.ActorRPCNotify(nil, self, "ClientLaunch", self.PlayerKey, AddSpeed, self.JumpMaxCount, IsWalking) -- UGCSendRPCSystem.ActorRPCNotify(nil, self, "ClientLaunchEffect", self.PlayerKey) end function UGCPlayerPawn:ClientLaunch(PlayerKey, InAddSpeed, InJumpMaxCount, IsWalking) self:ClientLaunchEffect(PlayerKey) if IsWalking then self.CharacterMovement.MovementMode = EMovementMode.MOVE_Falling self.CharacterMovement.Velocity = { X = self.CharacterMovement.Velocity.X, Y = self.CharacterMovement.Velocity.Y, Z = self.LaunchZSpeed } else self.JumpMaxCount = InJumpMaxCount self:Jump() end end function UGCPlayerPawn:CheckLaunch() return UGCGameSystem.GameState:GetEnablePlayerSkill(CustomEnum.EPlayerSkill.Launch) and self.LaunchEnergy >= self.LaunchEnergyCost end function UGCPlayerPawn:LaunchTick(DeltaTime) self:AddLaunchEnergy(DeltaTime) -- 这里通过设置玩家的跳跃按键的碰撞来限制玩家使用跳跃的最大次数,保证了弹射的使用 if self.CharacterMovement.MovementMode == EMovementMode.MOVE_Walking then self.JumpMaxCount = 2 -- UGCPawnAttrSystem.SetJumpZVelocity(self, self.BaseJumpZVelocity) if not UGCGameSystem.IsServer() then if self.JumpBtn == nil then self.JumpBtn = GameBusinessManager.GetWidgetFromName(ingame, "MainControlPanelTochButton_C").ShootingUIPanel.CustomJumpBtn end self.JumpBtn:SetVisibility(ESlateVisibility.Visible) end else -- UGCPawnAttrSystem.SetJumpZVelocity(self, self.LaunchZSpeed) if not UGCGameSystem.IsServer() then if self.JumpBtn == nil then self.JumpBtn = GameBusinessManager.GetWidgetFromName(ingame, "MainControlPanelTochButton_C").ShootingUIPanel.CustomJumpBtn end self.JumpBtn:SetVisibility(ESlateVisibility.HitTestInvisible) end end end function UGCPlayerPawn:AddLaunchEnergy(DeltaTime) self.LaunchEnergy = math.clamp(self.LaunchEnergy + DeltaTime * self.LaunchEnergyRecoverySpeed, 0, self.LaunchMaxEnergy) end function UGCPlayerPawn:ClientLaunchEffect(InPlayerKey) if InPlayerKey == UGCSystemLibrary.GetLocalPlayerKey() then SoundSystem.PlaySound(SoundSystem.ESound.Impulse) end self.P_HookFly_L:SetActive(true, true) self.P_HookFly_R:SetActive(true, true) self:AddFlyEffect(2.5) end function UGCPlayerPawn:AddFlyEffect(Time) if self.FlyEffectHandle then UGCEventSystem.StopTimer(self.FlyEffectHandle) end self.FlyEffectHandle = UGCEventSystem.SetTimer(self, function() self.P_HookFly_L:SetActive(false, false) self.P_HookFly_R:SetActive(false, false) self.FlyEffectHandle = nil end, Time) end ------------------------------------------------------- DashImpulseSkill ------------------------------------------------------- UGCPlayerPawn.MinDashVelocity = 2400 UGCPlayerPawn.MaxDashVelocity = 3600 --- 冲量强度 /s UGCPlayerPawn.ImpulseStrength = 10000 --- 移动范围(帧计算会有一点偏差)超过范围自动停止 UGCPlayerPawn.TargetDashLength = 1500 --- 最大冲刺时长 UGCPlayerPawn.DashMaxTime = 0.5 --- Dash的消耗限制 UGCPlayerPawn.DashImpulseEnergy = 0. UGCPlayerPawn.DashImpulseEnergyCost = 100. UGCPlayerPawn.EnergyRecoverySpeed = 20. UGCPlayerPawn.DashImpulseMaxEnergy = 200 function UGCPlayerPawn:InitDashImpulse() if (self.bInitedDashImpulse == nil or (not self:GetDashImpulseOverlapComponent():IsActive()) ) and UGCGameSystem.IsServer() then self.bInitedDashImpulse = true self.BP_PawnAuxiliaryOverlapCap:SetActive(true) self:GetDashImpulseOverlapComponent():SetActive(true) -- Pawn增加的碰撞盒都没效果 self:GetDashImpulseOverlapComponent().OnComponentBeginOverlap:Add(self.DashCollisionCapsuleBeginOverlap, self) UGCLogSystem.Log("[UGCPlayerPawn_InitDashImpulse] Finish DashCollisionCapsuleIsActive:%s", tostring(self:GetDashImpulseOverlapComponent():IsActive())) end end function UGCPlayerPawn:GetDashImpulseOverlapComponent() return self.BP_PawnAuxiliaryOverlapCap.ChildActor.Capsule end function UGCPlayerPawn:DashCollisionCapsuleBeginOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult) UGCLogSystem.Log("[UGCPlayerPawn_DashCollisionCapsuleBeginOverlap] OtherActor:%s", KismetSystemLibrary.GetObjectName(OtherActor)) self:StopDashImpulse() end --- 冲量冲刺 ---@param ForwardDir FVector 为nil则使用玩家向前向量作为方向 ---@param InStartDashPos FVector 调用时无需传入 function UGCPlayerPawn:DashImpulse(ForwardDir, InStartDashPos) --local CameraForward = self:GetController().PlayerCameraManager:GetActorForwardVector() if self.ImpulseDashing then return end if UGCGameSystem.IsServer() then if not self.bCanActiveSkill then return end end if self:CheckDashImpulse() then self.DashImpulseEnergy = self.DashImpulseEnergy - self.DashImpulseEnergyCost else return end -- self:InitDashImpulse() self:SetCanActiveSkill(false) self.ImpulseDashing = true self:TurnOffGravityScale(true) self:SetVelocityClamp(self.MaxDashVelocity) if ForwardDir == nil then self.ImpulseDir = VectorHelper.ToLuaTable(self:GetActorForwardVector()) else self.ImpulseDir = ForwardDir end -- 给予一个初始冲量 UGCLogSystem.Log("[UGCPlayerPawn_DashImpulse] ImpulseDir:%s", VectorHelper.ToString(self.ImpulseDir)) self.CharacterMovement.Velocity = VectorHelper.MulNumber(self.ImpulseDir, VectorHelper.Length(self.CharacterMovement.Velocity)) self.CharacterMovement:AddImpulse(VectorHelper.MulNumber(self.ImpulseDir, self.ImpulseStrength * 0.4), true) -- 给予一个初始速度 -- self.CharacterMovement.Velocity = VectorHelper.MulNumber(self.ImpulseDir, 1200) if UGCGameSystem.IsServer() then self.StartDashPos = VectorHelper.ToLuaTable(self:K2_GetActorLocation()) else -- self.StartDashPos = InStartDashPos self:DashEffect() end --self.StopImpulseDashHandle = UGCEventSystem.SetTimer(self, self.StopDashImpulse, self.DashMaxTime) if UGCGameSystem.IsServer() then UGCSendRPCSystem.ActorRPCNotify(nil, self, "DashImpulse", self.ImpulseDir) self.StopImpulseDashHandle = UGCEventSystem.SetTimer(self, function() self.StopImpulseDashHandle = nil self:StopDashImpulse() end, self.DashMaxTime) end end function UGCPlayerPawn:DashEffect() if self.PlayerKey == UGCSystemLibrary.GetLocalPlayerKey() then SoundSystem.PlaySound(SoundSystem.ESound.Impulse) end self:AddFlyEffect(2.5) end function UGCPlayerPawn:StopDashImpulse() if not self.ImpulseDashing then return end self:TurnOffGravityScale(false) self.CharacterMovement.Velocity = VectorHelper.VectorZero() self:SetVelocityClamp(self.VelocityClampBase) if UGCGameSystem.IsServer() then if self.StopImpulseDashHandle then UGCEventSystem.StopTimer(self.StopImpulseDashHandle) self.StopImpulseDashHandle = nil end UGCSendRPCSystem.ActorRPCNotify(nil, self, "StopDashImpulse") end self.ImpulseDashing = false self:SetCanActiveSkill(true) end function UGCPlayerPawn:AddDashImpulseEnergy(DeltaTime) self.DashImpulseEnergy = math.clamp(self.DashImpulseEnergy + DeltaTime * self.EnergyRecoverySpeed, 0, self.DashImpulseMaxEnergy) end function UGCPlayerPawn:CheckDashImpulse() return UGCGameSystem.GameState:GetEnablePlayerSkill(CustomEnum.EPlayerSkill.Dash) and self.DashImpulseEnergy >= self.DashImpulseEnergyCost end function UGCPlayerPawn:DashImpulseTick(DeltaTime) self:AddDashImpulseEnergy(DeltaTime) if self.ImpulseDashing then self.CharacterMovement:AddImpulse(VectorHelper.MulNumber(self.ImpulseDir, self.ImpulseStrength * DeltaTime), true) if self.CharacterMovement.MovementMode ~= EMovementMode.MOVE_Falling then self.CharacterMovement:SetMovementMode(EMovementMode.MOVE_Falling); end -- self.CharacterMovement.Velocity = KismetMathLibrary.ClampVectorSize(self.CharacterMovement.Velocity, self.MinDashVelocity, self.MaxDashVelocity) self.CharacterMovement.Velocity = VectorHelper.MulNumber(self.ImpulseDir, math.clamp(VectorHelper.Length(self.CharacterMovement.Velocity), self.MinDashVelocity, self.MaxDashVelocity)) if UGCGameSystem.IsServer() then if VectorHelper.Length(VectorHelper.Sub(self:K2_GetActorLocation(), self.StartDashPos)) > self.TargetDashLength then self:StopDashImpulse() end end end end ----------------------------------------------------- DashImpulseSkill End ----------------------------------------------------- ------------------------------------------------------- DashImpulseSkill2 ------------------------------------------------------- UGCPlayerPawn.Dash2_ForwardStrength = 4000 UGCPlayerPawn.Dash2_UpStrength = 500 function UGCPlayerPawn:DashImpulse2(DashDir) if UGCGameSystem.IsServer() then DashDir = VectorHelper.ToLuaTable(self:GetActorForwardVector()) UGCSendRPCSystem.ActorRPCNotify(nil, self, "DashImpulse2", DashDir) end self:SetVelocityClamp(4800) --self.CharacterMovement:AddImpulse(VectorHelper.MulNumber(DashDir, self.Dash2_ForwardStrength), true) self.CharacterMovement:AddImpulse({X = 0., Y = 0., Z = math.clamp(self.Dash2_UpStrength - self.CharacterMovement.Velocity.Z, 0, 1e5)}, true) UGCEventSystem.SetTimer(self, function() self.CharacterMovement:AddImpulse(VectorHelper.MulNumber(DashDir, self.Dash2_ForwardStrength), true) --self.CharacterMovement:AddImpulse({X = 0., Y = 0., Z = math.clamp(self.Dash2_UpStrength - self.CharacterMovement.Velocity.Z, 0, 1e5)}, true) end, 0.1) UGCEventSystem.SetTimer(self, function() self:SetVelocityClamp(self.VelocityClampBase) end, 2) end ----------------------------------------------------- DashImpulseSkill2 End ----------------------------------------------------- ----------------------------------------------------------- HookSkill ----------------------------------------------------------- --- 正在执行钩锁技能 UGCPlayerPawn.bHooking = false --- 钩锁飞行时间 UGCPlayerPawn.HookFlyTime = 0.2 --- 推动玩家最大持续时间 UGCPlayerPawn.PullPlayerMaxTime = 4. --- 第二次检测钩锁附着点时球体的半径 UGCPlayerPawn.SmartAimMediumTraceRadius = 300. --- 第三次检测钩锁附着点时球体的半径 UGCPlayerPawn.SmartAimLargeTraceRadius = 700. --- 单钩的第二次检测 UGCPlayerPawn.OneHookSecondTraceRadius = 100. --- 检测距离 UGCPlayerPawn.HookMaxDis = 6000. UGCPlayerPawn.TwoHookTraceMaxDis = 30000. UGCPlayerPawn.SmallSphereStartDis = 800 UGCPlayerPawn.BigSphereStartDis = 1500 UGCPlayerPawn.OneHookSecondTraceStartDis = 300 --- 是否为双发的钩锁,单发则从准星位置发射 UGCPlayerPawn.EnableTwoHook = true --- 正在拉动玩家 UGCPlayerPawn.bHookPullingPlayer = false --- Hook在玩家身上发射出去的插槽名字 --UGCPlayerPawn.HookSocketName_R = "thigh_r" --UGCPlayerPawn.HookSocketName_L = "thigh_l" UGCPlayerPawn.HookSocketName_Mid = "spine_01" UGCPlayerPawn.GearPropertyName_R = "SM_Gear_R" UGCPlayerPawn.GearPropertyName_L = "SM_Gear_L" UGCPlayerPawn.GearSocketName = "HookStart" --- 绘制检测线条 UGCPlayerPawn.bEnableDrawDebug = false UGCPlayerPawn.bEnableDrawDebug_Client = false --- 给予的初始冲量 UGCPlayerPawn.StartHookPullImpulse = 3200 --- 给予的持续冲量/s UGCPlayerPawn.HookPullImpulse = 3000 --- 速度范围 UGCPlayerPawn.MinPullVelocity = 1800 UGCPlayerPawn.MaxPullVelocity = 3000 --- 通过判断自动停止Pull UGCPlayerPawn.bAutoStopHookPush = true --- 单条钩锁模式时,结束后给予的向上冲量 UGCPlayerPawn.SimpleHookUpImpulse = 700 --- 单条钩锁模式时,结束后给予的向上冲量的触发距离的阈值,玩家距离目标位置小于此阈值则触发自动停止拉动且向上给予冲量 UGCPlayerPawn.UpImpulseDistanceThreshold = 100 --- 表示按下Hook技能后还启用了拉力 UGCPlayerPawn.EnabledHookPull = false --- Hook的消耗限制 UGCPlayerPawn.HookEnergy = 0. UGCPlayerPawn.HookEnergyCost = 100. UGCPlayerPawn.HookEnergyRecoverySpeed = 1000. UGCPlayerPawn.HookMaxEnergy = 100 --function UGCPlayerPawn:SetEnableTwoHook(InEnableTwoHook) -- if UGCGameSystem.IsServer() then -- if not self.bHooking and self.EnableTwoHook ~= InEnableTwoHook then -- self.EnableTwoHook = InEnableTwoHook -- UGCSendRPCSystem.ActorRPCNotify(nil, self,"SetEnableTwoHook", InEnableTwoHook) -- end -- else -- if self.EnableTwoHook ~= InEnableTwoHook then -- self.EnableTwoHook = InEnableTwoHook -- if self.PlayerKey == UGCSystemLibrary.GetLocalPlayerKey() then -- UGCEventSystem.SendEvent(EventEnum.HookNumChange, InEnableTwoHook) -- end -- end -- if self.EnableTwoHook == false then -- WidgetManager:ClosePanel(WidgetConfig.EUIType.HookTrace) -- end -- end --end function UGCPlayerPawn:GetHook(IsRight, InPlayerKey) local TargetHook = self.LeftHook if IsRight then TargetHook = self.RightHook end if not UE.IsValid(TargetHook) then local AllHook = GameplayStatics.GetAllActorsOfClass(self, ObjectPathTable.BP_Hook_Class, {}) UGCLogSystem.Log("[UGCPlayerPawn_GetHook] #AllHook:%s, IsRight:%s, InPlayerKey:%s", tostring(#AllHook), tostring(IsRight), tostring(InPlayerKey)) local NoOwnerHook = nil for i, v in pairs(AllHook) do local PlayerKey, TempIsRight = v:GetOwnerPlayer() if InPlayerKey == PlayerKey and TempIsRight == IsRight then return v elseif PlayerKey == nil and NoOwnerHook == nil then NoOwnerHook = v end end if NoOwnerHook then NoOwnerHook:SetPlayerKey(InPlayerKey, IsRight) return NoOwnerHook end end return TargetHook end function UGCPlayerPawn:InitHook() --if self.DoOnceInitHook then return end --self.DoOnceInitHook = true ---@field K2_AttachToComponent:fun(Parent:USceneComponent,SocketName:FName,LocationRule:EAttachmentRule,RotationRule:EAttachmentRule,ScaleRule:EAttachmentRule,bWeldSimulatedBodies:bool):bool UGCLogSystem.Log("[UGCPlayerPawn_InitHook]") self.SM_Gear_L:SetVisibility(true, true) self.SM_Gear_R:SetVisibility(true, true) self.SM_Gear_L:SetHiddenInGame(false); self.SM_Gear_R:SetHiddenInGame(false); self.SM_Gear_L:K2_AttachToComponent(self.Mesh, self.HookSocketName_Mid, EAttachmentRule.KeepRelative, EAttachmentRule.KeepRelative, EAttachmentRule.KeepRelative, true) self.SM_Gear_R:K2_AttachToComponent(self.Mesh, self.HookSocketName_Mid, EAttachmentRule.KeepRelative, EAttachmentRule.KeepRelative, EAttachmentRule.KeepRelative, true) self.SM_Gear_L:K2_SetRelativeLocation({X=-5,Y=-10,Z=22}) self.SM_Gear_L:K2_SetRelativeRotation({Pitch=0,Yaw=-90,Roll=90}) self.SM_Gear_R:K2_SetRelativeLocation({X=-5,Y=-10,Z=-22}) self.SM_Gear_R:K2_SetRelativeRotation({Pitch=0,Yaw=-90,Roll=90}) UGCLogSystem.Log("[UGCPlayerPawn_InitHook] End") end function UGCPlayerPawn:DetachHookMesh() --UGCLogSystem.Log("[UGCPlayerPawn_DetachHookMesh]") --self.SM_Gear_L:DetachFromParent(true, true) --self.SM_Gear_R:DetachFromParent(true, true) end function UGCPlayerPawn:AddHookEnergy(DeltaTime) self.HookEnergy = math.clamp(self.HookEnergy + DeltaTime * self.HookEnergyRecoverySpeed, 0, self.HookMaxEnergy) end function UGCPlayerPawn:CheckCanHook() return UGCGameSystem.GameState:GetEnablePlayerSkill(CustomEnum.EPlayerSkill.Hook) and self.HookEnergy >= self.HookEnergyCost end function UGCPlayerPawn:HookSkill(CameraForward, InIsTwoHook) UGCLogSystem.Log("[UGCPlayerPawn_HookSkill]") if (not UGCGameSystem.IsServer()) or self.bHooking or (not self.bCanActiveSkill) then return end if self:CheckCanHook() then self.HookEnergy = self.HookEnergy - self.HookEnergyCost else return end self.AutoStopHookHandle = UGCEventSystem.SetTimer(self, self.StopHookSkill, self.PullPlayerMaxTime) self:SetCanActiveSkill(false) self.EnableTwoHook = InIsTwoHook self.bHooking = true self.SmartAimLeftFound, self.SmartAimLocationLeft = self:FindHookAttachmentPoint(false, CameraForward) --UGCLogSystem.Log("[UGCPlayerPawn_HookSkill] SmartAimLocationLeft:%s", VectorHelper.ToString(self.SmartAimLocationLeft)) if self.EnableTwoHook then self.SmartAimRightFound, self.SmartAimLocationRight = self:FindHookAttachmentPoint(true, CameraForward) --UGCLogSystem.Log("[UGCPlayerPawn_HookSkill] SmartAimLocationRight:%s", VectorHelper.ToString(self.SmartAimLocationRight)) end UGCSendRPCSystem.ActorRPCNotify(nil, self, "FireHook", self.EnableTwoHook, self.SmartAimLeftFound, self.SmartAimLocationLeft, self.SmartAimRightFound, self.SmartAimLocationRight) if self.SmartAimLeftFound or (self.EnableTwoHook and self.SmartAimRightFound) then --- 待钩锁勾住时拉动玩家 self.EnableHookPullPlayerHandle = UGCEventSystem.SetTimer(self, self.EnableHookPullPlayer, self.HookFlyTime) end end function UGCPlayerPawn:StopHookSkill() UGCLogSystem.Log("[UGCPlayerPawn_StopHookSkill]") if not UGCGameSystem.IsServer() or not self.bHooking or self.SetNotHookingHandle then return end UGCLogSystem.Log("[UGCPlayerPawn_StopHookSkill] Start") if self.AutoStopHookHandle then UGCEventSystem.StopTimer(self.AutoStopHookHandle) self.AutoStopHookHandle = nil end self:SetCanActiveSkill(true) if self.EnableHookPullPlayerHandle then UGCEventSystem.StopTimer(self.EnableHookPullPlayerHandle) self.EnableHookPullPlayerHandle = nil end --- 停止拉动玩家 self:DisableHookPullPlayer() UGCLogSystem.Log("[UGCPlayerPawn_StopHookSkill] DisableHookPullPlayer Finish") --- 收回钩锁 UGCSendRPCSystem.ActorRPCNotify(nil, self, "RecoverHook") --- 待钩锁收回后设置bHooking = false self.SetNotHookingHandle = UGCEventSystem.SetTimer(self, function() self.bHooking = false self.SetNotHookingHandle = nil end, self.HookFlyTime) end function UGCPlayerPawn:EnableHookPullPlayer() -- UGCLogSystem.Log("[UGCPlayerPawn_EnableHookPullPlayer]") self:SetVelocityClamp(self.MaxPullVelocity) self.EnabledHookPull = true self.EnableHookPullPlayerHandle = nil self.bHookPullingPlayer = true self:TurnOffGravityScale(true) -- local PullDir = self:GetHookPullDir() self:GetHookPullDir() self.StartPullDir = table.DeepCopy(self.HookPullDir) self.CharacterMovement:AddImpulse(VectorHelper.MulNumber(self.HookPullDir, self.StartHookPullImpulse), true) self.CharacterMovement.Velocity = VectorHelper.MulNumber(self.HookPullDir, VectorHelper.Length(self.CharacterMovement.Velocity)) if UGCGameSystem.IsServer() then UGCSendRPCSystem.ActorRPCNotify(nil, self, "EnableHookPullPlayer") else self:HookPullEffect() end end function UGCPlayerPawn:DisableHookPullPlayer() UGCLogSystem.Log("[UGCPlayerPawn_DisableHookPullPlayer]") self:SetVelocityClamp(self.VelocityClampBase) self.bHookPullingPlayer = false self:TurnOffGravityScale(false) --if not self.EnableTwoHook and self.EnabledHookPull then if self.EnabledHookPull then self.CharacterMovement:AddImpulse(VectorHelper.MulNumber({ X = 0, Y = 0, Z = 1 }, self.SimpleHookUpImpulse), true) end self.EnabledHookPull = false if UGCGameSystem.IsServer() then UGCSendRPCSystem.ActorRPCNotify(nil, self, "DisableHookPullPlayer") else self:DisableHookPullEffect() end UGCLogSystem.Log("[UGCPlayerPawn_DisableHookPullPlayer] Finish") end --- 获取发射位置,仅客户端执行 function UGCPlayerPawn:GetHookFireStartPos(IsRight) if IsRight then return self.SM_Gear_R:GetSocketLocation(self.GearSocketName) else return self.SM_Gear_L:GetSocketLocation(self.GearSocketName) end end function UGCPlayerPawn:GetHookMesh(IsRight) if IsRight then return self.SM_Gear_R else return self.SM_Gear_L end end --- 发射钩抓 function UGCPlayerPawn:FireHook(InEnableTwoHook, InSmartAimLeftFound, InSmartAimLocationLeft, InSmartAimRightFound, InSmartAimLocationRight) -- UGCLogSystem.Log("[UGCPlayerPawn_FireHook] PlayerKey:%s", tostring(self.PlayerKey)) self.EnableTwoHook = InEnableTwoHook self.SmartAimLeftFound = InSmartAimLeftFound self.SmartAimLocationLeft = InSmartAimLocationLeft self.SmartAimRightFound = InSmartAimRightFound self.SmartAimLocationRight = InSmartAimLocationRight if not UE.IsValid(self.LeftHook) then self.LeftHook = self:GetHook(false, self.PlayerKey) end if not UE.IsValid(self.RightHook) then self.RightHook = self:GetHook(true, self.PlayerKey) end self.LeftHook:FireHook(self:GetHookFireStartPos(false), self.SmartAimLocationLeft, self.HookFlyTime, self, self.GearPropertyName_L, self.GearSocketName) if not self.SmartAimLeftFound then self.RecoverLeftHookHandle = UGCEventSystem.SetTimer(self, function() self.LeftHook:RecoverHook() self.RecoverLeftHookHandle = nil end, self.HookFlyTime ) end if self.EnableTwoHook then self.RightHook:FireHook(self:GetHookFireStartPos(true), self.SmartAimLocationRight, self.HookFlyTime, self, self.GearPropertyName_R, self.GearSocketName) if not self.SmartAimRightFound then self.RecoverRightHookHandle = UGCEventSystem.SetTimer(self, function() self.RightHook:RecoverHook() self.RecoverRightHookHandle = nil end, self.HookFlyTime ) end end self:FireHookEffect() end function UGCPlayerPawn:FireHookEffect() if self.PlayerKey == UGCSystemLibrary.GetLocalPlayerKey() then SoundSystem.PlaySound(SoundSystem.ESound.HookFire) end self.P_HookFire_L:SetActive(true, true) if self.EnableTwoHook then self.P_HookFire_R:SetActive(true, true) end end function UGCPlayerPawn:HookPullEffect() if self.PlayerKey == UGCSystemLibrary.GetLocalPlayerKey() then SoundSystem.PlaySound(SoundSystem.ESound.Impulse) end self.P_HookFly_L:SetActive(true, true) self.P_HookFly_R:SetActive(true, true) end function UGCPlayerPawn:DisableHookPullEffect() self.P_HookFly_L:SetActive(false, false) self.P_HookFly_R:SetActive(false, false) end function UGCPlayerPawn:RecoverHook() if self.RecoverLeftHookHandle then UGCEventSystem.StopTimer(self.RecoverLeftHookHandle) self.RecoverLeftHookHandle = nil end self.LeftHook:RecoverHook() if self.EnableTwoHook then if self.RecoverRightHookHandle then UGCEventSystem.StopTimer(self.RecoverRightHookHandle) self.RecoverRightHookHandle = nil end self.RightHook:RecoverHook() end end function UGCPlayerPawn:GetHookTraceStartPosition(IsRight) return VectorHelper.ToLuaTable(self:K2_GetActorLocation()) end function UGCPlayerPawn:GetTraceObjectTypes() return {EObjectTypeQuery.ObjectTypeQuery1 } end --- 查询附着点 ---@param IsRight bool ---@param CameraForward FVector ---@param FindDis float 查询的距离 默认为10000 ---@param FindNum uint 旋转查询的次数 默认为3 ---@return bool,FVector 是否检测到目标位置,抓钩目标的位置 function UGCPlayerPawn:FindHookAttachmentPoint(IsRight, CameraForward, FindDis, FindNum) UGCLogSystem.Log("[UGCPlayerPawn_FindHookAttachmentPoint] " .. (IsRight and "Right" or "Left")) if FindDis == nil then FindDis = self.HookMaxDis end if FindNum == nil or FindNum <= 0 then FindNum = 3 end local CameraRotation = KismetMathLibrary.Conv_VectorToRotator(CameraForward) local DetectDeflectionRotation = {Pitch=0.000000,Yaw=-11.000000,Roll=0.000000} if self.EnableTwoHook then if IsRight then DetectDeflectionRotation.Yaw = 11.000000 end else FindNum = 1 DetectDeflectionRotation.Yaw = 0.000000 end local TraceEndPos, FirstEndPos local TraceStartPos = self:GetHookTraceStartPosition(IsRight) UGCLogSystem.Log("[UGCPlayerPawn_FindHookAttachmentPoint] FindNum:%s", tostring(FindNum)) for i = 1, FindNum do local TargetCombineRotator = table.DeepCopy(DetectDeflectionRotation) TargetCombineRotator.Yaw = DetectDeflectionRotation.Yaw * i local TargetRotation = KismetMathLibrary.ComposeRotators(CameraRotation, TargetCombineRotator) local TraceDir = KismetMathLibrary.GetForwardVector(TargetRotation) local TraceEndDir = VectorHelper.MulNumber(TraceDir, FindDis) TraceEndPos = VectorHelper.Add(TraceStartPos, TraceEndDir) if i == 1 then FirstEndPos = table.DeepCopy(TraceEndPos) end --- 这里最多将触发3次检测 首次线条检测,未检测到则小球体检测,又未检测到则大球体检测 ---@field LineTraceSingleForObjects fun(WorldContextObject:UObject,Start:FVector,End:FVector,ObjectTypes:ULuaArrayHelper,bTraceComplex:bool,ActorsToIgnore:ULuaArrayHelper,DrawDebugType:EDrawDebugTrace,OutHit:FHitResult,bIgnoreSelf:bool,TraceColor:FLinearColor,TraceHitColor:FLinearColor,DrawTime:float):bool,FHitResult local bHit, HitResult = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, TraceEndPos, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) local IsSphere = false local FinishSphereRadius = 0. if not bHit then if self.EnableTwoHook then TraceEndDir = VectorHelper.MulNumber(TraceDir, self.TwoHookTraceMaxDis) TraceEndPos = VectorHelper.Add(TraceStartPos, TraceEndDir) IsSphere = true local SmallSphereTraceStartPos = VectorHelper.Add(TraceStartPos, VectorHelper.MulNumber(TraceDir, self.SmallSphereStartDis)) ---@field SphereTraceSingleForObjects fun(WorldContextObject:UObject,Start:FVector,End:FVector,Radius:float,ObjectTypes:ULuaArrayHelper,bTraceComplex:bool,ActorsToIgnore:ULuaArrayHelper,DrawDebugType:EDrawDebugTrace,OutHit:FHitResult,bIgnoreSelf:bool,TraceColor:FLinearColor,TraceHitColor:FLinearColor,DrawTime:float):bool,FHitResult bHit, HitResult = TraceManager.SphereTraceSingleForObjects(self, TraceEndPos, SmallSphereTraceStartPos, self.SmartAimMediumTraceRadius, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) FinishSphereRadius = self.SmartAimMediumTraceRadius if bHit then local bLineHit, LineHitResultInst = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, HitResult.ImpactPoint, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) UGCLogSystem.Log("[UGCPlayerPawn_FindHookAttachmentPoint] bLineHit:%s Distance:%s",tostring(bLineHit), tostring(LineHitResultInst.Distance)) if bLineHit and LineHitResultInst.Distance <= self.HookMaxDis then return true, VectorHelper.ToLuaTable(LineHitResultInst.ImpactPoint) else bHit = false end end if not bHit then local BigSphereTraceStartPos = VectorHelper.Add(TraceStartPos, VectorHelper.MulNumber(TraceDir, self.BigSphereStartDis)) bHit, HitResult = TraceManager.SphereTraceSingleForObjects(self, TraceEndPos, BigSphereTraceStartPos, self.SmartAimLargeTraceRadius, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) FinishSphereRadius = self.SmartAimLargeTraceRadius if bHit then local bLineHit, LineHitResultInst = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, HitResult.ImpactPoint, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) UGCLogSystem.Log("[UGCPlayerPawn_FindHookAttachmentPoint] 2 bLineHit:%s Distance:%s",tostring(bLineHit), tostring(LineHitResultInst.Distance)) if bLineHit and LineHitResultInst.Distance <= self.HookMaxDis then return true, VectorHelper.ToLuaTable(LineHitResultInst.ImpactPoint) else bHit = false end end end else local SmallSphereTraceStartPos = VectorHelper.Add(TraceStartPos, VectorHelper.MulNumber(TraceDir, self.OneHookSecondTraceStartDis)) ---@field SphereTraceSingleForObjects fun(WorldContextObject:UObject,Start:FVector,End:FVector,Radius:float,ObjectTypes:ULuaArrayHelper,bTraceComplex:bool,ActorsToIgnore:ULuaArrayHelper,DrawDebugType:EDrawDebugTrace,OutHit:FHitResult,bIgnoreSelf:bool,TraceColor:FLinearColor,TraceHitColor:FLinearColor,DrawTime:float):bool,FHitResult bHit, HitResult = TraceManager.SphereTraceSingleForObjects(self, SmallSphereTraceStartPos, TraceEndPos, self.OneHookSecondTraceRadius, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) end end if bHit then -- UGCLogSystem.Log("[UGCPlayerPawn_FindHookAttachmentPoint]") --- 防止球体检测过程前段中出现碰撞,进行二次线条检测 if IsSphere then local bHitInst, HitResultInst = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, HitResult.ImpactPoint, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) if bHitInst then return true, VectorHelper.ToLuaTable(HitResultInst.ImpactPoint) else return true, VectorHelper.ToLuaTable(HitResult.ImpactPoint) end --if VectorHelper.Equal(HitResult.Location, HitResult.ImpactPoint) then -- local ActorPos = HitResult.Actor:Get():K2_GetActorLocation() -- local EndPos = VectorHelper.Add(HitResult.ImpactPoint, KismetMathLibrary.ClampVectorSize(VectorHelper.Sub(HitResult.ImpactPoint, ActorPos), FinishSphereRadius)) -- local bHitInst, HitResultInst = TraceManager.LineTraceSingleForObjects(self, HitResult.ImpactPoint, EndPos, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug) -- if bHitInst then -- return true, VectorHelper.ToLuaTable(HitResultInst.ImpactPoint) -- else -- return true, VectorHelper.ToLuaTable(EndPos) -- end --else -- return true, VectorHelper.ToLuaTable(HitResult.ImpactPoint) --end --if bHitInst then -- return true, VectorHelper.ToLuaTable(HitResultInst.ImpactPoint) --else -- return true, VectorHelper.ToLuaTable(HitResult.ImpactPoint) --end -- return true, VectorHelper.ToLuaTable(HitResult.ImpactPoint) else return true, VectorHelper.ToLuaTable(HitResult.ImpactPoint) end end end return false, VectorHelper.ToLuaTable(FirstEndPos) end UGCPlayerPawn.bClientLastTracePointIsRight = false UGCPlayerPawn.ClientHookTraceNum_R = 1 UGCPlayerPawn.ClientHookTraceNum_L = 1 UGCPlayerPawn.ClientHookTraceFrequency = 20 UGCPlayerPawn.ClientHookLastTraceIntervalTime = 0 function UGCPlayerPawn:SetClientHookTraceNum(IsRight, NewNum) if IsRight then self.ClientHookTraceNum_R = NewNum else self.ClientHookTraceNum_L = NewNum end end function UGCPlayerPawn:ClientFindPoint() if self.ClientTracing then return end self.ClientTracing = true local IsRight = self.bClientLastTracePointIsRight if not GlobalConfigs.GameSetting.bIsTwoHook then return end local TraceNum if IsRight then TraceNum = self.ClientHookTraceNum_R else TraceNum = self.ClientHookTraceNum_L end local LocalCamera = UGCSystemLibrary.GetLocalPlayerController().PlayerCameraManager local CameraForward = LocalCamera:GetActorForwardVector() local CameraRotation = KismetMathLibrary.Conv_VectorToRotator(CameraForward) local TargetCombineRotator = {Pitch=0.000000,Yaw=-11.000000 * (TraceNum // 3 + 1) ,Roll=0.000000} if IsRight then TargetCombineRotator.Yaw = -TargetCombineRotator.Yaw end local TraceStartPos = self:K2_GetActorLocation() local TargetRotation = KismetMathLibrary.ComposeRotators(CameraRotation, TargetCombineRotator) local TraceDir = KismetMathLibrary.GetForwardVector(TargetRotation) --UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] TraceStartPos:%s, TraceEndPos:%s", VectorHelper.ToString(TraceStartPos), VectorHelper.ToString(TraceEndPos)) local bHit, HitResult, FinishSphereRadius local TraceState = TraceNum % 3 local TraceEndDir if TraceState == 0 then TraceEndDir = VectorHelper.MulNumber(TraceDir, self.HookMaxDis) else TraceEndDir = VectorHelper.MulNumber(TraceDir, self.TwoHookTraceMaxDis) end local TraceEndPos = VectorHelper.Add(TraceStartPos, TraceEndDir) if TraceState == 0 then bHit, HitResult = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, TraceEndPos, self:GetTraceObjectTypes(), {}, false) elseif TraceState == 1 then local SmallSphereTraceStartPos = VectorHelper.Add(TraceStartPos, VectorHelper.MulNumber(TraceDir, self.SmallSphereStartDis)) bHit, HitResult = TraceManager.SphereTraceSingleForObjects(self, TraceEndPos, SmallSphereTraceStartPos, self.SmartAimMediumTraceRadius, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug_Client) FinishSphereRadius = self.SmartAimMediumTraceRadius if bHit then local bLineHit, LineHitResultInst = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, HitResult.ImpactPoint, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug_Client) if bLineHit and LineHitResultInst.Distance <= self.HookMaxDis then HitResult = LineHitResultInst else bHit = false end end elseif TraceState == 2 then local BigSphereTraceStartPos = VectorHelper.Add(TraceStartPos, VectorHelper.MulNumber(TraceDir, self.BigSphereStartDis)) bHit, HitResult = TraceManager.SphereTraceSingleForObjects(self, TraceEndPos, BigSphereTraceStartPos, self.SmartAimLargeTraceRadius, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug_Client) FinishSphereRadius = self.SmartAimLargeTraceRadius if bHit then local bLineHit, LineHitResultInst = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, HitResult.ImpactPoint, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug_Client) if bLineHit and LineHitResultInst.Distance <= self.HookMaxDis then HitResult = LineHitResultInst else bHit = false end end else self:SetClientHookTraceNum(IsRight, 1) return end --UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] IsRight:%s, TraceNum:%s, bHit:%s, ImpactPoint:%s", tostring(IsRight), tostring(TraceNum), tostring(bHit), VectorHelper.ToString(HitResult.ImpactPoint)) if bHit then --if TraceState > 0 then -- local bHitInst, HitResultInst = TraceManager.LineTraceSingleForObjects(self, HitResult.ImpactPoint, HitResult.Actor:Get():K2_GetActorLocation(), self:GetTraceObjectTypes(), {}, false) -- if bHitInst then -- HitResult = HitResultInst -- end --end local TracePos = HitResult.ImpactPoint if TraceState > 0 then --local bHitInst, HitResultInst = TraceManager.LineTraceSingleForObjects(self, TraceStartPos, TracePos, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug_Client) --if bHitInst then -- TracePos = HitResultInst.ImpactPoint --end --if VectorHelper.Equal(HitResult.Location, HitResult.ImpactPoint) then -- UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] ImpactPoint:%s, Location:%s", VectorHelper.ToString(HitResult.ImpactPoint), VectorHelper.ToString(HitResult.Location)) -- UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] Is Equal") -- local ActorPos = HitResult.Actor:Get():K2_GetActorLocation() -- local EndPos = VectorHelper.Add(HitResult.ImpactPoint, KismetMathLibrary.ClampVectorSize(VectorHelper.Sub(HitResult.ImpactPoint, ActorPos), FinishSphereRadius)) -- local bHitInst, HitResultInst = TraceManager.LineTraceSingleForObjects(self, HitResult.ImpactPoint, EndPos, self:GetTraceObjectTypes(), {}, self.bEnableDrawDebug_Client) -- if bHitInst then -- TracePos = HitResultInst.ImpactPoint -- else -- TracePos = EndPos -- end --else -- UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] Is Not Equal") --end end self:SetClientHookTraceNum(IsRight, 0) local HookTraceWidget = WidgetManager:GetPanel(WidgetConfig.EUIType.HookTrace) HookTraceWidget:UpdateTracePos(IsRight, true, TracePos) --if TraceState > 0 then -- UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] ImpactPoint:%s, Location:%s", VectorHelper.ToString(HitResult.ImpactPoint), VectorHelper.ToString(HitResult.Location)) -- if VectorHelper.Equal(HitResult.ImpactPoint, HitResult.Location) then -- UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] Is Equal") -- else -- UGCLogSystem.Log("[UGCPlayerPawn_ClientFindPoint] Is Not Equal") -- end --end else if TraceNum == 8 then self:SetClientHookTraceNum(IsRight, 0) local HookTraceWidget = WidgetManager:GetPanel(WidgetConfig.EUIType.HookTrace) HookTraceWidget:UpdateTracePos(IsRight, false) else self:SetClientHookTraceNum(IsRight, TraceNum + 1) end end self.bClientLastTracePointIsRight = not self.bClientLastTracePointIsRight self.ClientTracing = false end function UGCPlayerPawn:ClientTickHookTrace(DeltaTime) if GlobalConfigs.GameSetting.bIsTwoHook and UGCGameSettingSystem.GetDeviceLevel() > 0 then self.ClientHookLastTraceIntervalTime = self.ClientHookLastTraceIntervalTime + DeltaTime if self.ClientHookLastTraceIntervalTime >= 1./ self.ClientHookTraceFrequency then self.ClientHookLastTraceIntervalTime = self.ClientHookLastTraceIntervalTime - 1./ self.ClientHookTraceFrequency self:ClientFindPoint() end end end function UGCPlayerPawn:GetHookPullDir() if self.SmartAimLeftFound then self.HookLeftDir = VectorHelper.Sub(self.SmartAimLocationLeft, self:K2_GetActorLocation()) self.HookLeftDir = VectorHelper.MulNumber(self.HookLeftDir, 1. / VectorHelper.Length(self.HookLeftDir)) else self.HookLeftDir = VectorHelper.VectorZero() end self.HookRightDir = VectorHelper.VectorZero() if self.EnableTwoHook and self.SmartAimRightFound then self.HookRightDir = VectorHelper.Sub(self.SmartAimLocationRight, self:K2_GetActorLocation()) self.HookRightDir = VectorHelper.MulNumber(self.HookRightDir, 1. / VectorHelper.Length(self.HookRightDir)) end self.HookPullDir = VectorHelper.Add(self.HookLeftDir, self.HookRightDir) self.HookPullDir = VectorHelper.MulNumber(self.HookPullDir, 1. / VectorHelper.Length(self.HookPullDir)) return self.HookPullDir end --- 自动停止条件 function UGCPlayerPawn:AutoStopHookPullCondition() if not UGCGameSystem.IsServer() or not self.bAutoStopHookPush then return false end if VectorHelper.CosineValue(self.StartPullDir, self.HookPullDir) < 0 then return true end if self.EnableTwoHook then if VectorHelper.CosineValue(self.StartPullDir, self.HookLeftDir) < 0 then return true end if VectorHelper.CosineValue(self.StartPullDir, self.HookRightDir) < 0 then return true end else if VectorHelper.Length(VectorHelper.Sub(self.SmartAimLocationLeft, self:K2_GetActorLocation())) <= self.UpImpulseDistanceThreshold then return true end end return false end function UGCPlayerPawn:TickPullPlayer(DeltaTime) self:AddHookEnergy(DeltaTime) if self.bHookPullingPlayer then -- local PullDir = self:GetHookPullDir() self:GetHookPullDir() --- 自动停止拉动可以设置速度方向而更稳定 if self:AutoStopHookPullCondition() then self:StopHookSkill() return end -- Test self.HookPullDir = self.StartPullDir -- Test End self.CharacterMovement:AddImpulse(VectorHelper.MulNumber(self.HookPullDir, self.HookPullImpulse * DeltaTime), true) if self.CharacterMovement.MovementMode ~= EMovementMode.MOVE_Falling then self.CharacterMovement:SetMovementMode(EMovementMode.MOVE_Falling); end if self.bAutoStopHookPush then self.CharacterMovement.Velocity = VectorHelper.MulNumber(self.HookPullDir, math.clamp(VectorHelper.Length(self.CharacterMovement.Velocity), self.MinPullVelocity, self.MaxPullVelocity)) else self.CharacterMovement.Velocity = KismetMathLibrary.ClampVectorSize(self.CharacterMovement.Velocity, self.MinPullVelocity, self.MaxPullVelocity) end end end --------------------------------------------------------- HookSkill End --------------------------------------------------------- --- 测试按键按下在服务器触发的函数 function UGCPlayerPawn:TestButtonFun(CameraForwardVector) -- self:PlayerDashSkill(self:GetActorForwardVector(), 1, 5000) -- self:PlayerDashSkill(CameraForwardVector, 1, 5000) -- self:DashImpulse(CameraForwardVector, 8000, 1500, 0.8) -- self:TestMoveComponentTo(CameraForwardVector) end function UGCPlayerPawn:TestButtonPressed(CameraForwardVector) self:HookSkill(CameraForwardVector) end function UGCPlayerPawn:TestButtonReleased() self:StopHookSkill() end --- Server的BeginPlay触发及Client的ClientMustBeExeBeginPlay触发 function UGCPlayerPawn:SkillInit() if UGCGameSystem.IsServer() then --self:InitDashImpulse() else self:InitHook() end end function UGCPlayerPawn:SkillEndPlay() if UGCGameSystem.IsServer() then else self:DetachHookMesh() end end function UGCPlayerPawn:TickSkill(DeltaTime) self:DashImpulseTick(DeltaTime) -- self:TickDash(DeltaTime) self:TickPullPlayer(DeltaTime) self:LaunchTick(DeltaTime) if UGCGameSystem.IsServer() then else if UGCSystemLibrary.GetLocalPlayerPawn() == self then self:ClientTickHookTrace(DeltaTime) end end end function UGCPlayerPawn:GetAvailableServerRPCs() return end return UGCPlayerPawn;