refactor(enemy): 敌人专属子类改为零代码配置型行为组件
This commit is contained in:
86
Assets/_Game/Scripts/Enemies/Behaviors/EnemyDeathSequence.cs
Normal file
86
Assets/_Game/Scripts/Enemies/Behaviors/EnemyDeathSequence.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Animancer;
|
||||
using BaseGames.Combat;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.Enemies.Behaviors
|
||||
{
|
||||
/// <summary>
|
||||
/// 死亡前摇无敌演出(零代码替代每敌人专属的 <c>Die()</c> 重写)。
|
||||
/// <para>
|
||||
/// <see cref="EnemyBase.Die"/> 会委托本组件:停行为树 / 停移动、停用受击框,播放前摇动画并等待,
|
||||
/// 期间敌人处于无敌(<see cref="EnemyBase.IsInvincible"/>),演出结束后回调真正的死亡清理。
|
||||
/// 前摇动画上可放置 SpawnProjectile 动画事件,配合 <see cref="EnemySpawnerOnEvent"/> 在演出中生成小怪。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public class EnemyDeathSequence : MonoBehaviour, IEnemyDeathSequence
|
||||
{
|
||||
[Header("前摇动画")]
|
||||
[Tooltip("死亡前摇动画(无敌演出);为空则跳过演出直接进入死亡清理")]
|
||||
[SerializeField] private ClipTransition _deathPreClip;
|
||||
[Tooltip("前摇演出时长(秒)")]
|
||||
[Min(0f)][SerializeField] private float _duration = 3f;
|
||||
|
||||
[Header("演出期间")]
|
||||
[Tooltip("演出期间停用的受击框(防止演出中被打断或二次受伤);对象池复用时 OnSpawn 自动恢复")]
|
||||
[SerializeField] private HurtBox[] _hurtBoxesToDisable;
|
||||
[Tooltip("演出开始时停止行为树(防止 BT 继续 Tick 覆盖演出动画)")]
|
||||
[SerializeField] private bool _stopBehaviorTree = true;
|
||||
[Tooltip("演出开始时停止移动")]
|
||||
[SerializeField] private bool _stopMovement = true;
|
||||
|
||||
private EnemyBase _enemy;
|
||||
private AnimancerComponent _animancer;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_enemy = GetComponentInParent<EnemyBase>();
|
||||
_animancer = _enemy != null ? _enemy.Animancer : GetComponentInParent<AnimancerComponent>();
|
||||
if (_enemy == null)
|
||||
Debug.LogError($"[EnemyDeathSequence] {name} 找不到 EnemyBase。", this);
|
||||
}
|
||||
|
||||
// 对象池复用:出生时恢复受击框(演出中曾被停用)
|
||||
private void OnEnable()
|
||||
{
|
||||
if (_enemy != null) _enemy.Spawned += RestoreHurtBoxes;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_enemy != null) _enemy.Spawned -= RestoreHurtBoxes;
|
||||
}
|
||||
|
||||
public void Play(Action onComplete)
|
||||
{
|
||||
StartCoroutine(Sequence(onComplete));
|
||||
}
|
||||
|
||||
private IEnumerator Sequence(Action onComplete)
|
||||
{
|
||||
if (_stopBehaviorTree) _enemy?.StopBehaviorTree();
|
||||
if (_stopMovement) _enemy?.StopMovement();
|
||||
|
||||
SetHurtBoxesEnabled(false);
|
||||
|
||||
if (_deathPreClip.Clip != null && _animancer != null)
|
||||
{
|
||||
_animancer.Play(_deathPreClip);
|
||||
if (_duration > 0f) yield return new WaitForSeconds(_duration);
|
||||
}
|
||||
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
|
||||
private void RestoreHurtBoxes() => SetHurtBoxesEnabled(true);
|
||||
|
||||
private void SetHurtBoxesEnabled(bool enabled)
|
||||
{
|
||||
if (_hurtBoxesToDisable == null) return;
|
||||
foreach (var hb in _hurtBoxesToDisable)
|
||||
if (hb != null) hb.enabled = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user