using System.Collections;
using Animancer;
using BaseGames.Combat;
using BaseGames.Core;
using BaseGames.Core.Pool;
using UnityEngine;
using UnityEngine.Events;
namespace BaseGames.Enemies.Boss
{
///
/// 嘲风 Boss 主脚本。
///
/// Phase 0(地面):4 技能加权随机(回旋扇/扇形连击/小龙卷/大龙卷)。
/// Phase 1(空中):风石技能 + 击落计数机制。
///
/// 阶段过渡流程:
/// 1. BossBase.BeginPhaseTransition → OnBeginPhaseTransition(1) 立即播放过渡动画 + 开始浮空
/// 2. 无敌期结束(≥ _riseDuration+buffer)→ BossBase.EnterPhase(1) 广播阶段切换事件
///
/// ⚠️ 动画由本脚本通过 Animancer.Play() 完整控制,不在 BD 中调用 BD_PlayAnimation。
///
public class ChaoFengBoss : BossBase
{
[Header("浮空 / 击落")]
[SerializeField] private ChaoFengFloatController _floatController;
[SerializeField] private ChaoFengKnockdownCounter _knockdownCounter;
[Header("阶段过渡动画")]
[SerializeField] private ClipTransition _phaseTransitionClip;
[Header("回旋扇收招动画")]
[SerializeField] private ClipTransition _boomerangEndClip;
[Header("弹体发射点")]
[SerializeField] private Transform _boomerangMuzzle;
[SerializeField] private Transform _tornadoMuzzle;
[SerializeField] private Transform _windStoneMuzzle;
[Header("弹体配置(ProjectileConfigSO,PoolKey 须与弹体地址一致)")]
[SerializeField] private ProjectileConfigSO _boomerangConfig;
[SerializeField] private ProjectileConfigSO _tornadoSmallConfig;
[SerializeField] private ProjectileConfigSO _tornadoLargeConfig;
[SerializeField] private ProjectileConfigSO _windStoneConfig;
[Header("击败演出动画")]
[SerializeField] private ClipTransition _defeatStruggleClip;
[Tooltip("倒地喘气(循环);与 ChaoFengKnockdownCounter._staggerClip 共用同一 Clip")]
[SerializeField] private ClipTransition _defeatPantClip;
[SerializeField] private ClipTransition _defeatStandUpClip;
[SerializeField] private float _defeatPantDuration = 3f;
[Header("白屏回调(可接 CameraManager / VFX Event)")]
[SerializeField] private UnityEngine.Events.UnityEvent _onDefeatWhiteFlash;
// ── 阶段过渡钩子 ─────────────────────────────────────────────────────
///
/// 阶段过渡开始时立即播放过渡动画并启动浮空协程。
/// invincibleDuration 需在 BD_BossPhaseTransition 中配置为 ≥ _riseDuration + 缓冲(约 2.0s)。
///
protected override void OnBeginPhaseTransition(int targetPhase)
{
if (targetPhase == 1)
{
if (_phaseTransitionClip.Clip != null)
Animancer.Play(_phaseTransitionClip);
StartCoroutine(_floatController.FloatUp());
}
}
// ── 受击转发 ─────────────────────────────────────────────────────────
///
/// 转发受击事件至击落计数器。
/// ⚠️ HurtBox 无公开 OnDamageTaken 事件,必须通过此虚方法转发。
///
protected override void OnDamageTaken(DamageInfo info)
{
base.OnDamageTaken(info);
_knockdownCounter?.OnBossHit(info);
}
// ── 动画事件 ─────────────────────────────────────────────────────────
///
/// 回旋扇返回时由 ReturnProjectile 调用,触发收扇动画。
///
public void OnBoomerangReturned()
{
if (_boomerangEndClip.Clip != null)
Animancer.Play(_boomerangEndClip);
}
// ── 弹体生成 ─────────────────────────────────────────────────────────
///
/// 由技能动画 AnimationEvent 触发,生成对应弹体。
/// payload: "boomerang" / "tornado_small" / "tornado_large" / "wind_stone"
/// 生成后通过 ProjectileConfigSO 调用 Projectile.Initialize 注入速度/重力/伤害源与方向。
///
public override void SpawnProjectile(string payload)
{
var pool = ServiceLocator.GetOrDefault();
if (pool == null) return;
switch (payload)
{
case "boomerang":
SpawnConfiguredAt(pool, _boomerangConfig, "PROJ_Boomerang",
MuzzlePos(_boomerangMuzzle), AimDir(_boomerangMuzzle),
proj => (proj as ReturnProjectile)?.SetOwner(transform));
break;
case "tornado_small":
SpawnConfiguredAt(pool, _tornadoSmallConfig, "PROJ_TornadoSmall",
MuzzlePos(_tornadoMuzzle), AimDir(_tornadoMuzzle), null);
break;
case "tornado_large":
// 定点召唤于玩家当前位置(落点锁定)
if (PlayerTransform != null)
SpawnConfiguredAt(pool, _tornadoLargeConfig, "PROJ_TornadoLarge",
PlayerTransform.position, Vector2.down, null);
break;
case "wind_stone":
SpawnConfiguredAt(pool, _windStoneConfig, "PROJ_WindStone",
MuzzlePos(_windStoneMuzzle), Vector2.down, null);
break;
}
}
private Vector2 MuzzlePos(Transform muzzle)
=> muzzle != null ? (Vector2)muzzle.position : (Vector2)transform.position;
/// 朝向玩家的发射方向;无玩家时退回当前朝向(localScale.x)。
private Vector2 AimDir(Transform muzzle)
{
Vector2 origin = MuzzlePos(muzzle);
if (PlayerTransform != null)
return ((Vector2)PlayerTransform.position - origin).normalized;
return transform.localScale.x >= 0f ? Vector2.right : Vector2.left;
}
///
/// 从池取出弹体并用 config 初始化(注入速度/重力/伤害源/方向)。
/// config 为空时仅生成不初始化并告警(需在 Inspector 指定对应 ProjectileConfigSO)。
///
private void SpawnConfiguredAt(IObjectPoolService pool, ProjectileConfigSO config, string fallbackKey,
Vector2 pos, Vector2 dir, System.Action onSpawned)
{
string key = config != null && !string.IsNullOrEmpty(config.PoolKey) ? config.PoolKey : fallbackKey;
var go = pool.Spawn(key, pos, Quaternion.identity);
if (go == null) return;
var proj = go.GetComponent();
if (proj == null)
{
Debug.LogWarning($"[ChaoFengBoss] 弹体 '{key}' 缺少 Projectile 组件。", this);
return;
}
onSpawned?.Invoke(proj);
if (config == null)
{
Debug.LogWarning($"[ChaoFengBoss] 弹体 '{key}' 未指定 ProjectileConfigSO,无法初始化速度/伤害。", this);
return;
}
var src = config.DamageSource;
var info = src != null
? DamageInfo.From(src, dir, pos, gameObject.layer, proj)
: default;
proj.Initialize(config, info, dir, gameObject.layer);
}
// ── 击败演出 ─────────────────────────────────────────────────────────
protected override void Die()
{
StartCoroutine(DefeatSequence());
}
private IEnumerator DefeatSequence()
{
StopBehaviorTree();
_knockdownCounter?.ForceEnd();
// Phase 2(空中)先落地
if (CurrentPhase >= 1 && _floatController != null)
yield return _floatController.FallDown();
// 空中挣扎(Defeat_Struggle)
if (_defeatStruggleClip.Clip != null)
{
Animancer.Play(_defeatStruggleClip);
yield return new WaitForSeconds(_defeatStruggleClip.Clip.length);
}
// 白屏效果
_onDefeatWhiteFlash?.Invoke();
// 倒地喘气(Defeat_Pant 循环)
if (_defeatPantClip.Clip != null)
Animancer.Play(_defeatPantClip);
yield return new WaitForSeconds(_defeatPantDuration);
// 站起(Defeat_StandUp 单次)
if (_defeatStandUpClip.Clip != null)
{
Animancer.Play(_defeatStandUpClip);
yield return new WaitForSeconds(_defeatStandUpClip.Clip.length);
}
// 广播战斗结束、触发结算过场
base.Die();
}
}
}