diff --git a/Assets/_Game/Data/Player/PLY_PlayerMovementConfig.asset b/Assets/_Game/Data/Player/PLY_PlayerMovementConfig.asset
index 6e157b6..240a78f 100644
--- a/Assets/_Game/Data/Player/PLY_PlayerMovementConfig.asset
+++ b/Assets/_Game/Data/Player/PLY_PlayerMovementConfig.asset
@@ -29,6 +29,7 @@ MonoBehaviour:
DashCooldown: 0.4
DashInvincibilityDuration: 0.2
DashInvincibilityCooldown: 0.9
+ PogoBounceForce: 15
DownDashSpeed: 22
DownDashDuration: 0.25
WallSlideSpeed: 3
diff --git a/Assets/_Game/Scripts/Combat/HitBox.cs b/Assets/_Game/Scripts/Combat/HitBox.cs
index 54929f8..0500d88 100644
--- a/Assets/_Game/Scripts/Combat/HitBox.cs
+++ b/Assets/_Game/Scripts/Combat/HitBox.cs
@@ -77,6 +77,13 @@ namespace BaseGames.Combat
/// 命中确认委托(PlayerCombat / EnemyCombat 订阅)。
public event System.Action OnHitConfirmed;
+ ///
+ /// 命中可破坏物(IBreakable)确认事件。
+ /// 与 OnHitConfirmed 区分:不走 HurtBox 伤害流水线,不参与灵力获取;
+ /// 供下劈弹跳等"打到实体即生效"的逻辑订阅。
+ ///
+ public event System.Action OnBreakableHitConfirmed;
+
// 宿主投射物缓存(Activate 时填入,DamageInfo.SourceProjectile 写入用)
private Projectile _ownerProjectile;
@@ -260,7 +267,10 @@ namespace BaseGames.Combat
// ③ 命中 IBreakable(机关/障碍物)
if (other.TryGetComponent(out var breakable))
+ {
breakable.TryInteract(info);
+ OnBreakableHitConfirmed?.Invoke(info);
+ }
}
// ── 当前激活期已命中目标集合(防止复合子 Collider 导致同帧多次命中)────────────
diff --git a/Assets/_Game/Scripts/Player/PlayerMovement.cs b/Assets/_Game/Scripts/Player/PlayerMovement.cs
index 7400e17..8de7025 100644
--- a/Assets/_Game/Scripts/Player/PlayerMovement.cs
+++ b/Assets/_Game/Scripts/Player/PlayerMovement.cs
@@ -214,6 +214,17 @@ namespace BaseGames.Player
_rb.velocity = new Vector2(_rb.velocity.x, _rb.velocity.y * _config.JumpCutMultiplier);
}
+ ///
+ /// 下劈命中弹跳(DownAttackState 调用)。覆盖当前垂直速度为 PogoBounceForce;
+ /// 固定高度(JumpCancelledEvent 仅 JumpState 处理,弹跳不受变高跳截断影响)。
+ ///
+ public void PogoBounce()
+ {
+ _rb.velocity = new Vector2(_rb.velocity.x, _config.PogoBounceForce);
+ _coyoteTimer = 0f;
+ _slopeSnapDisabled = true;
+ }
+
///
/// 二段跳。覆盖当前垂直速度为 DoubleJumpForce。
/// FallState / JumpState 在检测到 HasAbility(DoubleJump) && AirJumpsLeft > 0 时调用。
diff --git a/Assets/_Game/Scripts/Player/PlayerMovementConfigSO.cs b/Assets/_Game/Scripts/Player/PlayerMovementConfigSO.cs
index 0917655..9485a6a 100644
--- a/Assets/_Game/Scripts/Player/PlayerMovementConfigSO.cs
+++ b/Assets/_Game/Scripts/Player/PlayerMovementConfigSO.cs
@@ -60,6 +60,10 @@ namespace BaseGames.Player
[Tooltip("无敌的独立冷却(秒)。CD 内再次冲刺不会获得无敌帧,防止连冲变相持续无敌(推荐 0.9s)。")]
public float DashInvincibilityCooldown = 0.9f;
+ [Header("下劈弹跳(Pogo)")]
+ [Tooltip("下劈命中后的向上弹跳初速度。推荐略低于 JumpForce(如 JumpForce=18 时取 15),\n弹跳略矮于满跳;固定高度,不受变高跳截断影响。")]
+ public float PogoBounceForce = 15f;
+
[Header("下冲刺")]
[Tooltip("向下冲刺速度(单位/秒)。推荐 22,快速向下穿透空间。")]
public float DownDashSpeed = 22f;
diff --git a/Assets/_Game/Scripts/Player/States/DownAttackState.cs b/Assets/_Game/Scripts/Player/States/DownAttackState.cs
index 3754a61..6d883f5 100644
--- a/Assets/_Game/Scripts/Player/States/DownAttackState.cs
+++ b/Assets/_Game/Scripts/Player/States/DownAttackState.cs
@@ -58,10 +58,10 @@ namespace BaseGames.Player.States
{
if (_hasHitEnemy) return;
_hasHitEnemy = true;
- // Pogo 弹跳:命中敌人后向上弹起,同时重置空中能力(等同落地效果)
+ // Pogo 弹跳:命中后向上弹起(独立弹跳力,略矮于满跳),同时重置空中能力(等同落地效果)
Owner.ResetAirJumps();
Owner.GetState()?.ResetDashCharge();
- Move.Jump();
+ Move.PogoBounce();
}
public override void OnStateUpdate()
@@ -73,6 +73,25 @@ namespace BaseGames.Player.States
}
}
+ public override void OnStateFixedUpdate()
+ {
+ // 下劈期间保留完整空中水平操控(与 FallState 同款贴墙保护,防止压墙摩擦/卡角)
+ if (Mathf.Abs(Input.MoveInput.x) > 0.01f)
+ {
+ int inputDir = Input.MoveInput.x > 0 ? 1 : -1;
+ var wd = Owner.WallDetector;
+ bool currentFrameWall = inputDir > 0 ? Move.IsWallRight : Move.IsWallLeft;
+ if (currentFrameWall
+ || (wd != null && (wd.IsTouchingWall && wd.WallDirection == inputDir
+ || wd.HasPartialContact(inputDir))))
+ Move.ZeroHorizontalVelocity();
+ else
+ Move.Move(Input.MoveInput.x * Cfg.RunSpeed);
+ }
+ else
+ Move.ZeroHorizontalVelocity();
+ }
+
private void OnClipEnd()
{
if (_exited) return;
diff --git a/Assets/_Game/Scripts/Player/WeaponHitBoxInstance.cs b/Assets/_Game/Scripts/Player/WeaponHitBoxInstance.cs
index 0b55717..84404ca 100644
--- a/Assets/_Game/Scripts/Player/WeaponHitBoxInstance.cs
+++ b/Assets/_Game/Scripts/Player/WeaponHitBoxInstance.cs
@@ -31,7 +31,7 @@ namespace BaseGames.Player
private AttackDirection _activeDir;
private IFeedbackPlayer _feedback;
- /// 下劈命中确认事件(供 DownAttackState Pogo 逻辑)。
+ /// 下劈命中确认事件(供 DownAttackState Pogo 逻辑)。命中 HurtBox 或可破坏物均触发。
public event System.Action OnDownHitConfirmed;
/// 任意 HitBox 命中确认事件(供 PlayerCombat 订阅通用命中反馈)。
@@ -41,7 +41,10 @@ namespace BaseGames.Player
{
_allHitBoxes = GetComponentsInChildren(true);
foreach (var hb in _allHitBoxes)
- hb.OnHitConfirmed += OnAnyHitConfirmed;
+ {
+ hb.OnHitConfirmed += OnAnyHitConfirmed;
+ hb.OnBreakableHitConfirmed += OnAnyBreakableHitConfirmed;
+ }
_feedback = GetComponentInChildren() ?? NullFeedbackPlayer.Instance;
}
@@ -57,6 +60,17 @@ namespace BaseGames.Player
OnDownHitConfirmed?.Invoke(info);
}
+ ///
+ /// 命中可破坏物:播放轻量打击反馈;下劈方向时同样触发弹跳。
+ /// 不转发 OnHitConfirmed(可破坏物不参与灵力获取)。
+ ///
+ private void OnAnyBreakableHitConfirmed(DamageInfo info)
+ {
+ _feedback.PlayHit(HitWeight.Light);
+ if (_activeDir == AttackDirection.Down)
+ OnDownHitConfirmed?.Invoke(info);
+ }
+
// ── 公共 API ──────────────────────────────────────────────────────────
///