using System.Collections; using Animancer; using BaseGames.Boss; using BaseGames.Combat; using UnityEngine; namespace BaseGames.Enemies.Boss { /// /// 嘲风击落计数器(Phase 2)。 /// 由 直接调用 , /// 累计命中达到阈值后触发击落序列(下落 → 硬直 → 复位浮空)。 /// /// ⚠️ HurtBox 无公开 OnDamageTaken 事件,必须通过 EnemyBase.OnDamageTaken 虚方法转发。 /// public class ChaoFengKnockdownCounter : MonoBehaviour { [SerializeField] private int _threshold = 8; [Header("依赖引用")] [SerializeField] private ChaoFengBoss _boss; [SerializeField] private ChaoFengFloatController _floatCtrl; [Header("击落动画")] [SerializeField] private ClipTransition _knockdownHitClip; [Tooltip("击落后硬直动画(复用 Defeat_Pant Clip)")] [SerializeField] private ClipTransition _staggerClip; [SerializeField] private float _staggerDuration = 3f; private int _count; private bool _inKnockdown; private BaseGames.Core.IGroundedActor _playerGround; private Transform _cachedPlayer; /// /// 由 调用,累计受击并在达到阈值时触发击落。 /// 仅统计「玩家处于空中」时的命中(设计:空中攻击命中嘲风才计入击落)。 /// public void OnBossHit(DamageInfo info) { if (_inKnockdown || _boss == null || _boss.CurrentPhase != 1) return; if (!IsPlayerAirborne()) return; // Q6:仅玩家在空中的命中计数 _count++; if (_count >= _threshold) { _count = 0; StartCoroutine(KnockdownSequence()); } } /// /// 通过 Boss 缓存的 PlayerTransform 取玩家的 (PlayerMovement 实现), /// 判定其是否离地。取不到接口时按「空中」处理(保守计数,避免机制失效)。 /// private bool IsPlayerAirborne() { var player = _boss.PlayerTransform; if (player == null) return false; if (!ReferenceEquals(player, _cachedPlayer)) { _cachedPlayer = player; _playerGround = player.GetComponentInParent() ?? player.GetComponentInChildren(); } return _playerGround == null || !_playerGround.IsGrounded; } /// 强制结束正在进行中的击落序列(由 ChaoFengBoss.DefeatSequence 调用)。 public void ForceEnd() { StopAllCoroutines(); _inKnockdown = false; _count = 0; } private IEnumerator KnockdownSequence() { _inKnockdown = true; _boss.GetComponentInChildren()?.InterruptCurrentSkill(); if (_knockdownHitClip.Clip != null) _boss.Animancer.Play(_knockdownHitClip); yield return _floatCtrl.FallDown(); if (_staggerClip.Clip != null) _boss.Animancer.Play(_staggerClip); yield return new WaitForSeconds(_staggerDuration); yield return _floatCtrl.FloatUp(); _inKnockdown = false; } } }