#if UNITY_EDITOR || DEVELOPMENT_BUILD
using UnityEngine;
using BaseGames.Enemies.Abilities;
using BaseGames.Enemies.StatusEffects;
namespace BaseGames.Enemies
{
///
/// 运行时 AI 状态调试叠加层(仅 Editor)。
/// 挂到敌人 Prefab 根节点,运行时在场景视图 / GameView 上显示:
/// - AiPhase / EnemyStateType
/// - 当前激活的能力名称及运行状态
/// - LOS 状态 / 到玩家距离
/// - Boss:技能执行状态 + 各技能冷却倒计时
///
[AddComponentMenu("BaseGames/Debug/Enemy Debug Overlay")]
public sealed class EnemyDebugOverlay : MonoBehaviour
{
[Header("显示选项")]
[Tooltip("在 Scene 视图中绘制 GUI 标签")]
[SerializeField] private bool _showInSceneView = true;
[Tooltip("在 Game 视图中绘制 GUI 标签(需要 OnGUI)")]
[SerializeField] private bool _showInGameView = false;
[Tooltip("文字背景透明度")]
[SerializeField, Range(0f, 1f)] private float _bgAlpha = 0.65f;
private EnemyBase _enemy;
private BossBase _boss;
private EnemyStatusEffectManager _statusMgr;
private GUIStyle _labelStyle;
private GUIStyle _boxStyle;
private bool _stylesInit;
private void Awake()
{
_enemy = GetComponent();
_boss = GetComponent();
_statusMgr = GetComponent();
}
// ── Scene 视图标签(UnityEditor.Handles.Label)─────────────────────
private void OnDrawGizmos()
{
if (!_showInSceneView || !Application.isPlaying || _enemy == null) return;
var lines = BuildLines();
var label = string.Join("\n", lines);
var pos = transform.position + Vector3.up * 2.2f;
UnityEditor.Handles.Label(pos, label);
}
// ── Game 视图 GUI(OnGUI)──────────────────────────────────────────
private void OnGUI()
{
if (!_showInGameView || !Application.isPlaying || _enemy == null) return;
InitStyles();
var cam = UnityEngine.Camera.main;
if (cam == null) return;
Vector3 worldPos = transform.position + Vector3.up * 2.2f;
Vector3 screen = cam.WorldToScreenPoint(worldPos);
if (screen.z < 0f) return;
float screenY = Screen.height - screen.y;
var lines = BuildLines();
var text = string.Join("\n", lines);
var size = _labelStyle.CalcSize(new GUIContent(text));
var rect = new Rect(screen.x - size.x * 0.5f, screenY - size.y, size.x + 8f, size.y + 4f);
GUI.Box(rect, GUIContent.none, _boxStyle);
GUI.Label(rect, text, _labelStyle);
}
// ── 内部 ──────────────────────────────────────────────────────────
private System.Collections.Generic.List BuildLines()
{
var list = new System.Collections.Generic.List(8);
// 名称
list.Add($"{gameObject.name}");
// AiPhase + EnemyState
list.Add($"Phase: {_enemy.CurrentAiPhase} State: {_enemy.CurrentState}");
// 距离 + LOS
float dist = _enemy.Stats != null ? Mathf.Sqrt(_enemy.Stats.SqrDistanceToPlayer) : -1f;
bool los = _enemy.IsPlayerVisible();
var losColor = los ? "#44ff88" : "#ff6644";
list.Add($"Dist: {dist:F1}m LOS: {los}");
// 当前激活能力
if (_enemy.Abilities != null)
{
foreach (var ab in _enemy.Abilities.All)
{
if (ab.IsRunning)
{
string abilityId = ab.Config?.abilityId ?? ab.GetType().Name;
list.Add($"Ability: {abilityId} [{ab.Phase}]");
}
}
}
// Boss 信息
if (_boss != null)
{
list.Add($"BossSkillExec: {_boss.IsBossSkillExecuting}");
}
// 状态效果
if (_statusMgr != null)
{
var effects = _statusMgr.ActiveEffects;
for (int i = 0; i < effects.Count; i++)
list.Add($"FX: {effects[i].Type}");
}
return list;
}
private void InitStyles()
{
if (_stylesInit) return;
_stylesInit = true;
_labelStyle = new GUIStyle(GUI.skin.label)
{
richText = true,
fontSize = 11,
alignment = TextAnchor.UpperLeft,
padding = new RectOffset(4, 4, 2, 2),
};
_labelStyle.normal.textColor = Color.white;
var bgTex = new Texture2D(1, 1);
bgTex.SetPixel(0, 0, new Color(0.05f, 0.05f, 0.1f, _bgAlpha));
bgTex.Apply();
_boxStyle = new GUIStyle(GUI.skin.box);
_boxStyle.normal.background = bgTex;
}
}
}
#endif