using System.Threading; using Unity.VisualScripting; using UnityEngine; // ============================================================================ // HazardSkill // ---------------------------------------------------------------------------- // 보스 특별 스킬의 한 종류 (BossSkill 상속). 스킬 프리팹의 루트에 부착. // // 시퀀스: 자체 애니메이션 재생 → 선딜 → 피해 판정 ON → 유지 → OFF → 후딜 → 자동 파괴 // // 콜라이더의 "움직임"은 이 프리팹의 자체 Animator/클립이 담당한다 (보스와 무관). // 이 스크립트는 타이밍에 맞춰 HazardHitbox들의 피해 판정만 ON/OFF 한다. // ============================================================================ public class HazardSkill : BossSkill { [Header("HazardSkill")] [SerializeField] private Animator _animator; // 이 프리팹의 Animator (콜라이더 이동 담당) [SerializeField] private string _downAnimationState = "HazardSkillDown"; [SerializeField] private string _rightAnimationState = "HazardSkillRight"; [SerializeField] private float _windup = 0.5f; // 애니 시작 ~ 피해 판정 ON [SerializeField] private float _activeDuration = 1.5f; // 피해 판정 유지 시간 [SerializeField] private float _recovery = 0.6f; // 판정 OFF 후 후딜 [SerializeField] private GameObject _hazardHitboxOrigin; [SerializeField] private int _hitBoxDamage = 15; private SkillSupport support; private void Awake() { if (_animator == null) _animator = GetComponentInChildren(); } private void Start() { support = Object.FindFirstObjectByType(); } protected override async Awaitable RunSkill(CancellationToken token) { try { int dirChoice = Random.Range(0,2); //0,1 if(dirChoice == 0) // Down 포격 { if (_animator != null && !string.IsNullOrEmpty(_downAnimationState)) _animator.Play(_downAnimationState); } else if(dirChoice == 1) //Right 포격 { if (_animator != null && !string.IsNullOrEmpty(_rightAnimationState)) _animator.Play(_rightAnimationState); } PredictHazards(dirChoice); // 선딜 await Awaitable.WaitForSecondsAsync(_windup, token); FireHazards(dirChoice); // 후딜 await Awaitable.WaitForSecondsAsync(_recovery, token); } finally { } } private void PredictHazards(int dirChoice) { SkillPredict[] predicts = dirChoice switch { 0 => support.DownHazardPredicts, 1=> support.RightHazardPredicts, _=> null}; for (int i = 0; i < predicts.Length; i++) { if(predicts[i] != null) predicts[i].PredictVFX.Play(); } } private void FireHazards(int dirChoice) { Transform[] hazardPoss = dirChoice switch { 0 => support.DownHazardFirePos, 1=> support.RightHazardFirePos, _=> null}; Vector2 attackDir = dirChoice switch {0 => Vector2.down,1=>Vector2.right,_=>Vector2.left}; if (hazardPoss == null) return; for (int i = 0; i < hazardPoss.Length; i++) { GameObject hitbox = Instantiate(_hazardHitboxOrigin,hazardPoss[i].transform); HazardHitbox hazardHitbox = hitbox.GetComponent(); if(hazardHitbox != null) { hazardHitbox.Damage = _hitBoxDamage; } Rigidbody2D hitbox_rb = hitbox.GetComponent(); if(hitbox_rb != null) { hitbox_rb.AddForce(attackDir*100.0f); } Destroy(hitbox,5f); } } }