- 드로그 전투 컨텍스트를 BossBehaviorRuntimeState 중심 구조로 정리하고 BossEnemy, 패턴 액션, 조건 노드가 마지막 실행 결과와 phase 상태를 직접 사용하도록 갱신 - BT_Drog와 재빌드 에디터 스크립트를 확장해 phase 전환, 집행 결과 분기, 거리/쿨타임 기반 패턴 선택을 드로그 전용 자산과 노드 파라미터로 재구성 - 드로그 패턴/스킬/이펙트/애니메이션 플레이스홀더 자산을 재생성하고 보스 프리팹이 새 런타임 상태 및 등록 클립 구성을 참조하도록 정리
331 lines
11 KiB
C#
331 lines
11 KiB
C#
#if UNITY_EDITOR
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using Colosseum.Enemy;
|
|
|
|
namespace Colosseum.Editor
|
|
{
|
|
/// <summary>
|
|
/// BossEnemy 커스텀 인스펙터.
|
|
/// 페이즈 정보, HP, 상태를 시각적으로 표시합니다.
|
|
/// </summary>
|
|
[CustomEditor(typeof(BossEnemy))]
|
|
public class BossEnemyEditor : UnityEditor.Editor
|
|
{
|
|
private BossEnemy boss;
|
|
private BossBehaviorRuntimeState bossContext;
|
|
private bool showPhaseDetails = true;
|
|
private bool showThreatInfo = true;
|
|
private bool showDebugTools = true;
|
|
private int selectedPhaseIndex = 0;
|
|
private float debugHPPercent = 1f;
|
|
private float debugHPValue = 0f;
|
|
private string customConditionId = "Enraged";
|
|
|
|
private void OnEnable()
|
|
{
|
|
boss = (BossEnemy)target;
|
|
bossContext = boss != null ? boss.GetComponent<BossBehaviorRuntimeState>() : null;
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
// 기본 인스펙터 그리기
|
|
DrawDefaultInspector();
|
|
|
|
if (!Application.isPlaying)
|
|
{
|
|
EditorGUILayout.HelpBox("런타임 디버그 정보는 플레이 모드에서만 표시됩니다.", MessageType.Info);
|
|
return;
|
|
}
|
|
|
|
EditorGUILayout.Space(10);
|
|
|
|
// 상태 요약
|
|
DrawStatusSummary();
|
|
|
|
EditorGUILayout.Space(10);
|
|
|
|
// 페이즈 정보
|
|
DrawPhaseInfo();
|
|
|
|
EditorGUILayout.Space(10);
|
|
|
|
// 위협 정보
|
|
DrawThreatInfo();
|
|
|
|
EditorGUILayout.Space(10);
|
|
|
|
// 디버그 도구
|
|
DrawDebugTools();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 상태 요약 표시
|
|
/// </summary>
|
|
private void DrawStatusSummary()
|
|
{
|
|
EditorGUILayout.LabelField("상태 요약", EditorStyles.boldLabel);
|
|
EditorGUI.indentLevel++;
|
|
|
|
// HP 바
|
|
float hpPercent = boss.MaxHealth > 0 ? boss.CurrentHealth / boss.MaxHealth : 0f;
|
|
DrawProgressBar("HP", hpPercent, GetHealthColor(hpPercent), $"{boss.CurrentHealth:F0} / {boss.MaxHealth:F0}");
|
|
|
|
// 상태 정보
|
|
EditorGUILayout.LabelField("현재 페이즈", bossContext != null
|
|
? $"{bossContext.CurrentPatternPhase} / {bossContext.MaxPatternPhase}"
|
|
: "N/A");
|
|
EditorGUILayout.LabelField("상태", GetStatusText());
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 페이즈 상세 정보 표시
|
|
/// </summary>
|
|
private void DrawPhaseInfo()
|
|
{
|
|
showPhaseDetails = EditorGUILayout.Foldout(showPhaseDetails, "페이즈 상세 정보", true);
|
|
|
|
if (!showPhaseDetails)
|
|
return;
|
|
|
|
EditorGUI.indentLevel++;
|
|
|
|
if (bossContext == null)
|
|
{
|
|
EditorGUILayout.HelpBox("BossBehaviorRuntimeState를 찾지 못했습니다.", MessageType.Warning);
|
|
EditorGUI.indentLevel--;
|
|
return;
|
|
}
|
|
|
|
EditorGUILayout.LabelField("현재 Phase", bossContext.CurrentPatternPhase.ToString());
|
|
EditorGUILayout.LabelField("최대 Phase", bossContext.MaxPatternPhase.ToString());
|
|
EditorGUILayout.LabelField("경과 시간", $"{bossContext.PhaseElapsedTime:F1}초");
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 위협 정보 표시
|
|
/// </summary>
|
|
private void DrawThreatInfo()
|
|
{
|
|
showThreatInfo = EditorGUILayout.Foldout(showThreatInfo, "위협 정보", true);
|
|
|
|
if (!showThreatInfo)
|
|
return;
|
|
|
|
EditorGUI.indentLevel++;
|
|
|
|
if (!boss.UseThreatSystem)
|
|
{
|
|
EditorGUILayout.HelpBox("위협 시스템이 비활성화되어 있습니다.", MessageType.Info);
|
|
EditorGUI.indentLevel--;
|
|
return;
|
|
}
|
|
|
|
EditorGUILayout.LabelField("위협 테이블", EditorStyles.boldLabel);
|
|
EditorGUILayout.TextArea(boss.GetThreatDebugSummary(), GUILayout.MinHeight(70f));
|
|
|
|
if (GUILayout.Button("위협 초기화"))
|
|
{
|
|
boss.ClearAllThreat();
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 디버그 도구 표시
|
|
/// </summary>
|
|
private void DrawDebugTools()
|
|
{
|
|
showDebugTools = EditorGUILayout.Foldout(showDebugTools, "디버그 도구", true);
|
|
|
|
if (!showDebugTools)
|
|
return;
|
|
|
|
EditorGUI.indentLevel++;
|
|
|
|
EditorGUILayout.HelpBox("이 도구는 서버에서만 작동합니다.", MessageType.Info);
|
|
|
|
// 페이즈 강제 전환
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("페이즈 강제 전환", GUILayout.Width(120));
|
|
int maxPhaseIndex = bossContext != null ? Mathf.Max(0, bossContext.MaxPatternPhase - 1) : 0;
|
|
selectedPhaseIndex = EditorGUILayout.IntSlider(selectedPhaseIndex, 0, maxPhaseIndex);
|
|
if (GUILayout.Button("전환", GUILayout.Width(60)))
|
|
{
|
|
if (Application.isPlaying && bossContext != null)
|
|
{
|
|
bossContext.SetCurrentPatternPhase(selectedPhaseIndex + 1);
|
|
}
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Space(5);
|
|
|
|
// 현재 페이즈 재시작
|
|
if (GUILayout.Button("현재 페이즈 재시작"))
|
|
{
|
|
if (Application.isPlaying && bossContext != null)
|
|
{
|
|
bossContext.RestartCurrentPhaseTimer();
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.Space(5);
|
|
|
|
// HP 조작
|
|
EditorGUILayout.LabelField("HP 조작", EditorStyles.boldLabel);
|
|
EditorGUI.indentLevel++;
|
|
|
|
// 현재 HP 표시
|
|
EditorGUILayout.LabelField("현재",
|
|
$"{boss.CurrentHealth:F0} / {boss.MaxHealth:F0} ({(boss.MaxHealth > 0 ? boss.CurrentHealth / boss.MaxHealth * 100f : 0f):F1}%)");
|
|
|
|
// 퍼센트 슬라이더
|
|
EditorGUI.BeginChangeCheck();
|
|
debugHPPercent = EditorGUILayout.Slider("퍼센트", debugHPPercent, 0f, 1f);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
SetBossHP(debugHPPercent);
|
|
}
|
|
|
|
// 직접 HP 값 입력
|
|
EditorGUILayout.BeginHorizontal();
|
|
debugHPValue = EditorGUILayout.FloatField("직접 입력", debugHPValue);
|
|
EditorGUILayout.LabelField($"/ {boss.MaxHealth:F0}", GUILayout.Width(80));
|
|
if (GUILayout.Button("적용", GUILayout.Width(60)))
|
|
{
|
|
float clamped = Mathf.Clamp(debugHPValue, 0f, boss.MaxHealth);
|
|
float percent = boss.MaxHealth > 0 ? clamped / boss.MaxHealth : 0f;
|
|
debugHPPercent = percent;
|
|
SetBossHP(percent);
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUI.indentLevel--;
|
|
|
|
// 빠른 HP 설정 버튼
|
|
EditorGUILayout.Space(3);
|
|
EditorGUILayout.BeginHorizontal();
|
|
if (GUILayout.Button("HP 10%"))
|
|
{
|
|
SetBossHP(0.1f);
|
|
}
|
|
if (GUILayout.Button("HP 30%"))
|
|
{
|
|
SetBossHP(0.3f);
|
|
}
|
|
if (GUILayout.Button("HP 50%"))
|
|
{
|
|
SetBossHP(0.5f);
|
|
}
|
|
if (GUILayout.Button("HP 100%"))
|
|
{
|
|
SetBossHP(1f);
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Space(5);
|
|
|
|
// 커스텀 조건
|
|
EditorGUILayout.LabelField("커스텀 조건 설정", EditorStyles.boldLabel);
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("조건 ID:", GUILayout.Width(60));
|
|
customConditionId = EditorGUILayout.TextField(customConditionId);
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
if (GUILayout.Button("활성화"))
|
|
{
|
|
bossContext?.SetPhaseCustomCondition(customConditionId, true);
|
|
}
|
|
if (GUILayout.Button("비활성화"))
|
|
{
|
|
bossContext?.SetPhaseCustomCondition(customConditionId, false);
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HP 설정 (서버에서만)
|
|
/// </summary>
|
|
private void SetBossHP(float percent)
|
|
{
|
|
if (!Application.isPlaying)
|
|
return;
|
|
|
|
float targetHP = boss.MaxHealth * percent;
|
|
float damage = boss.CurrentHealth - targetHP;
|
|
|
|
if (damage > 0)
|
|
{
|
|
boss.TakeDamage(damage);
|
|
}
|
|
else if (damage < 0)
|
|
{
|
|
boss.Heal(-damage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 진행 바 그리기
|
|
/// </summary>
|
|
private void DrawProgressBar(string label, float value, Color color, string text = "")
|
|
{
|
|
Rect rect = EditorGUILayout.GetControlRect();
|
|
rect.height = 20f;
|
|
|
|
// 레이블
|
|
Rect labelRect = new Rect(rect.x, rect.y, 60, rect.height);
|
|
EditorGUI.LabelField(labelRect, label);
|
|
|
|
// 바
|
|
Rect barRect = new Rect(rect.x + 65, rect.y, rect.width - 65, rect.height);
|
|
EditorGUI.DrawRect(barRect, new Color(0.2f, 0.2f, 0.2f));
|
|
|
|
Rect fillRect = new Rect(barRect.x, barRect.y, barRect.width * Mathf.Clamp01(value), barRect.height);
|
|
EditorGUI.DrawRect(fillRect, color);
|
|
|
|
// 텍스트
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
GUIStyle centeredStyle = new GUIStyle(EditorStyles.label)
|
|
{
|
|
alignment = TextAnchor.MiddleCenter
|
|
};
|
|
EditorGUI.LabelField(barRect, text, centeredStyle);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// HP 비율에 따른 색상 반환
|
|
/// </summary>
|
|
private Color GetHealthColor(float percent)
|
|
{
|
|
if (percent > 0.6f)
|
|
return new Color(0.2f, 0.8f, 0.2f); // 녹색
|
|
if (percent > 0.3f)
|
|
return new Color(0.9f, 0.7f, 0.1f); // 노란색
|
|
return new Color(0.9f, 0.2f, 0.2f); // 빨간색
|
|
}
|
|
|
|
/// <summary>
|
|
/// 상태 텍스트 반환
|
|
/// </summary>
|
|
private string GetStatusText()
|
|
{
|
|
if (boss.IsDead)
|
|
return "<color=red>사망</color>";
|
|
return "<color=green>활성</color>";
|
|
}
|
|
}
|
|
}
|
|
#endif
|