Files
zeling_v2/Assets/_Game/Scripts/Enemies/Boss/ChaoFengBoss.cs

172 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using Animancer;
using BaseGames.Combat;
using BaseGames.Core;
using BaseGames.Core.Pool;
using UnityEngine;
using UnityEngine.Events;
namespace BaseGames.Enemies.Boss
{
/// <summary>
/// 嘲风 Boss 主脚本。
///
/// Phase 0地面4 技能加权随机(回旋扇/扇形连击/小龙卷/大龙卷)。
/// Phase 1空中风石技能 + 击落计数机制。
///
/// 阶段过渡流程:
/// 1. BossBase.BeginPhaseTransition → OnBeginPhaseTransition(1) 立即播放过渡动画 + 开始浮空
/// 2. 无敌期结束(≥ _riseDuration+buffer→ BossBase.EnterPhase(1) 广播阶段切换事件
///
/// ⚠️ 动画由本脚本通过 Animancer.Play() 完整控制,不在 BD 中调用 BD_PlayAnimation。
/// </summary>
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("击败演出动画")]
[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;
// ── 阶段过渡钩子 ─────────────────────────────────────────────────────
/// <summary>
/// 阶段过渡开始时立即播放过渡动画并启动浮空协程。
/// invincibleDuration 需在 BD_BossPhaseTransition 中配置为 ≥ _riseDuration + 缓冲(约 2.0s)。
/// </summary>
protected override void OnBeginPhaseTransition(int targetPhase)
{
if (targetPhase == 1)
{
if (_phaseTransitionClip.Clip != null)
Animancer.Play(_phaseTransitionClip);
StartCoroutine(_floatController.FloatUp());
}
}
// ── 受击转发 ─────────────────────────────────────────────────────────
/// <summary>
/// 转发受击事件至击落计数器。
/// ⚠️ HurtBox 无公开 OnDamageTaken 事件,必须通过此虚方法转发。
/// </summary>
protected override void OnDamageTaken(DamageInfo info)
{
base.OnDamageTaken(info);
_knockdownCounter?.OnBossHit(info);
}
// ── 动画事件 ─────────────────────────────────────────────────────────
/// <summary>
/// 回旋扇返回时由 ReturnProjectile 调用,触发收扇动画。
/// </summary>
public void OnBoomerangReturned()
{
if (_boomerangEndClip.Clip != null)
Animancer.Play(_boomerangEndClip);
}
// ── 弹体生成 ─────────────────────────────────────────────────────────
/// <summary>
/// 由技能动画 AnimationEvent 触发,生成对应弹体。
/// payload: "boomerang" / "tornado_small" / "tornado_large" / "wind_stone"
/// </summary>
public override void SpawnProjectile(string payload)
{
var pool = ServiceLocator.GetOrDefault<IObjectPoolService>();
if (pool == null) return;
switch (payload)
{
case "boomerang":
{
var go = pool.Spawn("PROJ_Boomerang",
_boomerangMuzzle != null ? _boomerangMuzzle.position : transform.position,
Quaternion.identity);
go?.GetComponent<ReturnProjectile>()?.SetOwner(transform);
break;
}
case "tornado_small":
pool.Spawn("PROJ_TornadoSmall",
_tornadoMuzzle != null ? _tornadoMuzzle.position : transform.position,
Quaternion.identity);
break;
case "tornado_large":
if (PlayerTransform != null)
pool.Spawn("PROJ_TornadoLarge", PlayerTransform.position, Quaternion.identity);
break;
case "wind_stone":
pool.Spawn("PROJ_WindStone",
_windStoneMuzzle != null ? _windStoneMuzzle.position : transform.position,
Quaternion.identity);
break;
}
}
// ── 击败演出 ─────────────────────────────────────────────────────────
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();
}
}
}