Files
zeling_v2/Assets/_Game/Scripts/Enemies/EnemyDebugOverlay.cs
T
joywayerandClaude Opus 5 a44aafee3a refactor(enemy): BossBase 瘦身——删技能执行与弹反反制两套
技能选取/执行归 EnemyAttackSelector + EnemyAbilityBase(阶段一已就位),
BossBase 不再持有 BossSkillExecutor。阶段切换改用能力注册表打断在跑的招。

弹反反制整套删除:它订阅的是全局弹反成功频道,无来源过滤——
玩家弹反任意小怪都会让场上 Boss 硬直。正确形态是 EnemyBase.ReceiveParry
(谁被弹反谁硬直),其接线为独立后续任务。

调试面板的 BossSkillExec 行换为阶段与过渡状态。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 16:19:21 +08:00

153 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#if UNITY_EDITOR || DEVELOPMENT_BUILD
using UnityEngine;
using BaseGames.Enemies.Abilities;
using BaseGames.Enemies.StatusEffects;
namespace BaseGames.Enemies
{
/// <summary>
/// 运行时 AI 状态调试叠加层(仅 Editor)。
/// 挂到敌人 Prefab 根节点,运行时在场景视图 / GameView 上显示:
/// - AI 决策状态 / EnemyStateType
/// - 当前激活的能力名称及运行状态
/// - LOS 状态 / 到玩家距离
/// - Boss:当前阶段与阶段过渡状态
/// </summary>
[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<EnemyBase>();
_boss = GetComponent<BossBase>();
_statusMgr = GetComponent<EnemyStatusEffectManager>();
}
// ── 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<string> BuildLines()
{
var list = new System.Collections.Generic.List<string>(8);
// 名称
list.Add($"<b>{gameObject.name}</b>");
// AI 决策状态 + EnemyState
list.Add($"Phase: <color=#ffcc44>{(_enemy.Brain != null ? _enemy.Brain.CurrentStateName : "-")}</color> State: <color=#88ddff>{_enemy.CurrentState}</color>");
// 距离 + 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: <color={losColor}>{los}</color>");
// 当前激活能力
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: <color=#ffaa44>{abilityId}</color> [{ab.Phase}]");
}
}
}
// Boss 信息
if (_boss != null)
{
// 上面第 2 行已用 "Phase:" 表示 AI 决策状态名,这里用 "BossPhase:" 区分,避免同名两行
list.Add($"BossPhase: {_boss.CurrentPhase}" +
(_boss.IsPhaseTransitioning ? " <color=#ffcc44>(transitioning)</color>" : ""));
}
// 状态效果
if (_statusMgr != null)
{
var effects = _statusMgr.ActiveEffects;
for (int i = 0; i < effects.Count; i++)
list.Add($"FX: <color=#dd88ff>{effects[i].Type}</color>");
}
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