From bdb24b05d151ab9db38b0dc3bd6e32a466505ae6 Mon Sep 17 00:00:00 2001 From: zhang hongbo Date: Wed, 24 Dec 2025 19:51:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0meowmentdebugtool=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=BC=80=E5=85=B3=EF=BC=8C=E6=95=B0=E5=80=BC=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E5=8E=BB=E6=8E=89=E5=B7=A5=E5=85=B7=E6=A0=8F?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CHANGELOG.md | 67 +++ .../Editor/DefineSymbolsManager.cs | 5 +- .../README.md | 550 ++---------------- .../Runtime/CustomButtonsModule.cs | 2 +- .../Runtime/CustomCheckBoxesModule.cs | 187 ++++++ .../Runtime/CustomCheckBoxesModule.cs.meta | 11 + .../Runtime/CustomValuesModule.cs | 274 +++++++++ .../Runtime/CustomValuesModule.cs.meta | 11 + .../Runtime/RuntimeUIGenerator.cs | 348 ++++++++++- .../Runtime/UniversalDebugTool.cs | 248 +++++++- .../SampleDebugFunctions.cs | 57 +- .../package.json | 2 +- 12 files changed, 1220 insertions(+), 542 deletions(-) create mode 100644 Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs create mode 100644 Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs.meta create mode 100644 Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomValuesModule.cs create mode 100644 Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomValuesModule.cs.meta diff --git a/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md index c92480c..ed8d539 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md +++ b/Packages/com.bywaystudios.meowmentdebugtool/CHANGELOG.md @@ -5,6 +5,73 @@ 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), 版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。 + + +## [0.3.7] - 2025-12-24 + +### Added +- **数值特性增强** + - `[DebugValue]` 特性新增 `defaultValue` 参数,用于设置初始默认值 + - 参数顺序:`displayName`, `minValue`, `maxValue`, `defaultValue`, `r`, `g`, `b` + - 若未指定 `defaultValue`(或传入-1),则自动使用 `minValue` 作为默认值 + +### Changed +- **模块命名优化** + - "自定义数值"页面重命名为"数值",简化用户界面 + - 统一更新相关日志消息和UI文本 + +### Improved +- **用户体验提升** + - 数值页面的确认按钮点击后自动关闭主窗口(与自定义按钮保持一致) + - 优化操作流程,调整数值后自动返回游戏界面 + + + +## [0.3.6] - 2025-12-24 + +### Added +- **自定义复选框页面 (CheckBoxes)** + - 新增 `[DebugCheckBox]` 特性,用于创建开关功能 + - 支持自定义显示名称和复选框颜色(RGB参数) + - 自动通过反射扫描并加载所有带该特性的静态方法 + - 方法必须接收一个 `bool` 参数作为开关状态 + - 支持状态保存,切换页面后保持开关状态 + - 使用 ScrollView 支持大量复选框滚动显示 + - 单行布局,每个复选框占据一行 + +- **自定义数值页面 (Values)** + - 新增 `[DebugValue]` 特性,用于创建整数值调整功能 + - 支持自定义显示名称、最小值、最大值、颜色(RGB参数) + - 复合UI组件:标题 + 滑块 + 输入框 + 确认按钮 + - 滑块和输入框双向绑定,实时同步数值 + - 数值自动限制在指定范围内(最小值-最大值) + - 方法必须接收一个 `int` 参数 + - 支持状态保存,切换页面后保持当前值 + - 使用 ScrollView 支持大量数值项滚动显示 + - 两行布局:标题行 + 控制行(滑块55% + 输入框17% + 按钮26%) + +### Changed +- 移除工具栏页面及相关功能(时间调整功能已不再需要) +- 优化UI布局尺寸 + - 复选框项宽度:800px,高度:80px + - 数值调整项宽度:900px,高度:140px + - 改进标题可见性,采用两行布局设计 + +### Fixed +- 修复运行时UI生成时的 NullReferenceException 问题 +- 修复 TMP_InputField 的 textComponent 必须为子对象的问题 +- 修复非激活父对象下创建UI组件的问题 + + +## [0.3.5] - 2025-12-22 + +- 增加四指隐藏Debugger显示效果 +- 性能优化,update代码优化 + + + + + ## [0.3.0] - 2025-12-22 ### Added diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs index e9926d8..b057711 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs +++ b/Packages/com.bywaystudios.meowmentdebugtool/Editor/DefineSymbolsManager.cs @@ -5,15 +5,16 @@ namespace MeowmentDebugTool.Editor { /// /// 自动添加 MEOWMENT_DEBUG_TOOL 宏定义 + /// 注意:已禁用自动添加功能,如需启用请取消注释 [InitializeOnLoad] 特性 /// - [InitializeOnLoad] + // [InitializeOnLoad] // 已注释,不再自动添加宏定义 public static class DefineSymbolsManager { private const string DEFINE_SYMBOL = "MEOWMENT_DEBUG_TOOL"; static DefineSymbolsManager() { - AddDefineSymbol(); + // AddDefineSymbol(); // 已注释,不再自动添加 } private static void AddDefineSymbol() diff --git a/Packages/com.bywaystudios.meowmentdebugtool/README.md b/Packages/com.bywaystudios.meowmentdebugtool/README.md index 809741e..b33dc59 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/README.md +++ b/Packages/com.bywaystudios.meowmentdebugtool/README.md @@ -1,547 +1,85 @@ -# MeowMent Debug Tool(喵刻调试工具) +# MeowMent Debug Tool -一个强大的 Unity 运行时调试工具,提供多标签页调试面板、控制台日志、可拖拽悬浮按钮、系统信息查看以及自定义调试按钮等功能。 +Unity 运行时调试工具。 -**版本:** 0.3.0 -**适用平台:** 全平台(Windows、Android、iOS等) -**Unity版本:** 2021.3 及以上 ---- -## 📋 目录 +## 目录 -- [功能特性](#功能特性) -- [给策划使用 - 基础功能](#给策划使用---基础功能) -- [给客户端使用 - 初始化配置](#给客户端使用---初始化配置) -- [给后端使用 - 添加自定义按钮](#给后端使用---添加自定义按钮) -- [常见问题](#常见问题) +- [给策划](#给策划) +- [给客户端](#给客户端) +- [给服务端](#给服务端) ---- +## 给策划 -## 🎯 功能特性 +点击屏幕左侧蓝色浮窗打开调试窗口。 -### 核心功能模块 -- **参数查看**:实时查看设备信息、系统信息,支持一键复制 -- **自定义按钮**:通过特性自动生成调试按钮,无需手动添加 -- **工具栏**:时间调整工具、截图隐藏功能 -- **控制台**:实时捕获Unity日志,支持过滤、搜索、查看堆栈 -- **设置**:运行时修改分辨率 +**参数查看** - 查看设备信息、系统信息,可复制 +**自定义按钮** - 执行调试功能(清空数据、添加道具等) +**开关** - 功能开关控制(开启/关闭某些功能) +**数值** - 数值调整(通过滑块和输入框调整整数值) +**控制台** - 查看日志、过滤、堆栈信息 +**设置** - 调整分辨率 -### UI特性 -- 可拖拽悬浮按钮,自动吸附边缘 -- 多标签页设计,清晰分类 -- Canvas层级30000,始终在最上层 -- 支持自定义TextMeshPro字体 +四指点击屏幕是隐藏和现实Debugger工具 ---- +## 给客户端 -## 👥 给策划使用 - 基础功能 - -### 1. 如何打开调试工具 - -游戏运行后,屏幕左侧会显示一个**蓝色圆形浮窗按钮**: - -- **点击浮窗** → 打开调试主窗口 -- **拖动浮窗** → 改变位置(会自动吸附到屏幕边缘) -- **点击左上角X** → 关闭主窗口,回到浮窗状态 - -### 2. 功能页面说明 - -调试窗口包含5个标签页: - -#### 📊 参数查看 -- **设备信息**:设备型号、系统版本、处理器、内存等 -- **系统信息**:Unity版本、图形API、显卡信息等 -- **复制按钮**:点击可复制信息到剪贴板,方便粘贴到bug报告 - -#### 🎮 自定义按钮 -- 显示后端程序员添加的调试功能按钮 -- 点击按钮即可执行对应功能(如清理存档、添加道具等) -- 不同按钮有不同颜色,方便区分 - -**常见按钮示例:** -- "清空玩家数据" - 重置游戏进度 -- "添加金币" - 增加游戏货币 -- "解锁所有关卡" - 开启所有内容 -- "重置今日任务" - 刷新每日任务 - -#### 🛠️ 工具栏 -- **时间调整**:模拟时间流逝(用于测试时间相关功能) -- **暂时隐藏(5秒)**:截图前点击此按钮,调试工具会隐藏5秒,方便截取干净的游戏画面 - -**使用场景:** -1. 需要截图游戏画面时 -2. 点击"暂时隐藏(5秒)" -3. 调试工具消失,快速截图 -4. 5秒后自动恢复,继续调试 - -#### 📝 控制台 -实时显示游戏日志,帮助定位问题: - -- **Info(白色)**:普通信息日志 -- **Warning(黄色)**:警告信息 -- **Error(红色)**:错误信息 -- **Fatal(深红)**:严重错误/异常 - -**功能按钮:** -- **清空**:清除所有日志 -- **锁定滚动**:勾选后自动滚动到最新日志 -- **过滤器**:点击Info/Warning/Error切换显示对应类型日志 - -**查看详情:** -- 点击任意日志条目 → 下方显示完整堆栈信息 -- 方便向程序员反馈详细错误 - -#### ⚙️ 设置 -- **分辨率调整**:修改游戏窗口大小(仅编辑器/Windows有效) -- **当前分辨率显示**:显示当前屏幕分辨率 - -### 3. 日常测试工作流 - -**测试新功能:** -1. 打开调试工具 -2. 切换到"自定义按钮"页面 -3. 点击相关测试按钮(如"开启活动") -4. 观察游戏效果 -5. 如有问题,切换到"控制台"查看错误 - -**截图报bug:** -1. 复现问题 -2. 点击"工具栏" → "暂时隐藏(5秒)" -3. 截取游戏画面 -4. 切换回"控制台"截取错误日志 -5. 一起提交给程序 - -**收集设备信息:** -1. 切换到"参数查看" -2. 点击"复制设备信息"或"复制系统信息" -3. 粘贴到bug报告中 - ---- - -## 💻 给客户端使用 - 初始化配置 - -### 1. 基础初始化 - -在游戏启动时(通常在启动场景的初始化脚本中)调用: +在游戏启动时初始化: ```csharp -using UnityEngine; using MeowmentDebugTool; using TMPro; -public class GameInitializer : MonoBehaviour -{ - [SerializeField] private TMP_FontAsset customFont; // 拖入自定义字体 - - void Start() - { - // 初始化调试工具 - UniversalDebugTool.Init(); - - // 设置自定义字体(可选) - if (customFont != null) - { - UniversalDebugTool.SetSDFFont(customFont); - } - } -} -``` - -### 2. API说明 - -#### `UniversalDebugTool.Init()` -初始化调试工具,自动创建: -- Canvas(排序顺序30000) -- 主调试窗口 -- 悬浮按钮 -- EventSystem(如果没有) - -**注意:** -- 只需调用一次 -- 工具会自动DontDestroyOnLoad,场景切换不销毁 -- 未调用Init()前不显示任何UI - -#### `UniversalDebugTool.SetSDFFont(TMP_FontAsset fontAsset)` -设置所有UI文本的字体: -- 包括已创建的UI和后续创建的按钮 -- 支持中文、特殊字符 -- 建议使用支持中文的SDF字体 - -**字体推荐:** -- 思源黑体 SDF -- 阿里巴巴普惠体 SDF -- 或项目现有的中文字体 - -### 3. 条件编译(推荐) - -为了确保打包时不包含调试代码: - -```csharp void Start() { #if MEOWMENT_DEBUG_TOOL UniversalDebugTool.Init(); - UniversalDebugTool.SetSDFFont(customFont); + UniversalDebugTool.SetSDFFont(customFont); // 可选,设置中文字体 #endif } ``` -**说明:** -- `MEOWMENT_DEBUG_TOOL` 宏在包安装时自动定义 -- 移除包时自动移除,不影响项目编译 -- 正式包不会包含调试工具代码 +## 给服务端 -### 4. 完整示例 +用 `[DebugButton]` 特性标记静态方法自动生成按钮: ```csharp -using UnityEngine; -using MeowmentDebugTool; -using TMPro; - -public class Test : MonoBehaviour +public static class DebugFunctions { - public TMP_FontAsset fontAsset; - - void Start() - { - #if MEOWMENT_DEBUG_TOOL - // 初始化调试工具 - UniversalDebugTool.Init(); - - // 设置字体 - if (fontAsset != null) - { - UniversalDebugTool.SetSDFFont(fontAsset); - } - #endif - } -} -``` - ---- - -## 🔧 给后端使用 - 添加自定义按钮 - -### 1. 基础用法 - -使用 `[DebugButton]` 特性标记静态方法,调试工具会自动生成按钮: - -```csharp -using UnityEngine; - -public static class PlayerDebugFunctions -{ - [DebugButton("清空玩家数据")] - private static void ClearPlayerData() + [DebugButton("清空数据")] + private static void ClearData() { PlayerPrefs.DeleteAll(); - Debug.Log("玩家数据已清空"); } - [DebugButton("添加1000金币")] + // 设置按钮颜色 (r, g, b) + [DebugButton("添加金币", 0.2f, 0.8f, 0.2f)] private static void AddCoins() { PlayerData.Coins += 1000; - Debug.Log($"当前金币:{PlayerData.Coins}"); + } + + // 复选框开关,方法必须接收bool参数 + [DebugCheckBox("无敌模式", 1f, 0.5f, 0f)] + private static void ToggleGodMode(bool isOn) + { + Player.IsInvincible = isOn; + } + + // 数值调整,方法必须接收int参数 + // 参数:显示名称, 最小值, 最大值, 默认值, r, g, b + [DebugValue("玩家等级", 1, 100, 50, 0f, 0.8f, 1f)] + private static void SetPlayerLevel(int level) + { + Player.Level = level; } } ``` -**运行效果:** -- 在"自定义按钮"页面会出现两个按钮 -- 点击按钮执行对应方法 +## 常见问题 -### 2. 特性参数详解 +**字体显示方块?** 调用 `SetSDFFont()` 设置中文字体 +**按钮不显示?** 检查方法是否为 `static` 且有 `[DebugButton]` 特性 +**如何移除?** 删除 Packages 下的工具包文件夹 -```csharp -[DebugButton(string displayName = "", float r = 0.8f, float g = 0.8f, float b = 0.8f)] -``` - -#### 参数说明: -- **displayName**:按钮显示文字(不填则使用方法名) -- **r, g, b**:按钮背景颜色(RGB值,范围0-1) - -#### 示例:不同颜色按钮 - -```csharp -public static class GameDebugFunctions -{ - // 绿色按钮 - 安全操作 - [DebugButton("保存游戏", 0.2f, 0.6f, 0.2f)] - private static void SaveGame() - { - GameManager.Save(); - } - - // 红色按钮 - 危险操作 - [DebugButton("删除存档", 0.9f, 0.2f, 0.2f)] - private static void DeleteSave() - { - GameManager.DeleteSave(); - } - - // 蓝色按钮 - 功能测试 - [DebugButton("跳到第10关", 0.2f, 0.5f, 0.9f)] - private static void JumpToLevel10() - { - LevelManager.LoadLevel(10); - } - - // 默认颜色(灰色) - [DebugButton("打印游戏状态")] - private static void PrintGameState() - { - Debug.Log($"Level: {GameManager.CurrentLevel}"); - } -} -``` - -### 3. 使用输入对话框 - -需要用户输入参数时,使用 `ShowInputDialog`: - -```csharp -using TMPro; - -public static class AdvancedDebugFunctions -{ - [DebugButton("设置玩家等级")] - private static void SetPlayerLevel() - { - UniversalDebugTool.ShowInputDialog( - "输入等级", - onConfirmAction: text => - { - if (int.TryParse(text, out int level)) - { - PlayerData.Level = level; - Debug.Log($"等级已设置为:{level}"); - } - else - { - Debug.LogWarning("请输入有效数字"); - } - }, - initialValue: "1", - contentType: TMP_InputField.ContentType.IntegerNumber - ); - } - - [DebugButton("设置玩家名称")] - private static void SetPlayerName() - { - UniversalDebugTool.ShowInputDialog( - "输入名称", - onConfirmAction: name => - { - PlayerData.Name = name; - Debug.Log($"名称已设置为:{name}"); - }, - initialValue: PlayerData.Name, - contentType: TMP_InputField.ContentType.Standard - ); - } -} -``` - -### 4. 条件编译(推荐) - -为了确保正式版不包含调试代码: - -```csharp -public static class ItemDebugFunctions -{ - #if MEOWMENT_DEBUG_TOOL - [DebugButton("添加道具")] - private static void AddItem() - { - ItemManager.AddItem(1001, 10); - } - #endif -} -``` - -### 5. 高级技巧 - -#### 技巧1:分类管理 -按功能模块创建不同的类: - -```csharp -// 玩家相关 -public static class PlayerDebug { ... } - -// 关卡相关 -public static class LevelDebug { ... } - -// 道具相关 -public static class ItemDebug { ... } -``` - -#### 技巧2:快速测试流程 - -```csharp -[DebugButton("快速进入战斗")] -private static void QuickEnterBattle() -{ - // 1. 设置测试数据 - PlayerData.Level = 10; - PlayerData.Coins = 9999; - - // 2. 解锁功能 - FeatureManager.UnlockAll(); - - // 3. 跳转场景 - SceneManager.LoadScene("Battle"); -} -``` - -#### 技巧3:开发辅助 - -```csharp -[DebugButton("开启所有调试选项")] -private static void EnableAllDebug() -{ - GameConfig.ShowFPS = true; - GameConfig.GodMode = true; - GameConfig.UnlimitedEnergy = true; - Debug.Log("所有调试选项已开启"); -} -``` - -### 6. 实战示例 - -```csharp -using UnityEngine; -using UnityEngine.SceneManagement; -using TMPro; - -public static class SampleDebugFunctions -{ - #region 玩家数据 - [DebugButton("重置游戏", 0.9f, 0.3f, 0.3f)] - private static void ResetGame() - { - PlayerPrefs.DeleteAll(); - SceneManager.LoadScene(0); - Debug.Log("游戏已重置"); - } - - [DebugButton("满级满资源", 0.2f, 0.8f, 0.2f)] - private static void MaxEverything() - { - PlayerData.Level = 99; - PlayerData.Coins = 999999; - PlayerData.Gems = 99999; - Debug.Log("已设置为满级满资源"); - } - #endregion - - #region 关卡测试 - [DebugButton("跳关", 0.3f, 0.6f, 0.9f)] - private static void JumpToLevel() - { - UniversalDebugTool.ShowInputDialog( - "输入关卡号", - text => - { - if (int.TryParse(text, out int level)) - { - LevelManager.LoadLevel(level); - } - }, - "1", - TMP_InputField.ContentType.IntegerNumber - ); - } - - [DebugButton("解锁所有关卡", 0.2f, 0.8f, 0.8f)] - private static void UnlockAllLevels() - { - for (int i = 0; i < 100; i++) - { - LevelManager.UnlockLevel(i); - } - Debug.Log("已解锁所有关卡"); - } - #endregion - - #region 系统测试 - [DebugButton("清理未使用资源", 0.9f, 0.5f, 0.3f)] - private static void UnloadUnusedAssets() - { - Resources.UnloadUnusedAssets(); - Debug.Log("已清理未使用的资源"); - } - - [DebugButton("触发GC")] - private static void ForceGC() - { - System.GC.Collect(); - Debug.Log("已触发垃圾回收"); - } - #endregion -} -``` - ---- - -## ❓ 常见问题 - -### Q1: 字体显示方块/乱码怎么办? -**A:** 调用 `UniversalDebugTool.SetSDFFont()` 设置支持中文的SDF字体。 - -### Q2: 自定义按钮不显示? -**A:** 检查: -- 方法是否为 `static` -- 是否添加了 `[DebugButton]` 特性 -- 是否在 `#if MEOWMENT_DEBUG_TOOL` 内 - -### Q3: 第二次点击"暂时隐藏"无效? -**A:** 等待上一次隐藏结束,或查看控制台是否有"已经在隐藏状态中"的警告。 - -### Q4: 如何在正式版移除调试工具? -**A:** 删除Packages目录下的工具包文件夹即可,`#if MEOWMENT_DEBUG_TOOL` 包裹的代码会自动失效。 - -### Q5: 控制台日志太多怎么办? -**A:** -- 点击"清空"按钮清除日志 -- 使用过滤器只显示Error/Warning -- 工具默认只保留最新100条日志 - -### Q6: 可以在多个场景使用吗? -**A:** 可以,工具使用DontDestroyOnLoad,场景切换不会销毁。 - ---- - -## 📝 更新日志 - -### [0.3.0] - 2025-12-22 -- ✨ 新增控制台模块,实时显示Unity日志 -- ✨ 新增暂时隐藏功能,方便截图 -- 🔨 重构代码架构,模块化设计 -- 🐛 修复多个UI布局问题 - -### [0.2.2] - 2025-12-19 -- 🔨 默认显示浮窗而非主窗口 -- 🐛 优化初始化逻辑 - -详见 [CHANGELOG.md](CHANGELOG.md) - ---- - -## 📦 依赖 - -- Unity 2021.3+ -- TextMesh Pro (com.unity.textmeshpro) -- Unity UI (com.unity.ugui) - ---- - -## 📧 联系方式 - -如有问题或建议,请联系开发团队。 - ---- - -**祝调试顺利!** 🐱 diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs index f7d3205..dd19081 100644 --- a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs @@ -53,7 +53,7 @@ namespace MeowmentDebugTool public string GetModuleName() { - return "自定义按钮"; + return "按钮"; } #endregion diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs new file mode 100644 index 0000000..7556993 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +namespace MeowmentDebugTool +{ + /// + /// 自定义复选框模块 - 通过反射加载标记为DebugCheckBox的方法 + /// + public class CustomCheckBoxesModule : IDebugModule + { + #region 字段 + private GameObject customCheckBoxesPage; + private RectTransform checkBoxContainer; + private GameObject checkBoxPrefab; + private ScrollRect checkBoxesScrollRect; + + // 保存的SDF字体资源 + private TMP_FontAsset savedFontAsset = null; + + // 保存每个复选框的状态 + private Dictionary checkBoxStates = new Dictionary(); + #endregion + + #region 构造函数 + public CustomCheckBoxesModule(GameObject page, RectTransform container, GameObject prefab, + ScrollRect scrollRect) + { + customCheckBoxesPage = page; + checkBoxContainer = container; + checkBoxPrefab = prefab; + checkBoxesScrollRect = scrollRect; + } + #endregion + + #region IDebugModule 实现 + public void Initialize() + { + Debug.Log("[CustomCheckBoxesModule] 初始化自定义复选框模块..."); + LoadCustomCheckBoxes(); + } + + public GameObject GetPage() + { + return customCheckBoxesPage; + } + + public string GetModuleName() + { + return "开关"; + } + #endregion + + #region 公共方法 + /// + /// 设置SDF字体 + /// + public void SetSDFFont(TMP_FontAsset fontAsset) + { + savedFontAsset = fontAsset; + } + + /// + /// 重新加载自定义复选框 + /// + public void ReloadCustomCheckBoxes() + { + LoadCustomCheckBoxes(); + } + #endregion + + #region 私有方法 + /// + /// 加载所有自定义复选框(使用反射) + /// + private void LoadCustomCheckBoxes() + { + if (checkBoxContainer == null || checkBoxPrefab == null) + { + Debug.LogWarning("[CustomCheckBoxesModule] 复选框容器或复选框预制件未设置"); + return; + } + + // 清空现有复选框 + foreach (Transform child in checkBoxContainer) + { + UnityEngine.Object.Destroy(child.gameObject); + } + + // 查找所有标记为DebugCheckBox的方法 + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in assemblies) + { + try + { + var types = assembly.GetTypes(); + foreach (var type in types) + { + var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var method in methods) + { + var attribute = method.GetCustomAttribute(); + if (attribute != null) + { + CreateCustomCheckBox(method, attribute); + } + } + } + } + catch (Exception e) + { + // 某些程序集可能无法访问,跳过 + Debug.LogWarning($"[CustomCheckBoxesModule] 无法访问程序集 {assembly.FullName}: {e.Message}"); + } + } + } + + private void CreateCustomCheckBox(MethodInfo method, DebugCheckBoxAttribute attribute) + { + // 验证方法签名:必须接受一个 bool 参数 + var parameters = method.GetParameters(); + if (parameters.Length != 1 || parameters[0].ParameterType != typeof(bool)) + { + Debug.LogWarning($"[CustomCheckBoxesModule] 方法 {method.Name} 必须接受一个 bool 参数"); + return; + } + + GameObject checkBoxObj = UnityEngine.Object.Instantiate(checkBoxPrefab, checkBoxContainer); + Toggle toggle = checkBoxObj.GetComponent(); + TMP_Text labelText = checkBoxObj.GetComponentInChildren(); + Image backgroundImage = checkBoxObj.GetComponent(); + + // 设置复选框文本 + if (labelText != null) + { + labelText.text = string.IsNullOrEmpty(attribute.DisplayName) ? method.Name : attribute.DisplayName; + + // 应用保存的字体 + if (savedFontAsset != null) + { + labelText.font = savedFontAsset; + } + } + + // 设置背景颜色 + if (backgroundImage != null && attribute.CheckBoxColor != default(Color)) + { + backgroundImage.color = attribute.CheckBoxColor; + } + + // 获取或初始化状态(默认为 false) + string methodKey = $"{method.DeclaringType?.FullName}.{method.Name}"; + if (!checkBoxStates.ContainsKey(methodKey)) + { + checkBoxStates[methodKey] = false; + } + + // 设置初始状态 + if (toggle != null) + { + toggle.isOn = checkBoxStates[methodKey]; + } + + // 设置复选框状态改变事件 + toggle.onValueChanged.AddListener((bool isOn) => + { + try + { + // 保存状态 + checkBoxStates[methodKey] = isOn; + + // 调用方法,传递状态 + method.Invoke(null, new object[] { isOn }); + Debug.Log($"[CustomCheckBoxesModule] 执行调试方法: {method.Name}, 状态: {isOn}"); + } + catch (Exception e) + { + Debug.LogError($"[CustomCheckBoxesModule] 执行调试方法 {method.Name} 时出错: {e.Message}"); + } + }); + } + #endregion + } +} diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs.meta b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs.meta new file mode 100644 index 0000000..ef26248 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomCheckBoxesModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e8d7e036c6d4b2d4083addffa8c87eb8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomValuesModule.cs b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomValuesModule.cs new file mode 100644 index 0000000..06a47c9 --- /dev/null +++ b/Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomValuesModule.cs @@ -0,0 +1,274 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +namespace MeowmentDebugTool +{ + /// + /// 自定义数值模块 - 通过反射加载标记为DebugValue的方法 + /// + public class CustomValuesModule : IDebugModule + { + #region 字段 + private GameObject customValuesPage; + private RectTransform valueContainer; + private GameObject valuePrefab; + private ScrollRect valuesScrollRect; + + // 保存的SDF字体资源 + private TMP_FontAsset savedFontAsset = null; + + // 保存每个数值的当前值 + private Dictionary valueStates = new Dictionary(); + + // 关闭窗口回调 + private Action onCloseWindowCallback; + #endregion + + #region 构造函数 + public CustomValuesModule(GameObject page, RectTransform container, GameObject prefab, + ScrollRect scrollRect, Action closeWindowCallback) + { + customValuesPage = page; + valueContainer = container; + valuePrefab = prefab; + valuesScrollRect = scrollRect; + onCloseWindowCallback = closeWindowCallback; + } + #endregion + + #region IDebugModule 实现 + public void Initialize() + { + Debug.Log("[CustomValuesModule] 初始化自定义数值模块..."); + LoadCustomValues(); + } + + public GameObject GetPage() + { + return customValuesPage; + } + + public string GetModuleName() + { + return "数值"; + } + #endregion + + #region 公共方法 + /// + /// 设置SDF字体 + /// + public void SetSDFFont(TMP_FontAsset fontAsset) + { + savedFontAsset = fontAsset; + } + + /// + /// 重新加载自定义数值 + /// + public void ReloadCustomValues() + { + LoadCustomValues(); + } + #endregion + + #region 私有方法 + /// + /// 加载所有自定义数值(使用反射) + /// + private void LoadCustomValues() + { + if (valueContainer == null || valuePrefab == null) + { + Debug.LogWarning("[CustomValuesModule] 数值容器或数值预制件未设置"); + return; + } + + // 清空现有数值 + foreach (Transform child in valueContainer) + { + UnityEngine.Object.Destroy(child.gameObject); + } + + // 查找所有标记为DebugValue的方法 + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in assemblies) + { + try + { + var types = assembly.GetTypes(); + foreach (var type in types) + { + var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var method in methods) + { + var attribute = method.GetCustomAttribute(); + if (attribute != null) + { + CreateCustomValue(method, attribute); + } + } + } + } + catch (Exception e) + { + // 某些程序集可能无法访问,跳过 + Debug.LogWarning($"[CustomValuesModule] 无法访问程序集 {assembly.FullName}: {e.Message}"); + } + } + } + + private void CreateCustomValue(MethodInfo method, DebugValueAttribute attribute) + { + // 验证方法签名:必须接受一个 int 参数 + var parameters = method.GetParameters(); + if (parameters.Length != 1 || parameters[0].ParameterType != typeof(int)) + { + Debug.LogWarning($"[CustomValuesModule] 方法 {method.Name} 必须接受一个 int 参数"); + return; + } + + GameObject valueObj = UnityEngine.Object.Instantiate(valuePrefab, valueContainer); + + // 获取组件 + TMP_Text labelText = valueObj.transform.Find("Label")?.GetComponent(); + Slider slider = valueObj.transform.Find("Slider")?.GetComponent(); + TMP_InputField inputField = valueObj.transform.Find("InputField")?.GetComponent(); + Button confirmButton = valueObj.transform.Find("ConfirmButton")?.GetComponent