diff --git a/MeowMentDebugTool.slnx b/MeowMentDebugTool.slnx index 8812841..4be91a3 100644 --- a/MeowMentDebugTool.slnx +++ b/MeowMentDebugTool.slnx @@ -1,4 +1,5 @@  - - + + + diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md new file mode 100644 index 0000000..a69f5fb --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +所有重要的变更都会记录在这个文件中。 + +格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), +版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。 + +## [0.2.2] - 2025-12-19 + +### Changed +- 默认显示浮窗而不是主窗口,提升用户体验 +- 点击自定义按钮后自动关闭主窗口,方便用户直接查看功能效果 + +### Fixed +- 优化初始化逻辑,避免重复初始化问题 + +## [0.2.0] - 2025-12-XX + +### Added +- 初始版本发布 +- 支持多标签页调试界面系统 +- 参数查看页面(设备信息、系统信息) +- 自定义按钮功能(通过反射自动加载带 `[DebugButton]` 特性的方法) +- 工具栏页面(时间调整工具) +- 设置页面(分辨率调整) +- 可拖拽的悬浮按钮 +- 输入对话框功能 +- 支持运行时动态创建UI +- 支持自定义 TextMeshPro SDF 字体 + +### Features +- Canvas层级设置为30000,确保始终在最上层 +- 未调用 `Init()` 前不显示任何UI +- 支持快捷键切换页面(F1-F4) +- DontDestroyOnLoad 确保场景切换时不销毁 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md.meta new file mode 100644 index 0000000..ababec7 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 612f48a21477a8447b81076490854b01 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Documentation.meta b/Packages/com.bywaystudios.meowmentdebugtool/Documentation.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Documentation.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Documentation.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Documentation/MeowmentDebugTool.md b/Packages/com.bywaystudios.meowmentdebugtool/Documentation/MeowmentDebugTool.md similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Documentation/MeowmentDebugTool.md rename to Packages/com.bywaystudios.meowmentdebugtool/Documentation/MeowmentDebugTool.md diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Documentation/MeowmentDebugTool.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/Documentation/MeowmentDebugTool.md.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Documentation/MeowmentDebugTool.md.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Documentation/MeowmentDebugTool.md.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Documentation/Usage.md b/Packages/com.bywaystudios.meowmentdebugtool/Documentation/Usage.md new file mode 100644 index 0000000..c988289 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Documentation/Usage.md @@ -0,0 +1,196 @@ +# MeowmentDebugTool 使用指南 + +## 快速开始 + +### 1. 初始化调试工具(自动创建UI) + +**只需一行代码,自动创建完整的调试UI:** + +```csharp +using UnityEngine; +using MeowmentDebugTool; + +public class GameStarter : MonoBehaviour +{ + void Start() + { + // 一行代码初始化,自动创建UI + UniversalDebugTool.Init(); + } +} +``` + +**特点:** +- ✅ 无需手动创建预制件 +- ✅ 无需拖拽引用 +- ✅ 自动生成完整UI +- ✅ 开箱即用 + +### 2. 使用快捷键或API控制 + +```csharp +// 显示调试工具 +UniversalDebugTool.Show(); + +// 隐藏调试工具 +UniversalDebugTool.Hide(); + +// 切换显示/隐藏 +UniversalDebugTool.Toggle(); +``` + +## 如何在主项目中使用自定义调试按钮 + +为了确保包可以自由装卸而不影响主工程的运行,请使用条件编译符号包裹调试代码。 + +### 基本用法 + +```csharp +using UnityEngine; + +#if MEOWMENT_DEBUG_TOOL +using MeowmentDebugTool; +#endif + +public class GameManager : MonoBehaviour +{ + // ✅ 正确的用法 - 使用条件编译 + #if MEOWMENT_DEBUG_TOOL + [DebugButton("重置游戏数据")] + public static void ResetGameData() + { + Debug.Log("游戏数据已重置"); + PlayerPrefs.DeleteAll(); + } + #endif + + // ❌ 错误的用法 - 不使用条件编译 + // 当包被卸载时,这会导致编译错误 + // [DebugButton("重置游戏数据")] + // public static void ResetGameData() + // { + // Debug.Log("游戏数据已重置"); + // PlayerPrefs.DeleteAll(); + // } +} +``` + +### 高级示例 + +#### 1. 带颜色的按钮 + +```csharp +#if MEOWMENT_DEBUG_TOOL +[DebugButton("危险操作", 1f, 0f, 0f)] // 红色按钮 +public static void DangerousOperation() +{ + Debug.LogWarning("执行危险操作!"); +} +#endif +``` + +#### 2. 多个调试按钮 + +```csharp +public class DebugCommands +{ + #if MEOWMENT_DEBUG_TOOL + [DebugButton("添加金币 +100")] + public static void AddGold() + { + // 你的逻辑 + Debug.Log("添加100金币"); + } + + [DebugButton("添加经验 +500")] + public static void AddExp() + { + // 你的逻辑 + Debug.Log("添加500经验"); + } + + [DebugButton("解锁所有关卡", 0f, 1f, 0f)] // 绿色按钮 + public static void UnlockAllLevels() + { + // 你的逻辑 + Debug.Log("所有关卡已解锁"); + } + + [DebugButton("清空背包", 1f, 0.5f, 0f)] // 橙色按钮 + public static void ClearInventory() + { + // 你的逻辑 + Debug.Log("背包已清空"); + } + #endif +} +``` + +#### 3. 调用包内API + +```csharp +public class GameUI : MonoBehaviour +{ + private void Update() + { + // 按下 F12 打开/关闭调试工具 + if (Input.GetKeyDown(KeyCode.F12)) + { + #if MEOWMENT_DEBUG_TOOL + UniversalDebugTool.Toggle(); + #endif + } + } + + public void OnSettingsButtonClick() + { + // 显示输入对话框 + #if MEOWMENT_DEBUG_TOOL + UniversalDebugTool.ShowInputDialog( + "输入玩家名称", + (name) => { + Debug.Log($"玩家名称:{name}"); + }, + "默认名称" + ); + #endif + } +} +``` + +### 工作原理 + +1. **包安装时**:Unity 会自动定义 `MEOWMENT_DEBUG_TOOL` 宏 +2. **包卸载时**:`MEOWMENT_DEBUG_TOOL` 宏会被自动移除 +3. **条件编译**:`#if MEOWMENT_DEBUG_TOOL` 块内的代码在包卸载后会被编译器忽略 + +### 最佳实践 + +✅ **推荐做法**: +- 所有使用 `DebugButtonAttribute` 的地方都用 `#if MEOWMENT_DEBUG_TOOL` 包裹 +- 所有调用 `UniversalDebugTool` API 的地方都用条件编译包裹 +- 将所有调试方法集中在一个或几个专门的类中 + +❌ **不推荐做法**: +- 直接使用特性而不加条件编译 +- 在核心业务逻辑中混入调试代码 +- 依赖调试工具的功能来实现正式功能 + +### 常见问题 + +**Q: 为什么要使用条件编译?** +A: 当你卸载这个包时,`DebugButtonAttribute` 类就不存在了,会导致编译错误。使用条件编译可以让代码在包不存在时被编译器忽略。 + +**Q: 忘记加条件编译怎么办?** +A: 如果卸载包后出现编译错误,只需在报错的代码前后加上 `#if MEOWMENT_DEBUG_TOOL` 和 `#endif` 即可。 + +**Q: 可以在正式发布版本中使用吗?** +A: 可以!条件编译的代码不会影响性能。但建议在正式版本中完全移除或禁用调试工具包。 + +**Q: 如何完全禁用调试工具?** +A: 在 Player Settings → Scripting Define Symbols 中移除 `MEOWMENT_DEBUG_TOOL`,或直接卸载这个包。 + +### 参考 + +- [Unity 条件编译文档](https://docs.unity3d.com/Manual/PlatformDependentCompilation.html) +- [Package Manager 版本定义](https://docs.unity3d.com/Manual/ScriptCompilationAssemblyDefinitionFiles.html#define-symbols) diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Documentation/Usage.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/Documentation/Usage.md.meta new file mode 100644 index 0000000..03fc9c5 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Documentation/Usage.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ab342e44111b45e409658513642a8ea9 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor.meta b/Packages/com.bywaystudios.meowmentdebugtool/Editor.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Editor.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/CreateTabButtonPrefab.cs b/Packages/com.bywaystudios.meowmentdebugtool/Editor/CreateTabButtonPrefab.cs similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/CreateTabButtonPrefab.cs rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/CreateTabButtonPrefab.cs diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/CreateTabButtonPrefab.cs.meta b/Packages/com.bywaystudios.meowmentdebugtool/Editor/CreateTabButtonPrefab.cs.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/CreateTabButtonPrefab.cs.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/CreateTabButtonPrefab.cs.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolDiagnostic.cs b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolDiagnostic.cs similarity index 94% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolDiagnostic.cs rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolDiagnostic.cs index 5267c9d..f020ec7 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolDiagnostic.cs +++ b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolDiagnostic.cs @@ -1,12 +1,15 @@ using UnityEngine; using UnityEditor; +using MeowmentDebugTool; -/// -/// 诊断UniversalDebugTool的引用问题 -/// -public class DebugToolDiagnostic : EditorWindow +namespace MeowmentDebugTool.Editor { - [MenuItem("Tools/Debug Tool/诊断引用问题")] + /// + /// 诊断UniversalDebugTool的引用问题 + /// + public class DebugToolDiagnostic : EditorWindow + { + [MenuItem("Tools/Debug Tool/诊断引用问题")] public static void ShowWindow() { var window = GetWindow("调试工具诊断"); @@ -124,4 +127,5 @@ public class DebugToolDiagnostic : EditorWindow } } } + } } diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolDiagnostic.cs.meta b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolDiagnostic.cs.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolDiagnostic.cs.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolDiagnostic.cs.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolPrefabGenerator.cs b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolPrefabGenerator.cs similarity index 99% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolPrefabGenerator.cs rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolPrefabGenerator.cs index 3d4585c..1318741 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolPrefabGenerator.cs +++ b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolPrefabGenerator.cs @@ -2,14 +2,17 @@ using UnityEngine; using UnityEditor; using UnityEngine.UI; using TMPro; +using MeowmentDebugTool; -/// -/// 通用调试工具预制件生成器 -/// 用于创建UniversalDebugTool所需的完整UI预制件 -/// -public class DebugToolPrefabGenerator : EditorWindow +namespace MeowmentDebugTool.Editor { - private string prefabSavePath = "Assets/UniversalDebugTool.prefab"; + /// + /// 通用调试工具预制件生成器 + /// 用于创建UniversalDebugTool所需的完整UI预制件 + /// + public class DebugToolPrefabGenerator : EditorWindow + { + private string prefabSavePath = "Assets/UniversalDebugTool.prefab"; [MenuItem("Tools/Debug Tool/生成调试工具预制件")] public static void ShowWindow() @@ -972,4 +975,5 @@ public class DebugToolPrefabGenerator : EditorWindow so.ApplyModifiedProperties(); } + } } diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolPrefabGenerator.cs.meta b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolPrefabGenerator.cs.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/DebugToolPrefabGenerator.cs.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/DebugToolPrefabGenerator.cs.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs new file mode 100644 index 0000000..e9926d8 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs @@ -0,0 +1,52 @@ +using UnityEditor; +using UnityEngine; + +namespace MeowmentDebugTool.Editor +{ + /// + /// 自动添加 MEOWMENT_DEBUG_TOOL 宏定义 + /// + [InitializeOnLoad] + public static class DefineSymbolsManager + { + private const string DEFINE_SYMBOL = "MEOWMENT_DEBUG_TOOL"; + + static DefineSymbolsManager() + { + AddDefineSymbol(); + } + + private static void AddDefineSymbol() + { + var target = EditorUserBuildSettings.selectedBuildTargetGroup; + + // 获取当前已定义的符号 + string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(target); + var defines = definesString.Split(';'); + + // 检查是否已存在 + bool exists = false; + foreach (var define in defines) + { + if (define.Trim() == DEFINE_SYMBOL) + { + exists = true; + break; + } + } + + // 如果不存在则添加 + if (!exists) + { + if (!string.IsNullOrEmpty(definesString)) + { + definesString += ";"; + } + definesString += DEFINE_SYMBOL; + + PlayerSettings.SetScriptingDefineSymbolsForGroup(target, definesString); + Debug.Log($"[MeowmentDebugTool] 已添加宏定义: {DEFINE_SYMBOL}"); + } + } + } +} diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs.meta b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs.meta new file mode 100644 index 0000000..e7bd524 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5698ea2959bec274ea3e28b53f9ba8e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/Hontbei.Meowmentdebugtool.Editor.asmdef b/Packages/com.bywaystudios.meowmentdebugtool/Editor/com.bywaystudios.meowmentdebugtool.Editor.asmdef similarity index 78% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/Hontbei.Meowmentdebugtool.Editor.asmdef rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/com.bywaystudios.meowmentdebugtool.Editor.asmdef index 6dcb863..5f43d82 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Editor/Hontbei.Meowmentdebugtool.Editor.asmdef +++ b/Packages/com.bywaystudios.meowmentdebugtool/Editor/com.bywaystudios.meowmentdebugtool.Editor.asmdef @@ -1,8 +1,8 @@ { - "name": "Hontbei.Meowmentdebugtool.Editor", + "name": "com.bywaystudios.meowmentdebugtool.Editor", "rootNamespace": "", "references": [ - "Hontbei.Meowmentdebugtool", + "com.bywaystudios.meowmentdebugtool", "Unity.TextMeshPro" ], "includePlatforms": [ diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Runtime/Hontbei.Meowmentdebugtool.asmdef.meta b/Packages/com.bywaystudios.meowmentdebugtool/Editor/com.bywaystudios.meowmentdebugtool.Editor.asmdef.meta similarity index 76% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Runtime/Hontbei.Meowmentdebugtool.asmdef.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Editor/com.bywaystudios.meowmentdebugtool.Editor.asmdef.meta index 04cee40..39eb6dd 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Runtime/Hontbei.Meowmentdebugtool.asmdef.meta +++ b/Packages/com.bywaystudios.meowmentdebugtool/Editor/com.bywaystudios.meowmentdebugtool.Editor.asmdef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ee28ff85037a9844f95ee9595c069fa4 +guid: a7ea52de8e3323042b5161a7449156b4 AssemblyDefinitionImporter: externalObjects: {} userData: diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/README.md b/Packages/com.bywaystudios.meowmentdebugtool/README.md similarity index 62% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/README.md rename to Packages/com.bywaystudios.meowmentdebugtool/README.md index 778cdc5..571fd28 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/README.md +++ b/Packages/com.bywaystudios.meowmentdebugtool/README.md @@ -51,32 +51,66 @@ ## 快速开始 -### 1. 在场景中生成调试工具预制体 +### 1. 在代码中初始化调试工具 -在 Unity 菜单中执行: +调试工具现在支持**运行时自动生成UI**,无需手动创建预制体。只需在代码中调用: -> Tools → Debug Tool → 生成调试工具预制件 +```csharp +using UnityEngine; +using MeowmentDebugTool; +using TMPro; -在弹窗中选择保存路径(默认:`Assets/UniversalDebugTool.prefab`),点击“生成预制件”。 +public class GameInitializer : MonoBehaviour +{ + public TMP_FontAsset customFont; // 可选:自定义字体 + + void Start() + { + // 初始化调试工具(自动创建UI) + UniversalDebugTool.Init(); + + // 可选:设置自定义SDF字体 + if (customFont != null) + { + UniversalDebugTool.SetSDFFont(customFont); + } + } +} +``` -生成后的预制体包含: +**初始化说明:** -- 一个独立的 `Canvas`(UI 根节点,排序顺序很高,保证在最上层渲染)。 -- `UniversalDebugTool` 主组件和其所需的 UI 层级。 -- 主调试窗口(含标签页、参数页、自定义按钮页、工具栏页、设置页)。 -- 可拖拽的调试悬浮按钮。 +- `UniversalDebugTool.Init()` 会自动创建完整的UI系统,包括: + - 独立的 Canvas(排序顺序 30000,保证在最上层渲染) + - 主调试窗口(含标签页、参数页、自定义按钮页、工具栏页、设置页) + - 可拖拽的调试悬浮按钮 + - EventSystem(如果场景中没有) +- `UniversalDebugTool.SetSDFFont()` 可以为所有UI文本设置自定义字体(可选) -### 2. 把预制体放入场景 +### 2. 运行时使用 -1. 在 Project 窗口中找到生成的 `UniversalDebugTool` 预制体。 -2. 将其拖入需要调试的场景(建议放到常驻/启动场景里)。 -3. 进入 Play 模式即可看到调试窗口。 +进入 Play 模式后: -默认行为: +- 默认显示主调试窗口在左上角 +- 点击左上角的 **X** 按钮,会隐藏主窗口并显示悬浮按钮 +- 拖动悬浮按钮改变位置(自动吸附边缘) +- 点击悬浮按钮可重新打开主窗口(拖动不会误触) -- 进入游戏即显示主调试窗口,并隐藏悬浮按钮。 -- 点击顶部左侧关闭按钮,会隐藏主窗口并显示悬浮按钮。 -- 拖动悬浮按钮改变位置;点击一次可重新打开主窗口。 +### 3. 条件编译(推荐) + +为了确保在移除包后不影响主工程,建议使用条件编译: + +```csharp +void Start() +{ + #if MEOWMENT_DEBUG_TOOL + UniversalDebugTool.Init(); + UniversalDebugTool.SetSDFFont(customFont); + #endif +} +``` + +`MEOWMENT_DEBUG_TOOL` 宏会在包安装时自动定义,卸载时自动移除。 --- @@ -179,14 +213,25 @@ public static class DemoInputDebug 以下方法均定义在 `UniversalDebugTool` 中: +**初始化和配置:** +- `static void Init()`:初始化调试工具,自动创建完整的UI系统(包括Canvas、主窗口、悬浮按钮、EventSystem等)。 +- `static void SetSDFFont(TMP_FontAsset fontAsset)`:为所有UI文本设置自定义SDF字体,包括预制件模板和后续创建的按钮。 + +**显示控制:** - `static bool InstanceExists`:当前场景中是否存在实例。 -- `static UniversalDebugTool Instance`:单例实例(通过 `FindObjectOfType` 查找)。 +- `static UniversalDebugTool Instance`:单例实例。 - `static void Show()`:显示调试工具 GameObject。 - `static void Hide()`:隐藏调试工具 GameObject。 -- `static void Toggle()`:在“窗口显示”和“窗口关闭 + 显示悬浮按钮”之间切换。 +- `static void Toggle()`:在"窗口显示"和"窗口关闭 + 显示悬浮按钮"之间切换。 + +**自定义按钮:** - `void ReloadCustomButtons()`:重新扫描并生成自定义按钮。 + +**输入对话框:** - `static void ShowInputDialog(string title, Action onConfirmAction, string initialValue = "", TMP_InputField.ContentType contentType = TMP_InputField.ContentType.Standard)`:显示输入对话框。 - `static void CloseInputDialog()`:关闭输入对话框并清理回调。 + +**信息查看:** - `void CopyDeviceInfoToClipboard()` / `void CopySystemInfoToClipboard()`:复制对应信息到系统剪贴板。 你也可以在自己项目的 UI / 快捷键逻辑中调用这些方法,例如: @@ -206,11 +251,25 @@ void Update() ## 注意事项 -- 依赖: - - Unity 新 UI(`UnityEngine.UI`)。 - - TextMesh Pro(`TMPro`)。 -- 默认 UI 参考分辨率为 1080×2340,建议以手机竖屏调试为主。可在“设置”页中修改窗口大小以适配不同设备。 -- 工具栏中的“时间调整”逻辑仅是示例,需要你在 `AdjustGameTime` 中实现自己项目的时间修改逻辑。 -- 悬浮按钮依赖 `DraggableFloatingButton` 组件,请不要从生成的预制体中移除此组件,否则会失去拖拽/吸附功能。 +**依赖:** +- Unity 新 UI(`UnityEngine.UI`) +- TextMesh Pro(`TMPro`) +- 包会自动创建 EventSystem(如果场景中没有) -如需进一步定制(增删标签页、调整布局、修改颜色风格等),推荐直接在生成的 `UniversalDebugTool` 预制体上修改 UI 结构和 `UniversalDebugTool` 组件的序列化字段。 +**使用建议:** +- 默认 UI 参考分辨率为 1080×2340,适合手机竖屏调试。可在"设置"页中修改窗口大小以适配不同设备。 +- 主窗口锚点在左上角,不受分辨率变化影响。 +- 悬浮按钮可在全屏范围内拖动,会自动吸附到边缘。 +- 工具栏中的"时间调整"逻辑仅是示例,需要在 `AdjustGameTime` 中实现实际的时间修改逻辑。 + +**字体设置:** +- 所有 UI 文本默认使用 TMP 的默认字体。 +- 调用 `SetSDFFont()` 可以为所有文本(包括后续创建的自定义按钮)设置自定义字体。 + +**条件编译:** +- 建议使用 `#if MEOWMENT_DEBUG_TOOL` 包裹调试工具相关代码。 +- 包安装时会自动定义 `MEOWMENT_DEBUG_TOOL` 宏,卸载时自动移除。 +- 这样可以确保移除包后不影响主工程编译。 + +**进一步定制:** +如需修改 UI 布局、颜色、标签页等,可以直接修改 `RuntimeUIGenerator.cs` 中的 UI 生成逻辑。 diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/README.md.meta b/Packages/com.bywaystudios.meowmentdebugtool/README.md.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/README.md.meta rename to Packages/com.bywaystudios.meowmentdebugtool/README.md.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Runtime.meta b/Packages/com.bywaystudios.meowmentdebugtool/Runtime.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Runtime.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Runtime.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/DraggableFloatingButton.cs b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/DraggableFloatingButton.cs new file mode 100644 index 0000000..b9d6789 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/DraggableFloatingButton.cs @@ -0,0 +1,235 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace MeowmentDebugTool +{ + /// + /// 可拖动的悬浮按钮 + /// 点击打开调试工具,可以在屏幕上自由拖动 + /// + public class DraggableFloatingButton : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler + { + [Header("设置")] + [Tooltip("是否限制在屏幕范围内")] + public bool clampToScreen = true; + + [Tooltip("与屏幕边缘的最小距离")] + public float edgePadding = 20f; + + [Header("自动吸附")] + [Tooltip("是否自动吸附到屏幕边缘")] + public bool snapToEdge = true; + + [Tooltip("吸附动画时间")] + public float snapDuration = 0.3f; + + private RectTransform rectTransform; + private Canvas canvas; + private Vector2 dragOffset; + private bool isDragging = false; + private Vector2 targetPosition; + private bool isSnapping = false; + + // 用于区分点击和拖动 + private Vector2 dragStartPosition; + private const float clickThreshold = 5f; // 小于这个距离算点击 + private bool wasDragging = false; // 标记刚才是否拖动过 + + private void Awake() + { + rectTransform = GetComponent(); + canvas = GetComponentInParent(); + + if (canvas == null) + { + Debug.LogError("DraggableFloatingButton 必须在Canvas下!"); + } + + targetPosition = rectTransform.anchoredPosition; + } + + private void Update() + { + // 平滑移动到目标位置(吸附动画) + if (isSnapping && !isDragging) + { + rectTransform.anchoredPosition = Vector2.Lerp( + rectTransform.anchoredPosition, + targetPosition, + Time.deltaTime / snapDuration + ); + + if (Vector2.Distance(rectTransform.anchoredPosition, targetPosition) < 0.5f) + { + rectTransform.anchoredPosition = targetPosition; + isSnapping = false; + } + } + } + + public void OnBeginDrag(PointerEventData eventData) + { + isDragging = true; + isSnapping = false; + + // 记录起始位置,用于判断是点击还是拖动 + dragStartPosition = eventData.position; + + // 计算拖动偏移 + RectTransformUtility.ScreenPointToLocalPointInRectangle( + canvas.transform as RectTransform, + eventData.position, + eventData.pressEventCamera, + out Vector2 localPoint + ); + + dragOffset = rectTransform.anchoredPosition - localPoint; + } + + public void OnDrag(PointerEventData eventData) + { + if (!isDragging) return; + + // 转换屏幕坐标到Canvas局部坐标 + RectTransformUtility.ScreenPointToLocalPointInRectangle( + canvas.transform as RectTransform, + eventData.position, + eventData.pressEventCamera, + out Vector2 localPoint + ); + + // 应用拖动偏移 + Vector2 newPosition = localPoint + dragOffset; + + // 限制在屏幕范围内 + if (clampToScreen) + { + newPosition = ClampToScreen(newPosition); + } + + rectTransform.anchoredPosition = newPosition; + } + + public void OnEndDrag(PointerEventData eventData) + { + isDragging = false; + + // 计算拖动距离 + float dragDistance = Vector2.Distance(dragStartPosition, eventData.position); + + // 如果拖动距离超过阈值,说明是拖动而不是点击 + if (dragDistance > clickThreshold) + { + wasDragging = true; + // 在下一帧重置标记 + StartCoroutine(ResetDragFlag()); + } + + // 自动吸附到最近的边缘 + if (snapToEdge) + { + SnapToNearestEdge(); + } + } + + private System.Collections.IEnumerator ResetDragFlag() + { + yield return null; // 等待一帧 + wasDragging = false; + } + + /// + /// 检查是否刚拖动过(用于Button点击事件判断) + /// + public bool GetWasDragging() + { + return wasDragging; + } + + private Vector2 ClampToScreen(Vector2 position) + { + RectTransform canvasRect = canvas.transform as RectTransform; + Vector2 canvasSize = canvasRect.sizeDelta; + Vector2 buttonSize = rectTransform.sizeDelta; + + // 计算可移动范围 + float minX = -canvasSize.x / 2 + buttonSize.x / 2 + edgePadding; + float maxX = canvasSize.x / 2 - buttonSize.x / 2 - edgePadding; + float minY = -canvasSize.y / 2 + buttonSize.y / 2 + edgePadding; + float maxY = canvasSize.y / 2 - buttonSize.y / 2 - edgePadding; + + position.x = Mathf.Clamp(position.x, minX, maxX); + position.y = Mathf.Clamp(position.y, minY, maxY); + + return position; + } + + private void SnapToNearestEdge() + { + RectTransform canvasRect = canvas.transform as RectTransform; + Vector2 canvasSize = canvasRect.sizeDelta; + Vector2 currentPos = rectTransform.anchoredPosition; + + // 计算到各个边缘的距离 + float distToLeft = Mathf.Abs(currentPos.x + canvasSize.x / 2); + float distToRight = Mathf.Abs(currentPos.x - canvasSize.x / 2); + float distToTop = Mathf.Abs(currentPos.y - canvasSize.y / 2); + float distToBottom = Mathf.Abs(currentPos.y + canvasSize.y / 2); + + // 找到最近的边 + float minDist = Mathf.Min(distToLeft, distToRight, distToTop, distToBottom); + + Vector2 snapPosition = currentPos; + Vector2 buttonSize = rectTransform.sizeDelta; + + if (minDist == distToLeft) + { + // 吸附到左边 + snapPosition.x = -canvasSize.x / 2 + buttonSize.x / 2 + edgePadding; + } + else if (minDist == distToRight) + { + // 吸附到右边 + snapPosition.x = canvasSize.x / 2 - buttonSize.x / 2 - edgePadding; + } + else if (minDist == distToTop) + { + // 吸附到顶部 + snapPosition.y = canvasSize.y / 2 - buttonSize.y / 2 - edgePadding; + } + else if (minDist == distToBottom) + { + // 吸附到底部 + snapPosition.y = -canvasSize.y / 2 + buttonSize.y / 2 + edgePadding; + } + + // 确保在屏幕范围内 + snapPosition = ClampToScreen(snapPosition); + + targetPosition = snapPosition; + isSnapping = true; + } + + /// + /// 设置悬浮按钮位置 + /// + public void SetPosition(Vector2 position) + { + if (clampToScreen) + { + position = ClampToScreen(position); + } + rectTransform.anchoredPosition = position; + targetPosition = position; + } + + /// + /// 获取当前位置 + /// + public Vector2 GetPosition() + { + return rectTransform.anchoredPosition; + } + } +} diff --git a/Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Runtime/DraggableFloatingButton.cs.meta b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/DraggableFloatingButton.cs.meta similarity index 100% rename from Packages/com.bywaystudios.meowmentdebugtool@0.1.4/Runtime/DraggableFloatingButton.cs.meta rename to Packages/com.bywaystudios.meowmentdebugtool/Runtime/DraggableFloatingButton.cs.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/RuntimeUIGenerator.cs b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/RuntimeUIGenerator.cs new file mode 100644 index 0000000..f00577c --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/RuntimeUIGenerator.cs @@ -0,0 +1,812 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.EventSystems; +using TMPro; + +namespace MeowmentDebugTool +{ + /// + /// 运行时UI生成器 - 自动创建调试工具的完整UI + /// + public static class RuntimeUIGenerator + { + private const int CANVAS_WIDTH = 1080; + private const int CANVAS_HEIGHT = 2340; + + /// + /// 创建完整的调试工具UI + /// + public static UniversalDebugTool CreateDebugToolUI() + { + // 检查并创建EventSystem + EnsureEventSystem(); + + // 创建根Canvas + GameObject canvasObj = new GameObject("UniversalDebugTool_Canvas"); + Canvas canvas = canvasObj.AddComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + canvas.sortingOrder = 30000; + canvas.overrideSorting = true; + + CanvasScaler scaler = canvasObj.AddComponent(); + scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; + scaler.referenceResolution = new Vector2(CANVAS_WIDTH, CANVAS_HEIGHT); + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + scaler.matchWidthOrHeight = 0.5f; + + canvasObj.AddComponent(); + + // 创建 UniversalDebugTool 组件 + UniversalDebugTool tool = canvasObj.AddComponent(); + + // 创建主窗口 + GameObject mainWindow = CreateMainWindow(canvasObj.transform); + + // 创建悬浮按钮 + GameObject floatingButton = CreateFloatingButton(canvasObj.transform); + + // 创建标签页 + GameObject tabContainer = mainWindow.transform.Find("TabButtonContainer").gameObject; + GameObject contentContainer = mainWindow.transform.Find("ContentContainer").gameObject; + + GameObject parametersPage = CreateParametersPage(contentContainer.transform); + GameObject customButtonsPage = CreateCustomButtonsPage(contentContainer.transform); + GameObject toolbarPage = CreateToolbarPage(contentContainer.transform); + GameObject settingsPage = CreateSettingsPage(contentContainer.transform); + + // 创建输入对话框 + GameObject inputDialog = CreateInputDialog(canvasObj.transform); + + // 设置引用 + SetupReferences(tool, canvas, mainWindow, floatingButton, + parametersPage, customButtonsPage, toolbarPage, settingsPage, inputDialog); + + return tool; + } + + private static GameObject CreateMainWindow(Transform parent) + { + GameObject mainWindow = new GameObject("MainWindow"); + mainWindow.transform.SetParent(parent, false); + RectTransform rect = mainWindow.AddComponent(); + rect.anchorMin = new Vector2(0, 1); + rect.anchorMax = new Vector2(0, 1); + rect.pivot = new Vector2(0, 1); + rect.sizeDelta = new Vector2(CANVAS_WIDTH, CANVAS_HEIGHT); + rect.anchoredPosition = Vector2.zero; + + // 背景 + Image bg = mainWindow.AddComponent(); + bg.color = new Color(0.1f, 0.1f, 0.1f, 0.95f); + + // 关闭按钮(左上角) + GameObject closeBtn = CreateButton("CloseButton", mainWindow.transform, "X"); + RectTransform closeBtnRect = closeBtn.GetComponent(); + closeBtnRect.anchorMin = new Vector2(0, 1); + closeBtnRect.anchorMax = new Vector2(0, 1); + closeBtnRect.pivot = new Vector2(0, 1); + closeBtnRect.sizeDelta = new Vector2(100, 100); + closeBtnRect.anchoredPosition = new Vector2(10, -10); + closeBtn.GetComponent().color = new Color(0.8f, 0.2f, 0.2f, 1f); + + // 标签按钮容器(从关闭按钮右侧开始) + GameObject tabContainer = new GameObject("TabButtonContainer"); + tabContainer.transform.SetParent(mainWindow.transform, false); + RectTransform tabRect = tabContainer.AddComponent(); + tabRect.anchorMin = new Vector2(0, 1); + tabRect.anchorMax = new Vector2(1, 1); + tabRect.pivot = new Vector2(0, 1); + tabRect.sizeDelta = new Vector2(-120, 100); + tabRect.anchoredPosition = new Vector2(120, 0); + + HorizontalLayoutGroup tabLayout = tabContainer.AddComponent(); + tabLayout.childControlWidth = true; + tabLayout.childControlHeight = true; + tabLayout.childForceExpandWidth = true; + tabLayout.childForceExpandHeight = true; + tabLayout.spacing = 10; + tabLayout.padding = new RectOffset(10, 20, 10, 10); + + // 内容容器 + GameObject contentContainer = new GameObject("ContentContainer"); + contentContainer.transform.SetParent(mainWindow.transform, false); + RectTransform contentRect = contentContainer.AddComponent(); + contentRect.anchorMin = new Vector2(0, 0); + contentRect.anchorMax = new Vector2(1, 1); + contentRect.pivot = new Vector2(0.5f, 0.5f); + contentRect.offsetMin = new Vector2(20, 20); + contentRect.offsetMax = new Vector2(-20, -120); + + return mainWindow; + } + + private static GameObject CreateFloatingButton(Transform parent) + { + GameObject floatBtn = new GameObject("FloatingButton"); + floatBtn.transform.SetParent(parent, false); + RectTransform rect = floatBtn.AddComponent(); + rect.anchorMin = new Vector2(0.5f, 0.5f); + rect.anchorMax = new Vector2(0.5f, 0.5f); + rect.pivot = new Vector2(0.5f, 0.5f); + rect.sizeDelta = new Vector2(120, 120); + rect.anchoredPosition = new Vector2(400, 0); + + Image img = floatBtn.AddComponent(); + img.color = new Color(0.2f, 0.6f, 1f, 0.8f); + + Button btn = floatBtn.AddComponent