using System; using UnityEngine; // ============================================================================ // Boss // ---------------------------------------------------------------------------- // 보스의 페이즈를 관리하는 컴포넌트. 같은 GameObject의 Enemy(몸)·BossAI(두뇌)와 // 함께 동작한다. // - Health 비율이 임계값 아래로 떨어지면 페이즈 전환 // - 전환 중엔 Enemy.SetInvulnerable(true)로 무적 + 전환 애니메이션 재생 // - CurrentPhase를 BossAI가 읽어 공격 패턴을 바꾼다 (BossAttack.MinPhase) // ============================================================================ [RequireComponent(typeof(Enemy))] [RequireComponent(typeof(Health))] public class Boss : MonoBehaviour { [Header("Phase")] // 페이즈 업이 일어나는 HP 비율 (내림차순). 예: {0.66, 0.33} → 페이즈 0→1→2. [SerializeField] private float[] _phaseThresholds = { 0.66f, 0.33f }; [SerializeField] private string _phaseTransitionAnimation = "BossPhaseChange"; [SerializeField] private float _phaseTransitionDuration = 1.2f; // 전환(무적) 지속 시간 private Enemy _enemy; private Health _health; private Animator _anim; private int _currentPhase; // 0부터 시작 private bool _isTransitioning; // 페이즈 전환 진행 중 public int CurrentPhase => _currentPhase; public bool IsTransitioning => _isTransitioning; public event Action OnPhaseChanged; // 전환 완료 시 발화 (인자 = 새 페이즈) private void Awake() { _enemy = GetComponent(); _health = GetComponent(); _anim = GetComponentInChildren(); } private void Update() { if (_isTransitioning || _health.IsDead) return; if (_currentPhase >= _phaseThresholds.Length) return; // 이미 마지막 페이즈 // 현재 페이즈의 임계값 아래로 HP가 떨어지면 다음 페이즈로 전환. if (_health.Ratio <= _phaseThresholds[_currentPhase]) RunPhaseTransition(); } // 페이즈 전환: 무적 ON → 전환 애니메이션 → 일정 시간 후 무적 OFF + 페이즈 증가. // 코루틴 대신 Awaitable 사용. destroyCancellationToken으로 파괴 시 자동 취소. private async void RunPhaseTransition() { _isTransitioning = true; _enemy.SetInvulnerable(true); if (_anim != null && !string.IsNullOrEmpty(_phaseTransitionAnimation)) _anim.Play(_phaseTransitionAnimation); try { await Awaitable.WaitForSecondsAsync(_phaseTransitionDuration, destroyCancellationToken); } catch (OperationCanceledException) { return; // 보스가 파괴됨 → 그대로 종료 } _currentPhase++; _enemy.SetInvulnerable(false); _isTransitioning = false; OnPhaseChanged?.Invoke(_currentPhase); } private void OnDestroy() { GameManager.Instance.WaveM.GameClear(); } }