2026-05-21 보스 특수스킬1
This commit is contained in:
58
Assets/02_Scripts/Enemy/Skills/BossSkill.cs
Normal file
58
Assets/02_Scripts/Enemy/Skills/BossSkill.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
// ============================================================================
|
||||
// BossSkill
|
||||
// ----------------------------------------------------------------------------
|
||||
// 보스 "특별 스킬"의 베이스 클래스. 스킬 하나 = 자기완결적 프리팹 하나.
|
||||
//
|
||||
// [스킬 프리팹] = BossSkill(상속) 컴포넌트 + 자체 Animator + HazardHitbox 자식들
|
||||
//
|
||||
// 동작 흐름:
|
||||
// - BossAI._skillPrefabs에 프리팹을 등록 (씬 인스턴스가 아닌 에셋 참조)
|
||||
// - 시전 시 BossAI가 프리팹을 Instantiate → Begin() 호출
|
||||
// - 스킬은 시퀀스가 끝나면 스스로 Destroy
|
||||
// - 취소(페이즈 전환·사망)는 BossAI가 인스턴스를 Destroy → 콜라이더도 함께 사라짐
|
||||
//
|
||||
// MinPhase/Range/Cooldown은 BossAI가 프리팹에서 직접 읽어 사용 가능 여부를 판단.
|
||||
// 쿨다운 "타이머"는 보스별 상태라 BossAI가 추적한다.
|
||||
//
|
||||
// 새 스킬 추가: BossSkill을 상속한 컴포넌트로 프리팹을 만들고 RunSkill만 구현.
|
||||
// ============================================================================
|
||||
public abstract class BossSkill : MonoBehaviour
|
||||
{
|
||||
[Header("BossSkill")]
|
||||
[SerializeField] private int _minPhase; // 이 페이즈(0부터) 이상에서만 사용 가능
|
||||
[SerializeField] private float _range = 4f; // 타겟이 이 X거리 안일 때만 사용
|
||||
[SerializeField] private float _cooldown = 8f; // 재사용 대기 (타이머는 BossAI가 보스별로 추적)
|
||||
[SerializeField] private string _casterAnimationState = "BossCast"; // 시전 중 보스가 재생할 애니메이션
|
||||
|
||||
public int MinPhase => _minPhase;
|
||||
public float Range => _range;
|
||||
public float Cooldown => _cooldown;
|
||||
public string CasterAnimationState => _casterAnimationState;
|
||||
|
||||
// BossAI가 인스턴스를 만든 직후 호출. 시퀀스를 끝까지 실행하고 스스로 파괴한다.
|
||||
// destroyCancellationToken: BossAI가 이 인스턴스를 Destroy하면 시퀀스가 취소된다.
|
||||
public async void Begin()
|
||||
{
|
||||
try
|
||||
{
|
||||
await RunSkill(destroyCancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return; // 외부에서 Destroy됨 → GameObject 이미 파괴 중이므로 그대로 종료
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e, this); // 스킬 버그가 나도 아래 Destroy로 정리는 보장
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
// 서브클래스가 실제 스킬 시퀀스를 구현. token이 취소되면 finally에서 정리할 것.
|
||||
protected abstract Awaitable RunSkill(CancellationToken token);
|
||||
}
|
||||
2
Assets/02_Scripts/Enemy/Skills/BossSkill.cs.meta
Normal file
2
Assets/02_Scripts/Enemy/Skills/BossSkill.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8622c72961cf4d4a83c6a904e3cedea
|
||||
84
Assets/02_Scripts/Enemy/Skills/HazardSkill.cs
Normal file
84
Assets/02_Scripts/Enemy/Skills/HazardSkill.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
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 Transform[] _downHazardFirePos; // 위에서 아래로 포격
|
||||
[SerializeField] private Transform[] _rightHazardFirePos; // 왼쪽에서 오른쪽으로 포격
|
||||
[SerializeField] private GameObject _hazardHitboxOrigin;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_animator == null)
|
||||
_animator = GetComponentInChildren<Animator>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 선딜
|
||||
await Awaitable.WaitForSecondsAsync(_windup, token);
|
||||
|
||||
FireHazards(dirChoice);
|
||||
|
||||
// 후딜
|
||||
await Awaitable.WaitForSecondsAsync(_recovery, token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void FireHazards(int dirChoice)
|
||||
{
|
||||
Transform[] _hazardPoss = dirChoice switch { 0 => _downHazardFirePos, 1=>_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);
|
||||
Rigidbody2D hitbox_rb = hitbox.GetComponent<Rigidbody2D>();
|
||||
if(hitbox_rb != null)
|
||||
{
|
||||
hitbox_rb.linearVelocity = attackDir*5.0f;
|
||||
}
|
||||
|
||||
Destroy(hitbox,5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Enemy/Skills/HazardSkill.cs.meta
Normal file
2
Assets/02_Scripts/Enemy/Skills/HazardSkill.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e20ef4137f5c87f4ca4500445779b574
|
||||
Reference in New Issue
Block a user