using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEngine; using UnityEngine.UI; using TMPro; namespace MeowmentDebugTool { /// /// 通用调试工具 - 支持多标签页的调试界面系统 /// 默认分辨率: 1080x2340 /// 使用方法: /// 1. 场景中放置 UniversalDebugTool 预制件 /// 2. 在代码中调用 UniversalDebugTool.Init() 初始化 /// 3. 未调用 Init() 前不会显示任何UI /// public class UniversalDebugTool : MonoBehaviour { #region 序列化字段 [Header("主窗口设置")] [SerializeField] private RectTransform mainWindow; [SerializeField] private Canvas canvas; [Header("标签页系统")] [SerializeField] private RectTransform tabButtonContainer; [SerializeField] private RectTransform contentContainer; [SerializeField] private GameObject tabButtonPrefab; [SerializeField] private Button closeButton; [SerializeField] private Color activeTabColor = Color.green; [SerializeField] private Color inactiveTabColor = Color.gray; [Header("悬浮按钮")] [SerializeField] private GameObject floatingButton; [SerializeField] private DraggableFloatingButton draggableComponent; [Header("参数查看页面")] [SerializeField] private GameObject parametersPage; [SerializeField] private TMP_Text deviceInfoText; [SerializeField] private TMP_Text systemInfoText; [SerializeField] private ScrollRect parametersScrollRect; [Header("自定义按钮页面")] [SerializeField] private GameObject customButtonsPage; [SerializeField] private RectTransform buttonContainer; [SerializeField] private GameObject buttonPrefab; [SerializeField] private ScrollRect buttonsScrollRect; [Header("工具栏页面")] [SerializeField] private GameObject toolbarPage; [SerializeField] private Slider timeAdjustSlider; [SerializeField] private TMP_Text timeAdjustValueText; [SerializeField] private Button timeIncreaseButton; [SerializeField] private Button timeDecreaseButton; [Header("设置页面")] [SerializeField] private GameObject settingsPage; [SerializeField] private TMP_InputField widthInputField; [SerializeField] private TMP_InputField heightInputField; [SerializeField] private Button applyResolutionButton; [SerializeField] private Button resetResolutionButton; [SerializeField] private TMP_Text currentResolutionText; [Header("输入对话框")] [SerializeField] private GameObject inputDialog; [SerializeField] private TMP_Text inputDialogTitle; [SerializeField] private TMP_InputField inputDialogInputField; [SerializeField] private Button inputDialogConfirmBtn; [SerializeField] private Button inputDialogCancelBtn; #endregion #region 私有变量 private static UniversalDebugTool instance; private static bool isInitialized = false; private Dictionary pages = new Dictionary(); private Dictionary tabButtons = new Dictionary(); private string currentPageKey = ""; // 默认分辨率 private Vector2 defaultResolution = new Vector2(1080, 2340); private Vector2 currentCustomResolution; // 自定义按钮回调 private static Action customButtonCallback; // Canvas层级设置 private const int TOP_SORT_ORDER = 30000; // 保存的SDF字体资源 private static TMP_FontAsset savedFontAsset = null; #endregion #region 单例 public static UniversalDebugTool Instance { get { if (instance == null) { instance = FindObjectOfType(); } return instance; } } public static bool InstanceExists => instance != null; #endregion #region Unity生命周期 private void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(gameObject); } else if (instance != this) { Destroy(gameObject); return; } currentCustomResolution = defaultResolution; // 设置Canvas为最上层 SetCanvasToTop(); // 未初始化前隐藏所有UI if (!isInitialized) { HideAllUI(); } // 注意:如果isInitialized为true,不在Awake中调用InitializeDebugTool // 因为此时反射设置的字段可能还没生效,延迟到Start中调用 } private void Start() { // 只有在已初始化但还没调用过InitializeDebugTool时才执行 // 这避免了Awake和Init()的重复调用问题 if (isInitialized && pages.Count == 0) { // 这是通过Init()创建的实例,需要在Start中完成初始化 // 此时反射设置的字段已经生效 InitializeDebugTool(); UpdateDeviceInfo(); UpdateSystemInfo(); LoadCustomButtons(); ShowMainWindow(); } } private void OnDestroy() { if (instance == this) { instance = null; } } #endregion #region 初始化 /// /// 初始化调试工具(自动创建UI) /// public static void Init() { if (isInitialized) { Debug.LogWarning("[MeowmentDebugTool] 已经初始化过了"); return; } isInitialized = true; Debug.Log("[MeowmentDebugTool] 开始初始化调试工具..."); // 如果场景中没有实例,运行时自动创建UI if (!InstanceExists) { Debug.Log("[MeowmentDebugTool] 运行时自动创建UI..."); instance = RuntimeUIGenerator.CreateDebugToolUI(); } if (InstanceExists) { Instance.InitializeDebugTool(); Instance.UpdateDeviceInfo(); Instance.UpdateSystemInfo(); Instance.LoadCustomButtons(); Instance.ShowMainWindow(); Debug.Log("[MeowmentDebugTool] ✅ 初始化完成!"); } } /// /// 设置所有TextMeshProUGUI的SDF字体 /// /// TMP字体资源 public static void SetSDFFont(TMP_FontAsset fontAsset) { if (!InstanceExists) { Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法设置字体"); return; } if (fontAsset == null) { Debug.LogWarning("[MeowmentDebugTool] 字体资源为空"); return; } int count = 0; // 1. 获取调试工具Canvas下的所有TextMeshProUGUI组件(包括隐藏的) TextMeshProUGUI[] allTexts = Instance.GetComponentsInChildren(true); foreach (var text in allTexts) { text.font = fontAsset; count++; } // 2. 查找预制件模板(_TempPrefabHolder)下的TextMeshProUGUI GameObject tempPrefabHolder = GameObject.Find("_TempPrefabHolder"); if (tempPrefabHolder != null) { TextMeshProUGUI[] prefabTexts = tempPrefabHolder.GetComponentsInChildren(true); foreach (var text in prefabTexts) { text.font = fontAsset; count++; } Debug.Log($"[MeowmentDebugTool] 已设置预制件模板中的 {prefabTexts.Length} 个文本组件"); } Debug.Log($"[MeowmentDebugTool] 共将 {count} 个文本组件的字体设置为: {fontAsset.name}"); // 3. 保存字体资源,供后续创建的按钮使用 savedFontAsset = fontAsset; Debug.Log("[MeowmentDebugTool] 字体资源已保存,后续创建的按钮将自动应用此字体"); // 4. 重新加载自定义按钮,使新字体应用到已存在的CustomButton Debug.Log("[MeowmentDebugTool] 重新加载自定义按钮以应用新字体..."); Instance.ReloadCustomButtons(); } /// /// 设置Canvas为最上层 /// private void SetCanvasToTop() { if (canvas != null) { canvas.sortingOrder = TOP_SORT_ORDER; canvas.overrideSorting = true; Debug.Log($"[MeowmentDebugTool] Canvas层级设置为: {TOP_SORT_ORDER}"); } } /// /// 隐藏所有UI /// private void HideAllUI() { if (mainWindow != null) mainWindow.gameObject.SetActive(false); if (floatingButton != null) floatingButton.SetActive(false); } private void InitializeDebugTool() { Debug.Log("🚀 初始化UniversalDebugTool..."); // 注册所有页面 RegisterPage("参数", parametersPage); RegisterPage("自定义按钮", customButtonsPage); RegisterPage("工具栏", toolbarPage); RegisterPage("设置", settingsPage); Debug.Log($"📄 已注册{pages.Count}个页面"); // 创建标签按钮 CreateTabButtons(); // 设置按钮事件 if (closeButton != null) closeButton.onClick.AddListener(CloseDebugWindow); if (applyResolutionButton != null) applyResolutionButton.onClick.AddListener(ApplyCustomResolution); if (resetResolutionButton != null) resetResolutionButton.onClick.AddListener(ResetToDefaultResolution); // 设置时间调整工具 if (timeAdjustSlider != null) { timeAdjustSlider.onValueChanged.AddListener(OnTimeAdjustValueChanged); // 初始化显示 UpdateTimeAdjustDisplay(timeAdjustSlider.value); } if (timeIncreaseButton != null) timeIncreaseButton.onClick.AddListener(OnIncreaseTime); if (timeDecreaseButton != null) timeDecreaseButton.onClick.AddListener(OnDecreaseTime); // 设置悬浮按钮点击事件 if (floatingButton != null) { Button floatBtn = floatingButton.GetComponent