135 lines
4.5 KiB
C#
135 lines
4.5 KiB
C#
using System.Collections.Generic;
|
|
using Cielonos.MainGame.Characters;
|
|
using UnityEngine;
|
|
|
|
namespace Cielonos.MainGame
|
|
{
|
|
/// <summary>
|
|
/// 索敌评分 Debug 显示组件。
|
|
/// 挂载到场景中任意 GameObject 上,运行时在每个敌人头顶显示当前索敌评分。
|
|
/// 仅在 Debug 模式开启时绘制,不影响正式构建。
|
|
/// </summary>
|
|
public class TargetingDebugDisplay : MonoBehaviour
|
|
{
|
|
[Header("Debug 设置")]
|
|
[Tooltip("是否启用索敌评分显示")]
|
|
public bool enableDebug;
|
|
|
|
[Tooltip("索敌评分查询半径")]
|
|
public float debugRadius = 20f;
|
|
|
|
[Tooltip("文字显示在敌人头顶的偏移量")]
|
|
public float headOffset = 2.2f;
|
|
|
|
[Tooltip("文字大小")]
|
|
public int fontSize = 20;
|
|
|
|
[Tooltip("最高分目标的标记颜色")]
|
|
public Color bestTargetColor = Color.green;
|
|
|
|
[Tooltip("普通目标的文字颜色")]
|
|
public Color normalColor = Color.white;
|
|
|
|
[Tooltip("背景颜色")]
|
|
public Color backgroundColor = new Color(0f, 0f, 0f, 0.6f);
|
|
|
|
private List<CombatManager.EnemySubmodule.TargetingScore> _cachedScores = new();
|
|
private readonly Dictionary<CharacterBase, CombatManager.EnemySubmodule.TargetingScore> _scoreMap = new();
|
|
private float _updateInterval = 0.1f;
|
|
private float _nextUpdateTime;
|
|
|
|
private GUIStyle _labelStyle;
|
|
private GUIStyle _bgStyle;
|
|
private Texture2D _bgTexture;
|
|
|
|
private void Update()
|
|
{
|
|
if (!enableDebug) return;
|
|
|
|
if (Time.time >= _nextUpdateTime)
|
|
{
|
|
_nextUpdateTime = Time.time + _updateInterval;
|
|
_cachedScores = CombatManager.EnemySm.GetScoredEnemies(debugRadius);
|
|
_scoreMap.Clear();
|
|
foreach (var score in _cachedScores)
|
|
{
|
|
_scoreMap[score.target] = score;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnGUI()
|
|
{
|
|
if (!enableDebug || _cachedScores.Count == 0) return;
|
|
|
|
EnsureStyles();
|
|
|
|
Camera cam = Camera.main;
|
|
if (cam == null) return;
|
|
|
|
bool isFirst = true;
|
|
foreach (var score in _cachedScores)
|
|
{
|
|
if (score.target == null) continue;
|
|
|
|
Vector3 worldPos = score.target.centerPoint.position + Vector3.up * headOffset;
|
|
Vector3 screenPos = cam.WorldToScreenPoint(worldPos);
|
|
|
|
if (screenPos.z <= 0) continue;
|
|
|
|
float guiY = Screen.height - screenPos.y;
|
|
|
|
string text = $"Total: {score.totalScore:F2}";
|
|
if (score.bonusScore != 0f)
|
|
{
|
|
text += $" (Base: {score.baseScore:F2} + Bonus: {score.bonusScore:F2})";
|
|
}
|
|
text += $"\nDist: {score.distanceScore:F2} Input: {score.inputDirScore:F2}" +
|
|
$"\nCam: {score.cameraFacingScore:F2} Sticky: {score.stickyScore:F2} Lock: {score.lockOnScore:F2}";
|
|
|
|
GUIContent content = new GUIContent(text);
|
|
Vector2 size = _labelStyle.CalcSize(content);
|
|
// CalcSize 不考虑换行,用 CalcHeight 代替
|
|
float height = _labelStyle.CalcHeight(content, size.x);
|
|
Rect bgRect = new Rect(screenPos.x - size.x / 2 - 4, guiY - height - 4, size.x + 8, height + 8);
|
|
Rect textRect = new Rect(screenPos.x - size.x / 2, guiY - height, size.x, height);
|
|
|
|
GUI.Box(bgRect, GUIContent.none, _bgStyle);
|
|
_labelStyle.normal.textColor = isFirst ? bestTargetColor : normalColor;
|
|
GUI.Label(textRect, content, _labelStyle);
|
|
|
|
isFirst = false;
|
|
}
|
|
}
|
|
|
|
private void EnsureStyles()
|
|
{
|
|
if (_labelStyle != null) return;
|
|
|
|
_bgTexture = new Texture2D(1, 1);
|
|
_bgTexture.SetPixel(0, 0, backgroundColor);
|
|
_bgTexture.Apply();
|
|
|
|
_bgStyle = new GUIStyle(GUI.skin.box)
|
|
{
|
|
normal = { background = _bgTexture }
|
|
};
|
|
|
|
_labelStyle = new GUIStyle(GUI.skin.label)
|
|
{
|
|
fontSize = fontSize,
|
|
alignment = TextAnchor.UpperCenter,
|
|
wordWrap = false
|
|
};
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (_bgTexture != null)
|
|
{
|
|
Destroy(_bgTexture);
|
|
}
|
|
}
|
|
}
|
|
}
|