782 lines
24 KiB
C#
782 lines
24 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Reflection;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using TMPro;
|
||
|
||
namespace MeowmentDebugTool
|
||
{
|
||
/// <summary>
|
||
/// 通用调试工具 - 支持多标签页的调试界面系统
|
||
/// 默认分辨率: 1080x2340
|
||
/// 使用方法:
|
||
/// 1. 场景中放置 UniversalDebugTool 预制件
|
||
/// 2. 在代码中调用 UniversalDebugTool.Init() 初始化
|
||
/// 3. 未调用 Init() 前不会显示任何UI
|
||
/// </summary>
|
||
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 consolePage;
|
||
[SerializeField] private ScrollRect consoleLogScrollRect;
|
||
[SerializeField] private RectTransform consoleLogContent;
|
||
[SerializeField] private ScrollRect consoleDetailScrollRect;
|
||
[SerializeField] private TMP_Text consoleDetailText;
|
||
[SerializeField] private Button consoleClearButton;
|
||
[SerializeField] private Toggle consoleLockScrollToggle;
|
||
[SerializeField] private Toggle consoleInfoFilterToggle;
|
||
[SerializeField] private Toggle consoleWarningFilterToggle;
|
||
[SerializeField] private Toggle consoleErrorFilterToggle;
|
||
[SerializeField] private Toggle consoleFatalFilterToggle;
|
||
[SerializeField] private GameObject consoleLogItemPrefab;
|
||
|
||
// [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<string, GameObject> pages = new Dictionary<string, GameObject>();
|
||
private Dictionary<string, Button> tabButtons = new Dictionary<string, Button>();
|
||
private string currentPageKey = "";
|
||
|
||
// Canvas层级设置
|
||
private const int TOP_SORT_ORDER = 30000;
|
||
|
||
// 保存的SDF字体资源
|
||
private static TMP_FontAsset savedFontAsset = null;
|
||
|
||
// 模块实例
|
||
private ParametersModule parametersModule;
|
||
private CustomButtonsModule customButtonsModule;
|
||
private ToolbarModule toolbarModule;
|
||
private SettingsModule settingsModule;
|
||
private ConsoleModule consoleModule;
|
||
private List<IDebugModule> allModules = new List<IDebugModule>();
|
||
|
||
// 暂时隐藏状态标志
|
||
private bool isHiding = false;
|
||
#endregion
|
||
|
||
#region 单例
|
||
public static UniversalDebugTool Instance
|
||
{
|
||
get
|
||
{
|
||
if (instance == null)
|
||
{
|
||
instance = FindObjectOfType<UniversalDebugTool>();
|
||
}
|
||
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;
|
||
}
|
||
|
||
// 设置Canvas为最上层
|
||
SetCanvasToTop();
|
||
|
||
// 未初始化前隐藏所有UI
|
||
if (!isInitialized)
|
||
{
|
||
HideAllUI();
|
||
}
|
||
// 注意:如果isInitialized为true,不在Awake中调用InitializeDebugTool
|
||
// 因为此时反射设置的字段可能还没生效,延迟到Start中调用
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
// 只有在已初始化但还没调用过InitializeDebugTool时才执行
|
||
// 这避免了Awake和Init()的重复调用问题
|
||
if (isInitialized && allModules.Count == 0)
|
||
{
|
||
// 这是通过Init()创建的实例,需要在Start中完成初始化
|
||
// 此时反射设置的字段已经生效
|
||
InitializeDebugTool();
|
||
InitializeAllModules();
|
||
ShowMainWindow();
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
// 更新控制台模块
|
||
if (consoleModule != null)
|
||
{
|
||
consoleModule.Update();
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
if (instance == this)
|
||
{
|
||
instance = null;
|
||
|
||
// 销毁控制台模块
|
||
if (consoleModule != null)
|
||
{
|
||
consoleModule.Shutdown();
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 初始化
|
||
/// <summary>
|
||
/// 初始化调试工具(自动创建UI)
|
||
/// </summary>
|
||
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.InitializeAllModules();
|
||
Instance.ShowMainWindow();
|
||
|
||
Debug.Log("[MeowmentDebugTool] 初始化完成!");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置所有TextMeshProUGUI的SDF字体
|
||
/// </summary>
|
||
/// <param name="fontAsset">TMP字体资源</param>
|
||
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<TextMeshProUGUI>(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<TextMeshProUGUI>(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. 通过模块重新加载自定义按钮
|
||
if (Instance.customButtonsModule != null)
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] 重新加载自定义按钮以应用新字体...");
|
||
Instance.customButtonsModule.SetSDFFont(fontAsset);
|
||
Instance.customButtonsModule.ReloadCustomButtons();
|
||
}
|
||
|
||
// 5. 为控制台模块应用字体
|
||
if (Instance.consoleModule != null)
|
||
{
|
||
Instance.consoleModule.SetSDFFont(fontAsset);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置Canvas为最上层
|
||
/// </summary>
|
||
private void SetCanvasToTop()
|
||
{
|
||
if (canvas != null)
|
||
{
|
||
canvas.sortingOrder = TOP_SORT_ORDER;
|
||
canvas.overrideSorting = true;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas层级设置为: {TOP_SORT_ORDER}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏所有UI
|
||
/// </summary>
|
||
private void HideAllUI()
|
||
{
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(false);
|
||
}
|
||
|
||
private void InitializeDebugTool()
|
||
{
|
||
Debug.Log("🚀 初始化UniversalDebugTool...");
|
||
|
||
// 创建模块实例
|
||
parametersModule = new ParametersModule(
|
||
parametersPage, deviceInfoText, systemInfoText, parametersScrollRect);
|
||
|
||
customButtonsModule = new CustomButtonsModule(
|
||
customButtonsPage, buttonContainer, buttonPrefab, buttonsScrollRect, CloseDebugWindow);
|
||
|
||
toolbarModule = new ToolbarModule(
|
||
toolbarPage, timeAdjustSlider, timeAdjustValueText,
|
||
timeIncreaseButton, timeDecreaseButton);
|
||
|
||
settingsModule = new SettingsModule(
|
||
settingsPage, widthInputField, heightInputField,
|
||
applyResolutionButton, resetResolutionButton, currentResolutionText,
|
||
mainWindow, canvas);
|
||
|
||
consoleModule = new ConsoleModule(
|
||
consolePage, consoleLogScrollRect, consoleLogContent,
|
||
consoleDetailScrollRect, consoleDetailText,
|
||
consoleClearButton, consoleLockScrollToggle,
|
||
consoleInfoFilterToggle, consoleWarningFilterToggle,
|
||
consoleErrorFilterToggle, consoleFatalFilterToggle, consoleLogItemPrefab);
|
||
|
||
// 添加所有模块到列表
|
||
allModules.Add(consoleModule);
|
||
allModules.Add(parametersModule);
|
||
allModules.Add(customButtonsModule);
|
||
allModules.Add(toolbarModule);
|
||
allModules.Add(settingsModule);
|
||
|
||
// 注册所有页面
|
||
foreach (var module in allModules)
|
||
{
|
||
RegisterPage(module.GetModuleName(), module.GetPage());
|
||
}
|
||
|
||
Debug.Log($"📄 已注册{pages.Count}个页面");
|
||
|
||
// 创建标签按钮
|
||
CreateTabButtons();
|
||
|
||
// 设置按钮事件
|
||
if (closeButton != null)
|
||
closeButton.onClick.AddListener(CloseDebugWindow);
|
||
|
||
// 设置悬浮按钮点击事件
|
||
if (floatingButton != null)
|
||
{
|
||
Button floatBtn = floatingButton.GetComponent<Button>();
|
||
if (floatBtn != null)
|
||
{
|
||
floatBtn.onClick.AddListener(OnFloatingButtonClick);
|
||
}
|
||
}
|
||
|
||
// 默认显示第一个页面
|
||
if (pages.Count > 0)
|
||
{
|
||
ShowPage("参数");
|
||
}
|
||
|
||
Debug.Log("[OK] UniversalDebugTool初始化完成!");
|
||
Debug.Log("💡 提示: 点击窗口顶部的标签切换页面,或按F1-F4使用快捷键");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化所有模块
|
||
/// </summary>
|
||
private void InitializeAllModules()
|
||
{
|
||
Debug.Log("🔧 初始化所有模块...");
|
||
foreach (var module in allModules)
|
||
{
|
||
module.Initialize();
|
||
}
|
||
Debug.Log("[OK] 所有模块初始化完成!");
|
||
}
|
||
|
||
private void RegisterPage(string pageName, GameObject pageObject)
|
||
{
|
||
if (pageObject != null && !pages.ContainsKey(pageName))
|
||
{
|
||
pages[pageName] = pageObject;
|
||
pageObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
private void CreateTabButtons()
|
||
{
|
||
if (tabButtonPrefab == null || tabButtonContainer == null)
|
||
{
|
||
string errorDetails = $"tabButtonPrefab={(tabButtonPrefab == null ? "null" : "已设置")}, " +
|
||
$"tabButtonContainer={(tabButtonContainer == null ? "null" : "已设置")}";
|
||
Debug.LogWarning($"⚠️ [MeowmentDebugTool] 标签按钮预制件或容器未完全初始化:{errorDetails}");
|
||
Debug.LogWarning("💡 这可能是Unity初始化顺序问题,如果标签正常显示则可以忽略此警告");
|
||
return;
|
||
}
|
||
|
||
Debug.Log($"📋 开始创建{pages.Count}个标签按钮...");
|
||
|
||
foreach (var page in pages)
|
||
{
|
||
GameObject buttonObj = Instantiate(tabButtonPrefab, tabButtonContainer);
|
||
buttonObj.name = $"Tab_{page.Key}";
|
||
|
||
Button button = buttonObj.GetComponent<Button>();
|
||
TMP_Text buttonText = buttonObj.GetComponentInChildren<TMP_Text>();
|
||
|
||
if (buttonText != null)
|
||
{
|
||
buttonText.text = page.Key;
|
||
Debug.Log($"[OK] 创建标签: [{page.Key}]");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"⚠️ 标签按钮 [{page.Key}] 缺少文本组件");
|
||
}
|
||
|
||
string pageName = page.Key; // 闭包捕获
|
||
button.onClick.AddListener(() => ShowPage(pageName));
|
||
|
||
tabButtons[page.Key] = button;
|
||
}
|
||
|
||
Debug.Log("[OK] 标签按钮创建完成!");
|
||
}
|
||
#endregion
|
||
|
||
#region 页面管理
|
||
/// <summary>
|
||
/// 显示指定的页面
|
||
/// </summary>
|
||
public void ShowPage(string pageName)
|
||
{
|
||
if (!pages.ContainsKey(pageName))
|
||
{
|
||
Debug.LogWarning($"页面 '{pageName}' 不存在!");
|
||
return;
|
||
}
|
||
|
||
// 隐藏所有页面
|
||
foreach (var page in pages.Values)
|
||
{
|
||
page.SetActive(false);
|
||
}
|
||
|
||
// 显示目标页面
|
||
pages[pageName].SetActive(true);
|
||
currentPageKey = pageName;
|
||
|
||
// 更新标签按钮状态
|
||
UpdateTabButtonStates(pageName);
|
||
}
|
||
|
||
private void UpdateTabButtonStates(string activePageName)
|
||
{
|
||
foreach (var kvp in tabButtons)
|
||
{
|
||
Image buttonImage = kvp.Value.GetComponent<Image>();
|
||
if (buttonImage != null)
|
||
{
|
||
buttonImage.color = kvp.Key == activePageName ? activeTabColor : inactiveTabColor;
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 参数查看功能(通过ParametersModule)
|
||
/// <summary>
|
||
/// 复制设备信息到剪贴板
|
||
/// </summary>
|
||
public void CopyDeviceInfoToClipboard()
|
||
{
|
||
parametersModule?.CopyDeviceInfoToClipboard();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复制系统信息到剪贴板
|
||
/// </summary>
|
||
public void CopySystemInfoToClipboard()
|
||
{
|
||
parametersModule?.CopySystemInfoToClipboard();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新所有信息
|
||
/// </summary>
|
||
public void RefreshAllInfo()
|
||
{
|
||
parametersModule?.RefreshAllInfo();
|
||
}
|
||
#endregion
|
||
|
||
#region 自定义按钮功能(通过CustomButtonsModule)
|
||
/// <summary>
|
||
/// 设置自定义按钮回调
|
||
/// </summary>
|
||
public static void SetCustomButtonCallback(Action<Button, TMP_Text> callback)
|
||
{
|
||
if (InstanceExists && Instance.customButtonsModule != null)
|
||
{
|
||
Instance.customButtonsModule.SetCustomButtonCallback(callback);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重新加载自定义按钮
|
||
/// </summary>
|
||
public void ReloadCustomButtons()
|
||
{
|
||
customButtonsModule?.ReloadCustomButtons();
|
||
}
|
||
#endregion
|
||
|
||
|
||
|
||
|
||
|
||
// #region 输入对话框
|
||
// /// <summary>
|
||
// /// 显示输入对话框
|
||
// /// </summary>
|
||
// public static void ShowInputDialog(string title, Action<string> onConfirmAction,
|
||
// string initialValue = "", TMP_InputField.ContentType contentType = TMP_InputField.ContentType.Standard)
|
||
// {
|
||
// if (!InstanceExists) return;
|
||
|
||
// var inst = Instance;
|
||
// if (inst.inputDialog == null) return;
|
||
|
||
// inst.inputDialogInputField.contentType = contentType;
|
||
// inst.inputDialog.SetActive(true);
|
||
// inst.inputDialogTitle.text = title;
|
||
// inst.inputDialogInputField.text = initialValue;
|
||
|
||
// inst.inputDialogConfirmBtn.onClick.RemoveAllListeners();
|
||
// inst.inputDialogConfirmBtn.onClick.AddListener(() =>
|
||
// {
|
||
// onConfirmAction?.Invoke(inst.inputDialogInputField.text);
|
||
// CloseInputDialog();
|
||
// });
|
||
|
||
// inst.inputDialogCancelBtn.onClick.RemoveAllListeners();
|
||
// inst.inputDialogCancelBtn.onClick.AddListener(CloseInputDialog);
|
||
// }
|
||
|
||
// /// <summary>
|
||
// /// 关闭输入对话框
|
||
// /// </summary>
|
||
// public static void CloseInputDialog()
|
||
// {
|
||
// if (!InstanceExists) return;
|
||
|
||
// var inst = Instance;
|
||
// if (inst.inputDialog == null) return;
|
||
|
||
// inst.inputDialog.SetActive(false);
|
||
// inst.inputDialogInputField.text = "";
|
||
// inst.inputDialogConfirmBtn.onClick.RemoveAllListeners();
|
||
// inst.inputDialogCancelBtn.onClick.RemoveAllListeners();
|
||
// }
|
||
// #endregion
|
||
|
||
#region 公共API
|
||
/// <summary>
|
||
/// 显示调试工具
|
||
/// </summary>
|
||
public static void Show()
|
||
{
|
||
if (InstanceExists)
|
||
{
|
||
Instance.gameObject.SetActive(true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏调试工具
|
||
/// </summary>
|
||
public static void Hide()
|
||
{
|
||
if (InstanceExists)
|
||
{
|
||
Instance.gameObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换调试工具显示状态
|
||
/// </summary>
|
||
public static void Toggle()
|
||
{
|
||
if (InstanceExists)
|
||
{
|
||
if (Instance.mainWindow != null && Instance.mainWindow.gameObject.activeSelf)
|
||
{
|
||
Instance.CloseDebugWindow();
|
||
}
|
||
else
|
||
{
|
||
Instance.OpenDebugWindow();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭调试窗口,显示悬浮按钮
|
||
/// </summary>
|
||
public void CloseDebugWindow()
|
||
{
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(true);
|
||
|
||
Debug.Log("[关闭] 调试窗口已关闭");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 悬浮按钮点击回调(检查是否为拖动)
|
||
/// </summary>
|
||
private void OnFloatingButtonClick()
|
||
{
|
||
// 检查是否刚拖动过
|
||
if (draggableComponent != null && draggableComponent.GetWasDragging())
|
||
{
|
||
// 如果刚拖动过,不打开窗口
|
||
Debug.Log("🚫 拖动操作,不打开窗口");
|
||
return;
|
||
}
|
||
|
||
// 否则打开窗口
|
||
OpenDebugWindow();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打开调试窗口,隐藏悬浮按钮
|
||
/// </summary>
|
||
public void OpenDebugWindow()
|
||
{
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(false);
|
||
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(true);
|
||
|
||
Debug.Log("[打开] 调试窗口已打开");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示主窗口(初始化时调用)
|
||
/// </summary>
|
||
private void ShowMainWindow()
|
||
{
|
||
if (mainWindow != null)
|
||
mainWindow.gameObject.SetActive(false);
|
||
|
||
if (floatingButton != null)
|
||
floatingButton.SetActive(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暂时隐藏调试工具UI(用于截图等场景)
|
||
/// </summary>
|
||
/// <param name="seconds">隐藏的秒数,默认5秒</param>
|
||
public static void HideTemporarily(float seconds = 5f)
|
||
{
|
||
if (!InstanceExists)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 调试工具未初始化,无法隐藏");
|
||
return;
|
||
}
|
||
|
||
if (Instance.isHiding)
|
||
{
|
||
Debug.LogWarning("[MeowmentDebugTool] 已经在隐藏状态中,请等待恢复");
|
||
return;
|
||
}
|
||
|
||
Instance.StartCoroutine(Instance.HideTemporarilyCoroutine(seconds));
|
||
}
|
||
|
||
private IEnumerator HideTemporarilyCoroutine(float seconds)
|
||
{
|
||
isHiding = true;
|
||
Debug.Log($"[MeowmentDebugTool] 开始暂时隐藏流程,时长: {seconds}秒");
|
||
|
||
// 保存Canvas初始状态
|
||
if (canvas == null)
|
||
{
|
||
Debug.LogError("[MeowmentDebugTool] Canvas为空!");
|
||
isHiding = false;
|
||
yield break;
|
||
}
|
||
|
||
bool canvasWasEnabled = canvas.enabled;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas初始状态: {(canvasWasEnabled ? "启用" : "禁用")}");
|
||
|
||
// 1. 先关闭主窗口(如果是打开状态)
|
||
bool wasMainWindowOpen = mainWindow != null && mainWindow.gameObject.activeSelf;
|
||
Debug.Log($"[MeowmentDebugTool] 主窗口初始状态: {(wasMainWindowOpen ? "打开" : "关闭")}");
|
||
|
||
if (wasMainWindowOpen)
|
||
{
|
||
CloseDebugWindow();
|
||
yield return null;
|
||
Debug.Log("[MeowmentDebugTool] 主窗口已关闭");
|
||
}
|
||
|
||
// 2. 隐藏Canvas(包括浮窗)
|
||
canvas.enabled = false;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas已禁用,UI完全隐藏");
|
||
|
||
// 3. 等待指定时间
|
||
yield return new WaitForSeconds(seconds);
|
||
|
||
// 4. 恢复Canvas
|
||
canvas.enabled = true;
|
||
Debug.Log($"[MeowmentDebugTool] Canvas已启用,UI恢复显示");
|
||
|
||
// 5. 验证恢复结果
|
||
if (canvas.enabled)
|
||
{
|
||
Debug.Log("[MeowmentDebugTool] ✓ UI已成功恢复(浮窗状态)");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("[MeowmentDebugTool] ✗ Canvas恢复失败!");
|
||
}
|
||
|
||
isHiding = false;
|
||
Debug.Log("[MeowmentDebugTool] 暂时隐藏流程结束");
|
||
}
|
||
#endregion
|
||
}
|
||
|
||
#region 自定义特性
|
||
/// <summary>
|
||
/// 调试按钮特性 - 标记方法为调试按钮
|
||
///
|
||
/// 使用说明:
|
||
/// 1. 在主项目中使用此特性时,请用条件编译包裹:
|
||
///
|
||
/// #if MEOWMENT_DEBUG_TOOL
|
||
/// [DebugButton("我的调试按钮")]
|
||
/// public static void MyDebugMethod()
|
||
/// {
|
||
/// Debug.Log("调试方法被执行");
|
||
/// }
|
||
/// #endif
|
||
///
|
||
/// 2. 这样当包被卸载时,代码不会报错,也不会影响主工程的正常运行
|
||
/// 3. MEOWMENT_DEBUG_TOOL 宏会在包安装时自动定义,卸载时自动移除
|
||
/// </summary>
|
||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||
public class DebugButtonAttribute : Attribute
|
||
{
|
||
public string DisplayName { get; set; }
|
||
public Color ButtonColor { get; set; }
|
||
|
||
public DebugButtonAttribute(string displayName = "", float r = 0.8f, float g = 0.8f, float b = 0.8f)
|
||
{
|
||
DisplayName = displayName;
|
||
ButtonColor = new Color(r, g, b, 1f);
|
||
}
|
||
}
|
||
#endregion
|
||
}
|