188 lines
13 KiB
C#
188 lines
13 KiB
C#
|
|
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
|
||
|
|
|
||
|
|
// ============================================================
|
||
|
|
// NorcielBoss.PublicAPI.cs — 외부 컴포넌트용 읽기전용 API (partial class)
|
||
|
|
//
|
||
|
|
// [역할]
|
||
|
|
// BossDebugDisplay 등 외부 컴포넌트가 보스 상태를 안전하게 읽을 수 있도록
|
||
|
|
// public getter 메서드와 프로퍼티를 한 곳에 모아둡니다.
|
||
|
|
//
|
||
|
|
// [설계]
|
||
|
|
// partial class로 NorcielBoss의 private 필드에 직접 접근합니다.
|
||
|
|
// 모든 API는 읽기전용이며 상태를 변경하지 않습니다. (테스트 메서드 제외)
|
||
|
|
// ============================================================
|
||
|
|
|
||
|
|
public partial class NorcielBoss : MonsterClass // 부분 클래스를 선언할거에요 -> NorcielBoss의 Public API 부분으로
|
||
|
|
{
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// Phase 상태 (읽기전용 프로퍼티)
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>Phase2 진입 여부 — phaseManager에서 가져옴</summary>
|
||
|
|
public bool IsPhase2 => phaseManager != null && phaseManager.IsPhase2; // 속성을 선언할거에요 -> Phase2 여부를 (외부 접근용)
|
||
|
|
|
||
|
|
/// <summary>Phase3 진입 여부 — phaseManager에서 가져옴</summary>
|
||
|
|
public bool IsPhase3 => phaseManager != null && phaseManager.IsPhase3; // 속성을 선언할거에요 -> Phase3 여부를 (외부 접근용)
|
||
|
|
|
||
|
|
/// <summary>전투 시작 여부</summary>
|
||
|
|
public bool IsBattleStarted => _isBattleStarted; // 속성을 선언할거에요 -> 전투 시작 여부를 (외부 접근용)
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// FSM 상태 조회
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>현재 FSM 상태 반환</summary>
|
||
|
|
public BossState GetCurrentState() => _state; // 함수를 선언할거에요 -> 현재 FSM 상태를 반환하는
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// 거리/범위 파라미터 조회 (Inspector 설정값 읽기)
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>근접 사거리 (m)</summary>
|
||
|
|
public float GetMeleeRange() => meleeRange; // 함수를 선언할거에요 -> 근접 사거리를 반환하는
|
||
|
|
|
||
|
|
/// <summary>던지기 사거리 (m)</summary>
|
||
|
|
public float GetThrowRange() => throwRange; // 함수를 선언할거에요 -> 던지기 사거리를 반환하는
|
||
|
|
|
||
|
|
/// <summary>대시 발동 거리 (m)</summary>
|
||
|
|
public float GetDashChaseRange() => dashChaseRange; // 함수를 선언할거에요 -> 대시 발동 거리를 반환하는
|
||
|
|
|
||
|
|
/// <summary>[v6.5] 대시 쿨다운 시간 (초) — ChargeMonster의 chargeDelay 역할</summary>
|
||
|
|
public float GetDashCooldownTime() => dashCooldownTime; // 함수를 선언할거에요 -> 대시 쿨다운 시간을 반환하는
|
||
|
|
|
||
|
|
/// <summary>내려찍기 판정 중심 오프셋 (보스 앞방향 m)</summary>
|
||
|
|
public float GetSmashForwardOffset() => smashForwardOffset; // 함수를 선언할거에요 -> 스매시 오프셋을 반환하는
|
||
|
|
|
||
|
|
/// <summary>내려찍기 판정 반경 (m)</summary>
|
||
|
|
public float GetSmashRadius() => smashRadius; // 함수를 선언할거에요 -> 스매시 반경을 반환하는
|
||
|
|
|
||
|
|
/// <summary>휩쓸기 판정 반경 (m)</summary>
|
||
|
|
public float GetSweepRadius() => sweepRadius; // 함수를 선언할거에요 -> 휩쓸기 반경을 반환하는
|
||
|
|
|
||
|
|
/// <summary>대시+스매시 콤보 대시 중단 거리 (m)</summary>
|
||
|
|
public float GetDashSmashArriveRange() => dashSmashArriveRange; // 함수를 선언할거에요 -> 콤보 도착 거리를 반환하는
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// 전투 상태 조회
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>현재 콤보 카운터 (연속 공격 횟수)</summary>
|
||
|
|
public int GetComboCounter() => _comboCounter; // 함수를 선언할거에요 -> 콤보 카운터를 반환하는
|
||
|
|
|
||
|
|
/// <summary>최대 콤보 횟수 — phaseManager에서 가져옴</summary>
|
||
|
|
public int GetMaxComboCount() => (phaseManager != null) ? phaseManager.MaxComboCount : 3; // 함수를 선언할거에요 -> 최대 콤보 횟수를 반환하는
|
||
|
|
|
||
|
|
/// <summary>공격 쿨타임 남은 시간 (초)</summary>
|
||
|
|
public float GetAttackTimer() => _attackTimer; // 함수를 선언할거에요 -> 공격 쿨타임을 반환하는
|
||
|
|
|
||
|
|
/// <summary>공격 패턴 간격 (초)</summary>
|
||
|
|
public float GetPatternInterval() => patternInterval; // 함수를 선언할거에요 -> 패턴 간격을 반환하는
|
||
|
|
|
||
|
|
/// <summary>플레이어까지 거리 (m) — 타겟 없으면 9999</summary>
|
||
|
|
public float GetDistanceToTarget() => GetDist(); // 함수를 선언할거에요 -> 플레이어까지 거리를 반환하는
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// HP 조회 (MonsterClass 필드 래핑)
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>최대 HP</summary>
|
||
|
|
public float GetMaxHP() => maxHP; // 함수를 선언할거에요 -> 최대 HP를 반환하는
|
||
|
|
|
||
|
|
/// <summary>현재 HP</summary>
|
||
|
|
public float GetCurrentHP() => currentHP; // 함수를 선언할거에요 -> 현재 HP를 반환하는
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// 디버그용 텍스트 조회
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>직전 사용 패턴 텍스트 (연속 횟수 포함)</summary>
|
||
|
|
public string GetLastPatternText() // 함수를 선언할거에요 -> 직전 패턴 정보를 텍스트로 반환하는
|
||
|
|
{
|
||
|
|
if ((int)_lastPattern < 0) return "없음"; // 반환할거에요 -> 아직 패턴 사용 전이면 "없음"을
|
||
|
|
string name = _lastPattern.ToString(); // 변환할거에요 -> 패턴 이름을 문자열로
|
||
|
|
if (_samePatternCount > 1) // 조건이 맞으면 실행할거에요 -> 연속 사용이면
|
||
|
|
name += $" x{_samePatternCount}"; // 덧붙일거에요 -> 연속 횟수를
|
||
|
|
return name; // 반환할거에요 -> 패턴 텍스트를
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>플레이어 행동 감지 상태 텍스트 (정지/접근/도주/카이팅)</summary>
|
||
|
|
public string GetPlayerBehaviorText() // 함수를 선언할거에요 -> 플레이어 행동 감지 정보를 텍스트로 반환하는
|
||
|
|
{
|
||
|
|
string text = ""; // 초기화할거에요 -> 빈 텍스트로
|
||
|
|
if (_playerStillTimer >= stillPunishTime) // 조건이 맞으면 실행할거에요 -> 정지 감지됐으면
|
||
|
|
text += $"<color=red>[정지 {_playerStillTimer:F1}s]</color> "; // 덧붙일거에요 -> 정지 경고를
|
||
|
|
if (_playerApproachTimer >= approachReactTime) // 조건이 맞으면 실행할거에요 -> 접근 감지됐으면
|
||
|
|
text += $"<color=yellow>[접근 {_playerApproachTimer:F1}s]</color> "; // 덧붙일거에요 -> 접근 감지를
|
||
|
|
if (_playerFleeTimer >= 1f) // 조건이 맞으면 실행할거에요 -> 도주 감지됐으면
|
||
|
|
text += $"<color=cyan>[도주 {_playerFleeTimer:F1}s]</color> "; // 덧붙일거에요 -> 도주 감지를
|
||
|
|
if (_kitingTimer >= kitingDetectTime * 0.5f) // 조건이 맞으면 실행할거에요 -> 카이팅 감지 중이면
|
||
|
|
text += $"<color=magenta>[카이팅 {_kitingTimer:F1}s]</color>"; // 덧붙일거에요 -> 카이팅 감지를
|
||
|
|
return text; // 반환할거에요 -> 완성된 텍스트를
|
||
|
|
}
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// 디버그/테스트용 제어 메서드
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>Inspector 테스트 버튼에서 호출 — 지정 패턴을 강제 실행</summary>
|
||
|
|
public void TestStartPattern(string patternName) // 함수를 선언할거에요 -> 테스트용 패턴 강제 실행을
|
||
|
|
{
|
||
|
|
if (_state == BossState.Dead) return; // 중단할거에요 -> 사망 상태면
|
||
|
|
|
||
|
|
// 문자열을 BossPattern으로 파싱
|
||
|
|
if (System.Enum.TryParse(patternName, out BossPattern pattern)) // 파싱할거에요 -> 문자열을 패턴 열거형으로
|
||
|
|
{
|
||
|
|
Debug.Log($"[Boss Test] 패턴 강제 실행: {pattern}"); // 로그를 찍을거에요
|
||
|
|
StartPattern(pattern); // 시작할거에요 -> 해당 패턴을
|
||
|
|
}
|
||
|
|
else // 아니면
|
||
|
|
{
|
||
|
|
Debug.LogWarning($"[Boss Test] 알 수 없는 패턴 이름: {patternName}"); // 경고를 찍을거에요
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
// 전투 시작 — BossZoneTrigger에서 호출
|
||
|
|
// ══════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
/// <summary>보스전 시작 — 포효 연출 후 Chase 상태로 전환 (BossZoneTrigger에서 호출)</summary>
|
||
|
|
public void StartBossBattle() // 함수를 선언할거에요 -> 보스전을 시작하는 (외부 호출용)
|
||
|
|
{
|
||
|
|
if (_isBattleStarted) return; // 중단할거에요 -> 이미 시작됐으면 중복 방지
|
||
|
|
StartCoroutine(BattleStartRoutine()); // 시작할거에요 -> 전투 시작 코루틴을
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>전투 시작 코루틴 — 포효 애니 → 체력바 표시 → Chase 전환</summary>
|
||
|
|
private System.Collections.IEnumerator BattleStartRoutine() // 코루틴을 정의할거에요 -> 전투 시작 연출을 처리하는
|
||
|
|
{
|
||
|
|
_isBattleStarted = true; // 설정할거에요 -> 전투 시작 플래그를
|
||
|
|
|
||
|
|
// NavMesh 에이전트 활성화
|
||
|
|
if (agent != null) agent.enabled = true; // 켤거에요 -> 에이전트를 (Init에서 꺼뒀으므로)
|
||
|
|
|
||
|
|
// 체력바 표시
|
||
|
|
if (bossHealthBar != null) bossHealthBar.SetActive(true); // 켤거에요 -> 체력바를
|
||
|
|
|
||
|
|
// 포효 애니메이션 재생 + 대기
|
||
|
|
PlayAnimDirect(anim_Roar); // 재생할거에요 -> 포효 애니를
|
||
|
|
yield return new UnityEngine.WaitForSeconds(2f); // 기다릴거에요 -> 포효 시간을 (애니 종료 대기)
|
||
|
|
|
||
|
|
// FSM 가동 → Chase 상태로 전환
|
||
|
|
SetState(BossState.Chase); // 전환할거에요 -> 추격 상태로
|
||
|
|
_attackTimer = patternInterval * 0.5f; // 설정할거에요 -> 첫 공격 쿨타임을 (v6: 절반으로 단축 → 포효 후 빠르게 첫 패턴 발동)
|
||
|
|
|
||
|
|
Debug.Log("[Boss] 전투 시작! → Chase 상태 진입"); // 로그를 찍을거에요
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Inspector 테스트 버튼에서 호출 — Phase2 강제 진입</summary>
|
||
|
|
public void TestEnterPhase2() // 함수를 선언할거에요 -> 테스트용 Phase2 강제 진입을
|
||
|
|
{
|
||
|
|
if (phaseManager != null) // 조건이 맞으면 실행할거에요 -> phaseManager 있으면
|
||
|
|
{
|
||
|
|
Debug.Log("[Boss Test] Phase2 강제 진입!"); // 로그를 찍을거에요
|
||
|
|
phaseManager.ConfirmPhase2(); // 호출할거에요 -> Phase2 강제 진입을
|
||
|
|
OnPhaseChanged(2); // 실행할거에요 -> Phase 전환 연출을
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|