- Implemented WeaponFeedback class for handling weapon-related feedbacks such as hit effects and attack sounds. - Added meta file for AddressableManagerWindow to manage addressable assets. - Included a new jump.data file for profiler data.
145 lines
6.1 KiB
C#
145 lines
6.1 KiB
C#
using UnityEngine;
|
||
using System.Collections;
|
||
|
||
namespace BaseGames.Player.States
|
||
{
|
||
/// <summary>
|
||
/// 冲刺状态(架构 05_PlayerModule §2 + §12)。
|
||
/// 施加水平位移 + 无敌帧;冲刺期间重力归零,结束后恢复;
|
||
/// 地面与空中统一使用此状态,空中每次离地限冲刺一次(_dashChargeUsed);
|
||
/// 需解锁 AbilityType.Dash 才能进入(PlayerController 负责条件检查)。
|
||
/// </summary>
|
||
public class DashState : PlayerStateBase
|
||
{
|
||
private float _timer;
|
||
private float _cooldownTimer;
|
||
/// <summary>
|
||
/// 无敌的独立冷却计时器。由 TickCooldown 每帧减少。
|
||
/// </summary>
|
||
private float _invincibilityCooldownTimer;
|
||
private int _facingDir;
|
||
|
||
/// <summary>本次离地后是否已消耗过冲刺次数。落地或下劈命中(Pogo)时重置。</summary>
|
||
private bool _dashChargeUsed;
|
||
|
||
public bool CanDash => _cooldownTimer <= 0f;
|
||
/// <summary>空中冲刺可用条件:冷却就绪 且 本次离地内尚未冲刺过。</summary>
|
||
public bool CanDashMidAir => _cooldownTimer <= 0f && !_dashChargeUsed;
|
||
|
||
/// <summary>重置冲刺次数(落地或 Pogo 时由 IdleState/RunState/DownAttackState 调用)。</summary>
|
||
public void ResetDashCharge() => _dashChargeUsed = false;
|
||
|
||
/// <summary>消耗空中冲刺次数(DownDashState 进入时调用,与普通空中冲刺共享次数上限)。</summary>
|
||
public void ConsumeAirDashCharge() => _dashChargeUsed = true;
|
||
|
||
/// <summary>
|
||
/// 无敌帧是否已冷却,即本次冲刺可以获得无敌。
|
||
/// </summary>
|
||
public bool CanGrantInvincibility => _invincibilityCooldownTimer <= 0f;
|
||
|
||
/// <summary>重置无敌冷却(冲刺使用无敌后调用)。</summary>
|
||
public void ResetInvincibilityCooldown(float cd) => _invincibilityCooldownTimer = cd;
|
||
|
||
// ── IsInvincible 不再在状态层硬编码,改为全面依赖 Stats._invincibleTimer ────────────
|
||
// 冲刺无敌窗口 = BeginInvincibility(DashInvincibilityDuration) 设定的时间限 Stats._invincibleTimer
|
||
// PlayerController.TakeDamage 已改为将 Stats.IsInvincible 纳入硬直判断,居间无敌窗口自然失效。
|
||
// 不再需要 override IsInvincible。
|
||
|
||
public DashState(PlayerController owner) : base(owner) { }
|
||
|
||
public override void OnStateEnter()
|
||
{
|
||
Debug.Assert(Cfg != null, "[DashState] MovementConfig 未配置,请在 PlayerController Inspector 中绑定 MovementConfig SO。", _owner);
|
||
|
||
_facingDir = Owner.FacingDirection;
|
||
_timer = Cfg.DashDuration;
|
||
|
||
// 空中冲刺:记录本次离地已使用冲刺(地面冲刺不消耗,仅空中限制一次)
|
||
if (!Move.IsGrounded)
|
||
_dashChargeUsed = true;
|
||
|
||
// 无敌帧:
|
||
// 条件 1:已解锁 InvincibleDash
|
||
// 条件 2:无敌冷却已就绪(防止 spam 冲刺连序无敌)
|
||
// 窗口时长 = DashInvincibilityDuration < DashDuration,冲刺后段无保护
|
||
// 在设置冷却计时器前捕获,供后续动画选择使用
|
||
bool isInvincibleDash = Stats != null
|
||
&& Stats.HasAbility(AbilityType.InvincibleDash)
|
||
&& CanGrantInvincibility;
|
||
|
||
if (isInvincibleDash)
|
||
{
|
||
Stats.BeginInvincibility(Cfg.DashInvincibilityDuration);
|
||
_invincibilityCooldownTimer = Cfg.DashInvincibilityCooldown;
|
||
}
|
||
|
||
// 关闭重力,施加冲刺速度
|
||
Move?.SetGravityScale(0f);
|
||
Move?.Dash(new Vector2(_facingDir, 0f), Cfg.DashSpeed);
|
||
|
||
// 播放冲刺动画:无敌冲刺使用专属 Clip,留空时回退到普通冲刺 Clip
|
||
var dashClip = (isInvincibleDash && AnimCfg?.DashInvincible != null)
|
||
? AnimCfg.DashInvincible
|
||
: AnimCfg?.Dash;
|
||
if (dashClip != null) Anim?.Play(dashClip);
|
||
|
||
Feedback.TriggerPreset("dash");
|
||
}
|
||
|
||
public override void OnStateUpdate()
|
||
{
|
||
_timer -= Time.deltaTime;
|
||
if (_timer <= 0f)
|
||
{
|
||
EndDash();
|
||
return;
|
||
}
|
||
|
||
// 跳跃可取消冲刺:冲刺期间按跳跃立即中断并起跳。
|
||
// 空中冲刺时若有剩余空中跳跃次数,消耗一次并使用二段跳力度。
|
||
if (Buffer.ConsumeJump())
|
||
{
|
||
if (!Move.IsGrounded && Owner.AirJumpsLeft > 0)
|
||
{
|
||
Owner.UseAirJump();
|
||
Owner.GetState<JumpState>()?.SetDoubleJump(true);
|
||
}
|
||
Owner.TransitionTo(Owner.GetState<JumpState>());
|
||
return;
|
||
}
|
||
// 注:碰墙时不中止冲刺,完成完整冲刺时长(物理阻止位移,但计时继续)
|
||
}
|
||
|
||
public override void OnStateExit()
|
||
{
|
||
// 恢复默认重力
|
||
Move?.SetGravityScale(Cfg.DefaultGravityScale);
|
||
_cooldownTimer = Cfg.DashCooldown;
|
||
}
|
||
|
||
public override void OnStateFixedUpdate()
|
||
{
|
||
// 冲刺期间保持冲刺速度(防止摩擦力减速)
|
||
if (_timer > 0f)
|
||
Move?.Dash(new Vector2(_facingDir, 0f), Cfg.DashSpeed);
|
||
}
|
||
|
||
private void EndDash()
|
||
{
|
||
// 双轴速度归零,防止冲刺结束时角色带着 DashSpeed 冲出平台边缘后继续向前飞行。
|
||
Move?.ZeroVelocity();
|
||
if (Move != null && Move.IsGrounded)
|
||
Owner.TransitionTo(Owner.GetState<IdleState>());
|
||
else
|
||
Owner.TransitionTo(Owner.GetState<FallState>());
|
||
}
|
||
|
||
/// <summary>每帧减少冒小帮冷却(由 PlayerController.Update 调用)。</summary>
|
||
public void TickCooldown(float dt)
|
||
{
|
||
if (_cooldownTimer > 0f) _cooldownTimer -= dt;
|
||
if (_invincibilityCooldownTimer > 0f) _invincibilityCooldownTimer -= dt;
|
||
}
|
||
}
|
||
}
|