using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을 /// /// 보스 AI 디버그 표시 컴포넌트 — 씬 뷰 Gizmo + 게임 화면 OnGUI 디버그 정보 표시 /// 보스의 상태, 거리, 패턴, 카이팅 감지 등을 시각화해요. /// public class BossDebugDisplay : MonoBehaviour { // ══════════════════════════════════════════════════════════ // Inspector 연결 // ══════════════════════════════════════════════════════════ [Header("=== 보스 AI 참조 ===")] [Tooltip("NorcielBoss 스크립트가 부착된 보스 오브젝트")] // 설명할거에요 -> 보스 참조 필드 설명을 [SerializeField] private NorcielBoss boss; // 변수를 선언할거에요 -> 보스 스크립트 참조를 // ══════════════════════════════════════════════════════════ // 패턴 테스트 버튼 (Inspector에서 플레이 중 체크) // ══════════════════════════════════════════════════════════ [Header("=== 패턴 테스트 (플레이 중 Inspector에서 체크 → 즉시 실행) ===")] [SerializeField] private bool testThrow = false; // 변수를 선언할거에요 -> 던지기 테스트 버튼을 [Header("=== Phase 테스트 ===")] [SerializeField] private bool testPhase2 = false; // 변수를 선언할거에요 -> Phase2 강제 진입 버튼을 [Header("=== 근접 패턴 테스트 (플레이 중 Inspector에서 체크 → 즉시 실행) ===")] [SerializeField] private bool testSmash = false; // 변수를 선언할거에요 -> 내려찍기 테스트 버튼을 [SerializeField] private bool testSweep = false; // 변수를 선언할거에요 -> 휩쓸기 테스트 버튼을 [SerializeField] private bool testDash = false; // 변수를 선언할거에요 -> 대시 테스트 버튼을 // ══════════════════════════════════════════════════════════ // 디버그 화면 로그 설정 // ══════════════════════════════════════════════════════════ [Header("=== 디버그 화면 로그 ===")] [Tooltip("체크하면 게임 화면 좌측 상단에 보스 상태 로그를 표시해요")] // 설명할거에요 -> 화면 로그 표시 여부 설명을 [SerializeField] private bool debugLogOnScreen = true; // 변수를 선언할거에요 -> 화면 로그 표시 여부를 // ══════════════════════════════════════════════════════════ // Update — 테스트 버튼 폴링 // ══════════════════════════════════════════════════════════ private void Update() // 함수를 실행할거에요 -> 매 프레임을 { if (boss == null) return; // 중단할거에요 -> 보스 참조 없으면 PollTestButtons(); // 확인할거에요 -> 테스트 버튼 입력을 } // ══════════════════════════════════════════════════════════ // 테스트 버튼 폴링 // ══════════════════════════════════════════════════════════ private void PollTestButtons() // 함수를 선언할거에요 -> 매 프레임 Inspector 테스트 버튼을 확인하는 { // 조건이 맞으면 실행할거에요 -> 던지기 테스트 체크됐으면 if (testThrow) // 조건을 확인할거에요 -> testThrow 플래그를 { testThrow = false; // 초기화할거에요 -> 플래그를 (중복 발동 방지) boss.TestStartPattern("Throw"); // 호출할거에요 -> 보스의 던지기 패턴 테스트를 } // 조건이 맞으면 실행할거에요 -> Phase2 테스트 체크됐으면 if (testPhase2) // 조건을 확인할거에요 -> testPhase2 플래그를 { testPhase2 = false; // 초기화할거에요 -> 플래그를 (중복 발동 방지) boss.TestEnterPhase2(); // 호출할거에요 -> 보스의 Phase2 강제 진입을 } // ─────────────── 근접 패턴 테스트 ───────────────── // 조건이 맞으면 실행할거에요 -> 내려찍기 테스트 체크됐으면 if (testSmash) // 조건을 확인할거에요 -> testSmash 플래그를 { testSmash = false; // 초기화할거에요 -> 플래그를 (중복 발동 방지) boss.TestStartPattern("Smash"); // 호출할거에요 -> 보스의 내려찍기 패턴 테스트를 } // 조건이 맞으면 실행할거에요 -> 휩쓸기 테스트 체크됐으면 if (testSweep) // 조건을 확인할거에요 -> testSweep 플래그를 { testSweep = false; // 초기화할거에요 -> 플래그를 (중복 발동 방지) boss.TestStartPattern("Sweep"); // 호출할거에요 -> 보스의 휩쓸기 패턴 테스트를 } // 조건이 맞으면 실행할거에요 -> 대시 테스트 체크됐으면 if (testDash) // 조건을 확인할거에요 -> testDash 플래그를 { testDash = false; // 초기화할거에요 -> 플래그를 (중복 발동 방지) boss.TestStartPattern("Dash"); // 호출할거에요 -> 보스의 대시 추격 패턴 테스트를 } } // ══════════════════════════════════════════════════════════ // 씬 뷰 기즈모 — 사거리 시각화 // ══════════════════════════════════════════════════════════ private void OnDrawGizmosSelected() // 함수를 실행할거에요 -> 씬 뷰 선택 시 사거리 시각화를 { if (boss == null) return; // 중단할거에요 -> 보스 참조 없으면 // ─────────────── 근접 사거리 (초록) ───────────────── Gizmos.color = Color.green; // 설정할거에요 -> Gizmo 색상을 초록으로 Gizmos.DrawWireSphere(boss.transform.position, boss.GetMeleeRange()); // 그릴거에요 -> 근접 사거리 구를 // ─────────────── 던지기 사거리 (청록) ───────────────── Gizmos.color = Color.cyan; // 설정할거에요 -> Gizmo 색상을 청록으로 Gizmos.DrawWireSphere(boss.transform.position, boss.GetThrowRange()); // 그릴거에요 -> 던지기 사거리 구를 // ─────────────── 대시 발동 거리 (자주) ───────────────── Gizmos.color = Color.magenta; // 설정할거에요 -> Gizmo 색상을 자주색으로 Gizmos.DrawWireSphere(boss.transform.position, boss.GetDashChaseRange()); // 그릴거에요 -> 대시 사거리 구를 // ─────────────── 내려찍기 판정 범위 (빨강) ───────────────── Gizmos.color = new Color(1f, 0.2f, 0.2f, 0.5f); // 설정할거에요 -> Gizmo 색상을 반투명 빨강으로 Vector3 smashCenter = boss.transform.position + boss.transform.forward * boss.GetSmashForwardOffset(); // 계산할거에요 -> 내려찍기 중심을 Gizmos.DrawWireSphere(smashCenter, boss.GetSmashRadius()); // 그릴거에요 -> 내려찍기 판정 구를 // ─────────────── 휩쓸기 판정 범위 (주황) ───────────────── Gizmos.color = new Color(1f, 0.6f, 0f, 0.5f); // 설정할거에요 -> Gizmo 색상을 반투명 주황으로 Gizmos.DrawWireSphere(boss.transform.position, boss.GetSweepRadius()); // 그릴거에요 -> 휩쓸기 판정 구를 // ─────────────── 대시+스매시 도착 범위 (노랑) ───────────────── Gizmos.color = new Color(1f, 1f, 0f, 0.4f); // 설정할거에요 -> Gizmo 색상을 반투명 노랑으로 Gizmos.DrawWireSphere(boss.transform.position, boss.GetDashSmashArriveRange()); // 그릴거에요 -> 콤보 도착 거리 구를 // ─────────────── Phase/State 텍스트 (씬 뷰) ───────────────── #if UNITY_EDITOR string phaseText = boss.IsPhase3 ? "Phase 3 (광폭화)" // 결정할거에요 -> Phase 텍스트를 : boss.IsPhase2 ? "Phase 2" : "Phase 1"; string stateText = $"{phaseText} | {boss.GetCurrentState()}"; // 조합할거에요 -> Phase + State 텍스트를 // 조건이 맞으면 실행할거에요 -> 콤보 진행 중이면 if (boss.GetComboCounter() > 0) // 조건을 확인할거에요 -> 콤보 카운터가 stateText += $" | 콤보 #{boss.GetComboCounter()}"; // 덧붙일거에요 -> 콤보 정보를 GUIStyle gizmoStyle = new GUIStyle(); // 생성할거에요 -> Gizmo 텍스트 스타일을 gizmoStyle.fontSize = 14; // 설정할거에요 -> 글자 크기를 gizmoStyle.fontStyle = FontStyle.Bold; // 설정할거에요 -> 글씨 무게를 굵게로 gizmoStyle.normal.textColor = boss.IsPhase3 ? Color.red // 설정할거에요 -> Phase별 색상을 : boss.IsPhase2 ? Color.yellow : Color.white; Vector3 labelPos = boss.transform.position + Vector3.up * 3.5f; // 계산할거에요 -> 보스 머리 위 위치를 UnityEditor.Handles.Label(labelPos, stateText, gizmoStyle); // 그릴거에요 -> 씬 뷰에 텍스트를 #endif } // ══════════════════════════════════════════════════════════ // 게임 화면 디버그 로그 (OnGUI) // 플레이 중 좌측 상단에 보스 상태를 실시간 표시해요. // ══════════════════════════════════════════════════════════ private void OnGUI() // 함수를 정의할거에요 -> 매 프레임 게임 화면에 UI를 그리는 { if (!debugLogOnScreen) return; // 중단할거에요 -> 토글 꺼져있으면 if (boss == null) return; // 중단할거에요 -> 보스 참조 없으면 if (!boss.IsBattleStarted) return; // 중단할거에요 -> 전투 시작 전이면 // ─────────────── Phase 표시 (리치 텍스트) ───────────────── string phase = boss.IsPhase3 ? "Phase 3 (광폭화)" // 결정할거에요 -> Phase 텍스트를 (색상 포함) : boss.IsPhase2 ? "Phase 2" : "Phase 1"; // ─────────────── HP 퍼센트 + 색상 ───────────────── float maxHp = boss.GetMaxHP(); // 가져올거에요 -> 보스 최대 HP를 float currentHp = boss.GetCurrentHP(); // 가져올거에요 -> 보스 현재 HP를 float hpPercent = maxHp > 0 ? (currentHp / maxHp) * 100f : 0f; // 계산할거에요 -> HP 퍼센트를 string hpColor = hpPercent > 50f ? "green" : hpPercent > 25f ? "yellow" : "red"; // 결정할거에요 -> HP 구간별 색상을 // ─────────────── 콤보 표시 ───────────────── int comboCounter = boss.GetComboCounter(); // 가져올거에요 -> 현재 콤보 카운터를 int maxCombo = boss.GetMaxComboCount(); // 가져올거에요 -> 최대 콤보 횟수를 string comboText = comboCounter > 0 // 결정할거에요 -> 콤보 텍스트를 (진행 중일 때만 표시) ? $" 콤보 #{comboCounter}/{maxCombo}" : ""; // ─────────────── 플레이어 거리 ───────────────── float dist = boss.GetDistanceToTarget(); // 가져올거에요 -> 플레이어까지 거리를 // ─────────────── 플레이어 행동 감지 상태 텍스트 ───────────────── string behaviorText = boss.GetPlayerBehaviorText(); // 가져올거에요 -> 플레이어 행동 감지 텍스트를 // ─────────────── 직전 패턴 표시 ───────────────── string lastPatternText = boss.GetLastPatternText(); // 가져올거에요 -> 직전 패턴 정보를 // ─────────────── 텍스트 조합 ───────────────── string debugText = $"{phase}{comboText}\n" // 조합할거에요 -> 전체 디버그 텍스트를 + $"HP: {currentHp:F0}/{maxHp:F0} ({hpPercent:F0}%)\n" + $"State: {boss.GetCurrentState()} | Last: {lastPatternText}\n" + $"거리: {dist:F1}m | 쿨타임: {boss.GetAttackTimer():F1}s\n" + $"간격: {boss.GetPatternInterval():F2}s {behaviorText}"; // ─────────────── 리치 텍스트 지원 스타일 ───────────────── GUIStyle richStyle = new GUIStyle(GUI.skin.box); // 생성할거에요 -> 리치 텍스트 스타일을 richStyle.richText = true; // 활성화할거에요 -> , 등 리치 텍스트 파싱을 richStyle.fontSize = 14; // 설정할거에요 -> 글자 크기를 richStyle.alignment = TextAnchor.UpperLeft; // 설정할거에요 -> 좌측 상단 정렬로 richStyle.normal.textColor = Color.white; // 설정할거에요 -> 기본 글자 색을 하양으로 richStyle.padding = new RectOffset(10, 10, 8, 8); // 설정할거에요 -> 안쪽 여백을 // ─────────────── 화면 좌측 상단에 그리기 ───────────────── GUI.Box(new Rect(10, 10, 360, 120), debugText, richStyle); // 그릴거에요 -> 좌측 상단에 보스 상태 박스를 } }