Compare commits
No commits in common. "master" and "main" have entirely different histories.
106
.gitignore
vendored
106
.gitignore
vendored
@ -1,106 +0,0 @@
|
||||
# This .gitignore file should be placed at the root of your Unity project directory
|
||||
#
|
||||
# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore
|
||||
#
|
||||
.utmp/
|
||||
/[Ll]ibrary/
|
||||
/[Tt]emp/
|
||||
/[Oo]bj/
|
||||
/[Bb]uild/
|
||||
/[Bb]uilds/
|
||||
/[Ll]ogs/
|
||||
/[Uu]ser[Ss]ettings/
|
||||
*.log
|
||||
|
||||
# By default unity supports Blender asset imports, *.blend1 blender files do not need to be commited to version control.
|
||||
*.blend1
|
||||
*.blend1.meta
|
||||
|
||||
# MemoryCaptures can get excessive in size.
|
||||
# They also could contain extremely sensitive data
|
||||
/[Mm]emoryCaptures/
|
||||
|
||||
# Recordings can get excessive in size
|
||||
/[Rr]ecordings/
|
||||
|
||||
# Uncomment this line if you wish to ignore the asset store tools plugin
|
||||
# /[Aa]ssets/AssetStoreTools*
|
||||
|
||||
# Autogenerated Jetbrains Rider plugin
|
||||
/[Aa]ssets/Plugins/Editor/JetBrains*
|
||||
# Jetbrains Rider personal-layer settings
|
||||
*.DotSettings.user
|
||||
|
||||
# Visual Studio cache directory
|
||||
.vs/
|
||||
|
||||
# Gradle cache directory
|
||||
.gradle/
|
||||
|
||||
# Autogenerated VS/MD/Consulo solution and project files
|
||||
ExportedObj/
|
||||
.consulo/
|
||||
*.csproj
|
||||
*.unityproj
|
||||
*.sln
|
||||
*.suo
|
||||
*.tmp
|
||||
*.user
|
||||
*.userprefs
|
||||
*.pidb
|
||||
*.booproj
|
||||
*.svd
|
||||
*.pdb
|
||||
*.mdb
|
||||
*.opendb
|
||||
*.VC.db
|
||||
|
||||
# Unity3D generated meta files
|
||||
*.pidb.meta
|
||||
*.pdb.meta
|
||||
*.mdb.meta
|
||||
|
||||
# Unity3D generated file on crash reports
|
||||
sysinfo.txt
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Builds
|
||||
*.apk
|
||||
*.aab
|
||||
*.unitypackage
|
||||
*.unitypackage.meta
|
||||
|
||||
# Crashlytics generated file
|
||||
crashlytics-build.properties
|
||||
|
||||
# TestRunner generated files
|
||||
InitTestScene*.unity*
|
||||
|
||||
# Addressables default ignores, before user customizations
|
||||
/ServerData
|
||||
/[Aa]ssets/StreamingAssets/aa*
|
||||
/[Aa]ssets/AddressableAssetsData/link.xml*
|
||||
/[Aa]ssets/Addressables_Temp*
|
||||
# By default, Addressables content builds will generate addressables_content_state.bin
|
||||
# files in platform-specific subfolders, for example:
|
||||
# /Assets/AddressableAssetsData/OSX/addressables_content_state.bin
|
||||
/[Aa]ssets/AddressableAssetsData/*/*.bin*
|
||||
|
||||
# Visual Scripting auto-generated files
|
||||
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db
|
||||
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db.meta
|
||||
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers
|
||||
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers.meta
|
||||
|
||||
# Auto-generated scenes by play mode tests
|
||||
/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity*
|
||||
|
||||
.vsconfig
|
||||
|
||||
Logs/
|
||||
[Aa]ssets/
|
||||
[Pp]ublish/
|
||||
.vscode/settings.json
|
||||
*.dat
|
||||
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
@ -1,5 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"visualstudiotoolsforunity.vstuc"
|
||||
]
|
||||
}
|
||||
10
.vscode/launch.json
vendored
10
.vscode/launch.json
vendored
@ -1,10 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach to Unity",
|
||||
"type": "vstuc",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
<Solution>
|
||||
<Project Path="com.bywaystudios.meowmentdebugtool.csproj" />
|
||||
<Project Path="com.bywaystudios.meowmentdebugtool.Editor.csproj" />
|
||||
<Project Path="Assembly-CSharp.csproj" />
|
||||
</Solution>
|
||||
@ -1,169 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
所有重要的变更都会记录在这个文件中。
|
||||
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
||||
版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
|
||||
|
||||
## [0.3.11] - 2025-12-30
|
||||
|
||||
### Added
|
||||
|
||||
- 添加按钮分组功能
|
||||
|
||||
## [0.3.9] - 2025-12-25
|
||||
|
||||
### Added
|
||||
- **数值模块运行时控制**
|
||||
- 新增 `UpdateDebugValue()` 公开接口,支持运行时动态修改数值特性的当前值
|
||||
- 支持完整方法名("ClassName.MethodName")或简单方法名("MethodName")查找
|
||||
- 自动限制值在特性定义的最小值和最大值范围内
|
||||
- 同步更新UI滑块和输入框显示
|
||||
|
||||
## [0.3.8] - 2025-12-25
|
||||
### Improved
|
||||
- **控制台模块性能优化**
|
||||
- 默认不显示Info和Warning类型日志(Error和Fatal保持默认显示)
|
||||
- 对于被过滤的日志类型不创建LogItem UI元素,大幅减少初始内存占用和UI开销
|
||||
- 仅在用户手动激活对应过滤器时才创建和显示相关日志UI
|
||||
- 显著提升启动性能,特别是在大量Info/Warning日志场景下
|
||||
|
||||
|
||||
|
||||
## [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
|
||||
- **控制台模块 (Console)**
|
||||
- 实时捕获并显示Unity日志(Info、Warning、Error、Fatal)
|
||||
- 支持日志类型过滤(可单独开关各类型日志显示)
|
||||
- 支持日志点击查看详细信息(堆栈跟踪)
|
||||
- 日志数量统计和实时更新
|
||||
- 支持清空日志功能
|
||||
- 支持锁定滚动功能(自动滚动到最新日志)
|
||||
- 日志项对象池优化,提升性能
|
||||
- 最大日志数限制(默认100条,可配置)
|
||||
- 日志详情区域显示完整堆栈信息
|
||||
- 使用UGUI实现,支持ScrollRect滚动
|
||||
|
||||
- **暂时隐藏功能**
|
||||
- 工具栏新增"暂时隐藏(5秒)"按钮
|
||||
- 用于截图时临时隐藏调试工具UI
|
||||
- 自动在指定时间后恢复显示
|
||||
- 支持防重入保护,避免重复触发
|
||||
- 恢复后保持浮窗状态,不自动打开主窗口
|
||||
|
||||
### Changed
|
||||
- 重构代码架构,将功能模块化
|
||||
- 新增 `IDebugModule` 接口
|
||||
- 拆分为独立模块:`ParametersModule`、`CustomButtonsModule`、`ToolbarModule`、`SettingsModule`、`ConsoleModule`
|
||||
- 优化控制台UI布局
|
||||
- ControlPanel高度优化为40像素
|
||||
- LogArea和DetailArea固定高度
|
||||
- 移除不常用的Spacer元素
|
||||
- 优化日志显示
|
||||
- 日志项高度从30增加到50像素
|
||||
- 字体大小从22增加到28
|
||||
- 添加上下边距提升可读性
|
||||
- 移除所有emoji字符,避免字体缺失警告
|
||||
- 锁定滚动功能默认开启
|
||||
|
||||
### Fixed
|
||||
- 修复Canvas rebuild loop错误(延迟刷新机制)
|
||||
- 修复日志项RectTransform锚点设置问题
|
||||
- 修复VerticalLayoutGroup子元素高度控制问题
|
||||
- 修复页面未激活时不必要的更新操作
|
||||
- 修复暂时隐藏功能第二次执行失败的问题
|
||||
|
||||
## [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 确保场景切换时不销毁
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 612f48a21477a8447b81076490854b01
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f19c5c16d0604dc46933685ee55053c1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,169 +0,0 @@
|
||||
>>>
|
||||
**_Package Documentation Template_**
|
||||
|
||||
Use this template to create preliminary, high-level documentation meant to introduce users to the feature and the sample files included in this package. When writing your documentation, do the following:
|
||||
|
||||
1. Follow instructions in blockquotes.
|
||||
|
||||
2. Replace angle brackets with the appropriate text. For example, replace "<package name>" with the official name of the package.
|
||||
|
||||
3. Delete sections that do not apply to your package. For example, a package containing only sample files does not have a "Using <package_name>" section, so this section can be removed.
|
||||
|
||||
4. After documentation is completed, make sure you delete all instructions and examples in blockquotes including this preamble and its title:
|
||||
|
||||
```
|
||||
>>>
|
||||
Delete all of the text between pairs of blockquote markdown.
|
||||
>>>
|
||||
```
|
||||
>>>
|
||||
|
||||
# About <package name>
|
||||
|
||||
>>>
|
||||
Name the heading of the first topic after the **displayName** of the package as it appears in the package manifest.
|
||||
|
||||
This first topic includes a brief, high-level explanation of the package and, if applicable, provides links to Unity Manual topics.
|
||||
|
||||
There are two types of packages:
|
||||
|
||||
- Packages that include features that augment the Unity Editor or Runtime.
|
||||
- Packages that include sample files.
|
||||
|
||||
Choose one of the following introductory paragraphs that best fits the package:
|
||||
>>>
|
||||
|
||||
Use the <package name> package to <list of the main uses for the package>. For example, use <package name> to create/generate/extend/capture <mention major use case, or a good example of what the package can be used for>. The <package name> package also includes <other relevant features or uses>.
|
||||
|
||||
> *or*
|
||||
|
||||
The <package name> package includes examples of <name of asset type, model, prefabs, and/or other GameObjects in the package>. For more information, see <xref to topic in the Unity Manual>.
|
||||
|
||||
>>>
|
||||
**_Examples:_**
|
||||
|
||||
Here are some examples for reference only. Do not include these in the final documentation file:
|
||||
|
||||
*Use the Unity Recorder package to capture and save in-game data. For example, use Unity Recorder to record an mp4 file during a game session. The Unity Recorder package also includes an interface for setting-up and triggering recording sessions.*
|
||||
|
||||
*The Timeline Examples package includes examples of Timeline assets, Timeline Instances, animation, GameObjects, and scripts that illustrate how to use Unity's Timeline. For more information, see [ Unity's Timeline](https://docs.unity3d.com/Manual/TimelineSection.html) in the [Unity Manual](https://docs.unity3d.com). For licensing and usage, see Package Licensing.*
|
||||
>>>
|
||||
|
||||
# Installing <package name>
|
||||
>>>
|
||||
Begin this section with a cross-reference to the official Unity Manual topic on how to install packages. If the package requires special installation instructions, include these steps in this section.
|
||||
>>>
|
||||
|
||||
To install this package, follow the instructions in the [Package Manager documentation](https://docs.unity3d.com/Packages/com.unity.package-manager-ui@latest/index.html).
|
||||
|
||||
>>>
|
||||
For some packages, there may be additional steps to complete the setup. You can add those here.
|
||||
>>>
|
||||
|
||||
In addition, you need to install the following resources:
|
||||
|
||||
- <name of resource>: To install, open *Window > <name of menu item>*. The resource appears <at this location>.
|
||||
- <name of sample>: To install, open *Window > <name of menu item>*. The new sample folder appears <at this location>.
|
||||
|
||||
|
||||
<a name="UsingPackageName"></a>
|
||||
# Using <package name>
|
||||
>>>
|
||||
The contents of this section depends on the type of package.
|
||||
|
||||
For packages that augment the Unity Editor with additional features, this section should include workflow and/or reference documentation:
|
||||
|
||||
* At a minimum, this section should include reference documentation that describes the windows, editors, and properties that the package adds to Unity. This reference documentation should include screen grabs (see how to add screens below), a list of settings, an explanation of what each setting does, and the default values of each setting.
|
||||
* Ideally, this section should also include a workflow: a list of steps that the user can easily follow that demonstrates how to use the feature. This list of steps should include screen grabs (see how to add screens below) to better describe how to use the feature.
|
||||
|
||||
For packages that include sample files, this section may include detailed information on how the user can use these sample files in their projects and scenes. However, workflow diagrams or illustrations could be included if deemed appropriate.
|
||||
|
||||
## How to add images
|
||||
|
||||
*(This section is for reference. Do not include in the final documentation file)*
|
||||
|
||||
If the [Using <package name>](#UsingPackageName) section includes screen grabs or diagrams, a link to the image must be added to this MD file, before or after the paragraph with the instruction or description that references the image. In addition, a caption should be added to the image link that includes the name of the screen or diagram. All images must be PNG files with underscores for spaces. No animated GIFs.
|
||||
|
||||
An example is included below:
|
||||
|
||||

|
||||
|
||||
Notice that the example screen shot is included in the images folder. All screen grabs and/or diagrams must be added and referenced from the images folder.
|
||||
|
||||
For more on the Unity documentation standards for creating and adding screen grabs, see this confluence page: https://confluence.hq.unity3d.com/pages/viewpage.action?pageId=13500715
|
||||
>>>
|
||||
|
||||
|
||||
|
||||
# Technical details
|
||||
## Requirements
|
||||
>>>
|
||||
This subtopic includes a bullet list with the compatible versions of Unity. This subtopic may also include additional requirements or recommendations for 3rd party software or hardware. An example includes a dependency on other packages. If you need to include references to non-Unity products, make sure you refer to these products correctly and that all references include the proper trademarks (tm or r)
|
||||
>>>
|
||||
|
||||
This version of <package name> is compatible with the following versions of the Unity Editor:
|
||||
|
||||
* 2018.1 and later (recommended)
|
||||
|
||||
To use this package, you must have the following 3rd party products:
|
||||
|
||||
* <product name and version with trademark or registered trademark.>
|
||||
* <product name and version with trademark or registered trademark.>
|
||||
* <product name and version with trademark or registered trademark.>
|
||||
|
||||
## Known limitations
|
||||
>>>
|
||||
This section lists the known limitations with this version of the package. If there are no known limitations, or if the limitations are trivial, exclude this section. An example is provided.
|
||||
>>>
|
||||
|
||||
<package name> version <package version> includes the following known limitations:
|
||||
|
||||
* <brief one-line description of first limitation.>
|
||||
* <brief one-line description of second limitation.>
|
||||
* <and so on>
|
||||
|
||||
>>>
|
||||
*Example (For reference. Do not include in the final documentation file):*
|
||||
|
||||
The Unity Recorder version 1.0 has the following limitations:*
|
||||
|
||||
* The Unity Recorder does not support sound.
|
||||
* The Recorder window and Recorder properties are not available in standalone players.
|
||||
* MP4 encoding is only available on Windows.
|
||||
>>>
|
||||
|
||||
## Package contents
|
||||
>>>
|
||||
This section includes the location of important files you want the user to know about. For example, if this is a sample package containing textures, models, and materials separated by sample group, you may want to provide the folder location of each group.
|
||||
>>>
|
||||
|
||||
The following table indicates the <describe the breakdown you used here>:
|
||||
|
||||
|Location|Description|
|
||||
|---|---|
|
||||
|`<folder>`|Contains <describe what the folder contains>.|
|
||||
|`<file>`|Contains <describe what the file represents or implements>.|
|
||||
|
||||
>>>
|
||||
*Example (For reference. Do not include in the final documentation file):*
|
||||
|
||||
The following table indicates the root folder of each type of sample in this package. Each sample's root folder contains its own Materials, Models, or Textures folders:
|
||||
|
||||
|Folder Location|Description|
|
||||
|---|---|
|
||||
|`WoodenCrate_Orange`|Root folder containing the assets for the orange crates.|
|
||||
|`WoodenCrate_Mahogany`|Root folder containing the assets for the mahogany crates.|
|
||||
|`WoodenCrate_Shared`|Root folder containing any material assets shared by all crates.|
|
||||
>>>
|
||||
|
||||
## Document revision history
|
||||
>>>
|
||||
This section includes the revision history of the document. The revision history tracks when a document is created, edited, and updated. If you create or update a document, you must add a new row describing the revision. The Documentation Team also uses this table to track when a document is edited and its editing level. An example is provided:
|
||||
|
||||
|Date|Reason|
|
||||
|---|---|
|
||||
|Sept 12, 2017|Unedited. Published to package.|
|
||||
|Sept 10, 2017|Document updated for package version 1.1.<br>New features: <li>audio support for capturing MP4s.<li>Instructions on saving Recorder prefabs|
|
||||
|Sept 5, 2017|Limited edit by Documentation Team. Published to package.|
|
||||
|Aug 25, 2017|Document created. Matches package version 1.0.|
|
||||
>>>
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aec9ee7d68a191447a418cccf7100f20
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,196 +0,0 @@
|
||||
# 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)
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab342e44111b45e409658513642a8ea9
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94ff33738b6ce3f4ab8b77b08ced2cdf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,107 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建Tab按钮预制件的辅助工具
|
||||
/// </summary>
|
||||
public class CreateTabButtonPrefab : EditorWindow
|
||||
{
|
||||
[MenuItem("Tools/Debug Tool/手动创建Tab按钮预制件")]
|
||||
public static void CreatePrefab()
|
||||
{
|
||||
// 创建Tab按钮
|
||||
GameObject btn = new GameObject("TabButtonPrefab");
|
||||
|
||||
RectTransform rt = btn.AddComponent<RectTransform>();
|
||||
rt.sizeDelta = new Vector2(200, 80);
|
||||
|
||||
Image img = btn.AddComponent<Image>();
|
||||
img.color = Color.gray;
|
||||
|
||||
Button button = btn.AddComponent<Button>();
|
||||
button.targetGraphic = img;
|
||||
|
||||
// 添加文本
|
||||
GameObject textObj = new GameObject("Text");
|
||||
textObj.transform.SetParent(btn.transform, false);
|
||||
|
||||
RectTransform textRt = textObj.AddComponent<RectTransform>();
|
||||
textRt.anchorMin = Vector2.zero;
|
||||
textRt.anchorMax = Vector2.one;
|
||||
textRt.sizeDelta = Vector2.zero;
|
||||
|
||||
TextMeshProUGUI text = textObj.AddComponent<TextMeshProUGUI>();
|
||||
text.text = "Tab";
|
||||
text.fontSize = 32;
|
||||
text.fontStyle = FontStyles.Bold;
|
||||
text.enableAutoSizing = true;
|
||||
text.fontSizeMin = 12;
|
||||
text.fontSizeMax = 72;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.color = Color.white;
|
||||
|
||||
// 保存为预制件
|
||||
string path = "Assets/TabButtonPrefab.prefab";
|
||||
PrefabUtility.SaveAsPrefabAsset(btn, path);
|
||||
|
||||
// 清理
|
||||
DestroyImmediate(btn);
|
||||
|
||||
// 选中
|
||||
Selection.activeObject = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
||||
|
||||
EditorUtility.DisplayDialog("成功", $"Tab按钮预制件已创建: {path}\n请将其拖到UniversalDebugTool的Tab Button Prefab字段", "确定");
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Debug Tool/手动创建自定义按钮预制件")]
|
||||
public static void CreateCustomButtonPrefab()
|
||||
{
|
||||
// 创建自定义按钮
|
||||
GameObject btn = new GameObject("CustomButtonPrefab");
|
||||
|
||||
RectTransform rt = btn.AddComponent<RectTransform>();
|
||||
rt.sizeDelta = new Vector2(200, 80);
|
||||
|
||||
Image img = btn.AddComponent<Image>();
|
||||
img.color = new Color(0.3f, 0.3f, 0.8f);
|
||||
|
||||
Button button = btn.AddComponent<Button>();
|
||||
button.targetGraphic = img;
|
||||
|
||||
// 添加文本
|
||||
GameObject textObj = new GameObject("Text");
|
||||
textObj.transform.SetParent(btn.transform, false);
|
||||
|
||||
RectTransform textRt = textObj.AddComponent<RectTransform>();
|
||||
textRt.anchorMin = Vector2.zero;
|
||||
textRt.anchorMax = Vector2.one;
|
||||
textRt.sizeDelta = Vector2.zero;
|
||||
textRt.offsetMin = new Vector2(10, 10);
|
||||
textRt.offsetMax = new Vector2(-10, -10);
|
||||
|
||||
TextMeshProUGUI text = textObj.AddComponent<TextMeshProUGUI>();
|
||||
text.text = "Button";
|
||||
text.fontSize = 24;
|
||||
text.fontStyle = FontStyles.Bold;
|
||||
text.enableAutoSizing = true;
|
||||
text.fontSizeMin = 12;
|
||||
text.fontSizeMax = 72;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.color = Color.white;
|
||||
text.enableWordWrapping = true;
|
||||
|
||||
// 保存为预制件
|
||||
string path = "Assets/CustomButtonPrefab.prefab";
|
||||
PrefabUtility.SaveAsPrefabAsset(btn, path);
|
||||
|
||||
// 清理
|
||||
DestroyImmediate(btn);
|
||||
|
||||
// 选中
|
||||
Selection.activeObject = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
||||
|
||||
EditorUtility.DisplayDialog("成功", $"自定义按钮预制件已创建: {path}\n请将其拖到UniversalDebugTool的Button Prefab字段", "确定");
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09b47930b7f0d1a46ad5443d47b1fcaf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,131 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using MeowmentDebugTool;
|
||||
|
||||
namespace MeowmentDebugTool.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 诊断UniversalDebugTool的引用问题
|
||||
/// </summary>
|
||||
public class DebugToolDiagnostic : EditorWindow
|
||||
{
|
||||
[MenuItem("Tools/Debug Tool/诊断引用问题")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<DebugToolDiagnostic>("调试工具诊断");
|
||||
window.minSize = new Vector2(500, 400);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private UniversalDebugTool tool;
|
||||
private Vector2 scrollPos;
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
EditorGUILayout.LabelField("UniversalDebugTool 诊断工具", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox("这个工具会检查调试工具的所有引用是否正确设置", MessageType.Info);
|
||||
|
||||
GUILayout.Space(10);
|
||||
tool = (UniversalDebugTool)EditorGUILayout.ObjectField("调试工具对象", tool, typeof(UniversalDebugTool), true);
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
if (tool == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("请从Hierarchy或Project中拖入UniversalDebugTool对象", MessageType.Warning);
|
||||
|
||||
if (GUILayout.Button("在场景中查找"))
|
||||
{
|
||||
tool = FindObjectOfType<UniversalDebugTool>();
|
||||
if (tool == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("未找到", "场景中没有UniversalDebugTool对象", "确定");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
|
||||
|
||||
// 检查所有引用
|
||||
SerializedObject so = new SerializedObject(tool);
|
||||
|
||||
CheckReference(so, "mainWindow", "Main Window");
|
||||
CheckReference(so, "canvas", "Canvas");
|
||||
CheckReference(so, "tabButtonContainer", "Tab Button Container", true);
|
||||
CheckReference(so, "contentContainer", "Content Container");
|
||||
CheckReference(so, "tabButtonPrefab", "Tab Button Prefab", true);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("页面引用", EditorStyles.boldLabel);
|
||||
CheckReference(so, "parametersPage", "Parameters Page");
|
||||
CheckReference(so, "customButtonsPage", "Custom Buttons Page");
|
||||
CheckReference(so, "settingsPage", "Settings Page");
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("参数页面组件", EditorStyles.boldLabel);
|
||||
CheckReference(so, "deviceInfoText", "Device Info Text");
|
||||
CheckReference(so, "systemInfoText", "System Info Text");
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("按钮页面组件", EditorStyles.boldLabel);
|
||||
CheckReference(so, "buttonContainer", "Button Container");
|
||||
CheckReference(so, "buttonPrefab", "Button Prefab", true);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("设置页面组件", EditorStyles.boldLabel);
|
||||
CheckReference(so, "widthInputField", "Width Input Field");
|
||||
CheckReference(so, "heightInputField", "Height Input Field");
|
||||
CheckReference(so, "applyResolutionButton", "Apply Resolution Button");
|
||||
CheckReference(so, "resetResolutionButton", "Reset Resolution Button");
|
||||
CheckReference(so, "currentResolutionText", "Current Resolution Text");
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("输入对话框组件", EditorStyles.boldLabel);
|
||||
CheckReference(so, "inputDialog", "Input Dialog");
|
||||
CheckReference(so, "inputDialogTitle", "Input Dialog Title");
|
||||
CheckReference(so, "inputDialogInputField", "Input Dialog Input Field");
|
||||
CheckReference(so, "inputDialogConfirmBtn", "Input Dialog Confirm Button");
|
||||
CheckReference(so, "inputDialogCancelBtn", "Input Dialog Cancel Button");
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
if (GUILayout.Button("重新生成预制件", GUILayout.Height(40)))
|
||||
{
|
||||
DebugToolPrefabGenerator.ShowWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckReference(SerializedObject so, string propertyName, string displayName, bool critical = false)
|
||||
{
|
||||
SerializedProperty prop = so.FindProperty(propertyName);
|
||||
if (prop != null)
|
||||
{
|
||||
bool isNull = prop.objectReferenceValue == null;
|
||||
|
||||
GUIStyle style = new GUIStyle(EditorStyles.label);
|
||||
if (isNull)
|
||||
{
|
||||
if (critical)
|
||||
{
|
||||
style.normal.textColor = Color.red;
|
||||
EditorGUILayout.LabelField($"❌ {displayName}: 未设置 (必需)", style);
|
||||
}
|
||||
else
|
||||
{
|
||||
style.normal.textColor = new Color(1f, 0.5f, 0f);
|
||||
EditorGUILayout.LabelField($"⚠️ {displayName}: 未设置", style);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
style.normal.textColor = Color.green;
|
||||
EditorGUILayout.LabelField($"✅ {displayName}: {prop.objectReferenceValue.name}", style);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 207ea43d8a1b48b4d82353ac89ef2933
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab355a91334847f45aa2fe391a061474
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,53 +0,0 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MeowmentDebugTool.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动添加 MEOWMENT_DEBUG_TOOL 宏定义
|
||||
/// 注意:已禁用自动添加功能,如需启用请取消注释 [InitializeOnLoad] 特性
|
||||
/// </summary>
|
||||
// [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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5698ea2959bec274ea3e28b53f9ba8e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "com.bywaystudios.meowmentdebugtool.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"com.bywaystudios.meowmentdebugtool",
|
||||
"Unity.TextMeshPro"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7ea52de8e3323042b5161a7449156b4
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,85 +0,0 @@
|
||||
# MeowMent Debug Tool
|
||||
|
||||
Unity 运行时调试工具。
|
||||
|
||||
|
||||
|
||||
## 目录
|
||||
|
||||
- [给策划](#给策划)
|
||||
- [给客户端](#给客户端)
|
||||
- [给服务端](#给服务端)
|
||||
|
||||
## 给策划
|
||||
|
||||
点击屏幕左侧蓝色浮窗打开调试窗口。
|
||||
|
||||
**参数查看** - 查看设备信息、系统信息,可复制
|
||||
**自定义按钮** - 执行调试功能(清空数据、添加道具等)
|
||||
**开关** - 功能开关控制(开启/关闭某些功能)
|
||||
**数值** - 数值调整(通过滑块和输入框调整整数值)
|
||||
**控制台** - 查看日志、过滤、堆栈信息
|
||||
**设置** - 调整分辨率
|
||||
|
||||
四指点击屏幕是隐藏和现实Debugger工具
|
||||
|
||||
## 给客户端
|
||||
|
||||
在游戏启动时初始化:
|
||||
|
||||
```csharp
|
||||
using MeowmentDebugTool;
|
||||
using TMPro;
|
||||
|
||||
void Start()
|
||||
{
|
||||
#if MEOWMENT_DEBUG_TOOL
|
||||
UniversalDebugTool.Init();
|
||||
UniversalDebugTool.SetSDFFont(customFont); // 可选,设置中文字体
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
## 给服务端
|
||||
|
||||
用 `[DebugButton]` 特性标记静态方法自动生成按钮:
|
||||
|
||||
```csharp
|
||||
public static class DebugFunctions
|
||||
{
|
||||
[DebugButton("分组1","清空数据")]
|
||||
private static void ClearData()
|
||||
{
|
||||
PlayerPrefs.DeleteAll();
|
||||
}
|
||||
|
||||
// 设置按钮颜色 (r, g, b)
|
||||
[DebugButton("分组1","添加金币", 0.2f, 0.8f, 0.2f)]
|
||||
private static void AddCoins()
|
||||
{
|
||||
PlayerData.Coins += 1000;
|
||||
}
|
||||
|
||||
// 复选框开关,方法必须接收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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
**字体显示方块?** 调用 `SetSDFFont()` 设置中文字体
|
||||
**按钮不显示?** 检查方法是否为 `static` 且有 `[DebugButton]` 特性
|
||||
**如何移除?** 删除 Packages 下的工具包文件夹
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e02e5b1c453f4e40ae8aae7b10ddf6c
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e468d6a064653104c9c82559cbcae7ef
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,729 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 控制台模块 - 显示Unity日志(基于UGUI实现)
|
||||
/// </summary>
|
||||
public class ConsoleModule : IDebugModule
|
||||
{
|
||||
#region 字段
|
||||
private GameObject consolePage;
|
||||
|
||||
// UI组件
|
||||
private ScrollRect logScrollRect;
|
||||
private RectTransform logContent;
|
||||
private ScrollRect detailScrollRect;
|
||||
private TMP_Text detailText;
|
||||
|
||||
// 按钮
|
||||
private Button clearButton;
|
||||
private Toggle lockScrollToggle;
|
||||
private Toggle infoFilterToggle;
|
||||
private Toggle warningFilterToggle;
|
||||
private Toggle errorFilterToggle;
|
||||
private Toggle fatalFilterToggle;
|
||||
|
||||
// 文字筛选
|
||||
private TMP_InputField textFilterInputField;
|
||||
private string textFilter = "";
|
||||
private TMP_Text infoFilterLabel;
|
||||
private TMP_Text warningFilterLabel;
|
||||
private TMP_Text errorFilterLabel;
|
||||
private TMP_Text fatalFilterLabel;
|
||||
|
||||
// 日志项预制件
|
||||
private GameObject logItemPrefab;
|
||||
|
||||
// 日志数据 - 分离的缓存池
|
||||
private Queue<LogNode> infoLogNodes = new Queue<LogNode>();
|
||||
private Queue<LogNode> warningLogNodes = new Queue<LogNode>();
|
||||
private Queue<LogNode> errorLogNodes = new Queue<LogNode>();
|
||||
private Queue<LogNode> fatalLogNodes = new Queue<LogNode>();
|
||||
private LogNode selectedNode = null;
|
||||
|
||||
// 日志计数
|
||||
private int infoCount = 0;
|
||||
private int warningCount = 0;
|
||||
private int errorCount = 0;
|
||||
private int fatalCount = 0;
|
||||
|
||||
// 设置
|
||||
private bool lockScroll = true;
|
||||
private int maxInfoLines = 50;
|
||||
private int maxWarningLines = 50;
|
||||
private int maxErrorLines = 50;
|
||||
private int maxFatalLines = 50;
|
||||
private bool infoFilter = false; // 默认不显示Info
|
||||
private bool warningFilter = false; // 默认不显示Warning
|
||||
private bool errorFilter = true;
|
||||
private bool fatalFilter = true;
|
||||
|
||||
// 颜色设置
|
||||
private Color32 infoColor = Color.white;
|
||||
private Color32 warningColor = Color.yellow;
|
||||
private Color32 errorColor = Color.red;
|
||||
private Color32 fatalColor = new Color(0.7f, 0.2f, 0.2f);
|
||||
|
||||
// UI对象池
|
||||
private List<GameObject> logItemPool = new List<GameObject>();
|
||||
private List<GameObject> activeLogItems = new List<GameObject>();
|
||||
|
||||
// 保存的字体
|
||||
private TMP_FontAsset savedFontAsset = null;
|
||||
|
||||
// 延迟刷新标记
|
||||
private bool needRefresh = false;
|
||||
private int lastRefreshFrame = -1;
|
||||
private bool hasRegisteredLogCallback = false;
|
||||
private bool uiInitialized = false;
|
||||
private int lastDisplayedInfoCount = -1;
|
||||
private int lastDisplayedWarningCount = -1;
|
||||
private int lastDisplayedErrorCount = -1;
|
||||
private int lastDisplayedFatalCount = -1;
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
public ConsoleModule(GameObject page, ScrollRect logScroll, RectTransform logContentTransform,
|
||||
ScrollRect detailScroll, TMP_Text detail,
|
||||
Button clearBtn, Toggle lockToggle, Toggle infoToggle, Toggle warningToggle,
|
||||
Toggle errorToggle, Toggle fatalToggle, TMP_InputField textFilterInput, GameObject logItemPrefabObj)
|
||||
{
|
||||
consolePage = page;
|
||||
logScrollRect = logScroll;
|
||||
logContent = logContentTransform;
|
||||
detailScrollRect = detailScroll;
|
||||
detailText = detail;
|
||||
clearButton = clearBtn;
|
||||
lockScrollToggle = lockToggle;
|
||||
infoFilterToggle = infoToggle;
|
||||
warningFilterToggle = warningToggle;
|
||||
errorFilterToggle = errorToggle;
|
||||
fatalFilterToggle = fatalToggle;
|
||||
textFilterInputField = textFilterInput;
|
||||
logItemPrefab = logItemPrefabObj;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDebugModule 实现
|
||||
public void Initialize()
|
||||
{
|
||||
Debug.Log("[ConsoleModule] 初始化控制台模块...");
|
||||
EnsureLogCaptureRegistered();
|
||||
|
||||
Debug.Log("[ConsoleModule] 控制台模块初始化完成");
|
||||
}
|
||||
|
||||
public GameObject GetPage()
|
||||
{
|
||||
return consolePage;
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return "控制台";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 公共方法
|
||||
/// <summary>
|
||||
/// 设置SDF字体
|
||||
/// </summary>
|
||||
public void SetSDFFont(TMP_FontAsset fontAsset)
|
||||
{
|
||||
savedFontAsset = fontAsset;
|
||||
|
||||
// 应用到详情文本
|
||||
if (detailText != null && fontAsset != null)
|
||||
{
|
||||
detailText.font = fontAsset;
|
||||
}
|
||||
|
||||
// 刷新已有日志项
|
||||
if (uiInitialized)
|
||||
{
|
||||
RefreshLogDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsurePageViewInitialized()
|
||||
{
|
||||
EnsureLogCaptureRegistered();
|
||||
|
||||
if (uiInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查必要的组件
|
||||
if (consolePage == null)
|
||||
Debug.LogError("[ConsoleModule] consolePage is null!");
|
||||
if (logScrollRect == null)
|
||||
Debug.LogError("[ConsoleModule] logScrollRect is null!");
|
||||
if (logContent == null)
|
||||
Debug.LogError("[ConsoleModule] logContent is null!");
|
||||
if (detailScrollRect == null)
|
||||
Debug.LogError("[ConsoleModule] detailScrollRect is null!");
|
||||
if (detailText == null)
|
||||
Debug.LogError("[ConsoleModule] detailText is null!");
|
||||
if (clearButton == null)
|
||||
Debug.LogError("[ConsoleModule] clearButton is null!");
|
||||
if (logItemPrefab == null)
|
||||
Debug.LogError("[ConsoleModule] logItemPrefab is null!");
|
||||
|
||||
if (clearButton != null)
|
||||
{
|
||||
clearButton.onClick.RemoveListener(ClearAllLogs);
|
||||
clearButton.onClick.AddListener(ClearAllLogs);
|
||||
}
|
||||
|
||||
if (lockScrollToggle != null)
|
||||
{
|
||||
lockScrollToggle.onValueChanged.RemoveListener(OnLockScrollChanged);
|
||||
lockScrollToggle.isOn = lockScroll;
|
||||
lockScrollToggle.onValueChanged.AddListener(OnLockScrollChanged);
|
||||
}
|
||||
|
||||
if (infoFilterToggle != null)
|
||||
{
|
||||
infoFilterToggle.onValueChanged.RemoveListener(OnInfoFilterChanged);
|
||||
infoFilterToggle.isOn = infoFilter;
|
||||
infoFilterToggle.onValueChanged.AddListener(OnInfoFilterChanged);
|
||||
infoFilterLabel = infoFilterToggle.GetComponentInChildren<TMP_Text>(true);
|
||||
}
|
||||
|
||||
if (warningFilterToggle != null)
|
||||
{
|
||||
warningFilterToggle.onValueChanged.RemoveListener(OnWarningFilterChanged);
|
||||
warningFilterToggle.isOn = warningFilter;
|
||||
warningFilterToggle.onValueChanged.AddListener(OnWarningFilterChanged);
|
||||
warningFilterLabel = warningFilterToggle.GetComponentInChildren<TMP_Text>(true);
|
||||
}
|
||||
|
||||
if (errorFilterToggle != null)
|
||||
{
|
||||
errorFilterToggle.onValueChanged.RemoveListener(OnErrorFilterChanged);
|
||||
errorFilterToggle.isOn = errorFilter;
|
||||
errorFilterToggle.onValueChanged.AddListener(OnErrorFilterChanged);
|
||||
errorFilterLabel = errorFilterToggle.GetComponentInChildren<TMP_Text>(true);
|
||||
}
|
||||
|
||||
if (fatalFilterToggle != null)
|
||||
{
|
||||
fatalFilterToggle.onValueChanged.RemoveListener(OnFatalFilterChanged);
|
||||
fatalFilterToggle.isOn = fatalFilter;
|
||||
fatalFilterToggle.onValueChanged.AddListener(OnFatalFilterChanged);
|
||||
fatalFilterLabel = fatalFilterToggle.GetComponentInChildren<TMP_Text>(true);
|
||||
}
|
||||
|
||||
if (textFilterInputField != null)
|
||||
{
|
||||
textFilterInputField.onValueChanged.RemoveListener(OnTextFilterChanged);
|
||||
textFilterInputField.text = textFilter;
|
||||
textFilterInputField.onValueChanged.AddListener(OnTextFilterChanged);
|
||||
}
|
||||
|
||||
if (detailText != null)
|
||||
detailText.text = "点击日志查看详细信息...";
|
||||
|
||||
uiInitialized = true;
|
||||
needRefresh = true;
|
||||
RefreshLogDisplay();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取日志统计信息
|
||||
/// </summary>
|
||||
public void GetLogCount(out int info, out int warning, out int error, out int fatal)
|
||||
{
|
||||
RefreshCount();
|
||||
info = infoCount;
|
||||
warning = warningCount;
|
||||
error = errorCount;
|
||||
fatal = fatalCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置各类型日志的最大缓存数量
|
||||
/// </summary>
|
||||
public void SetMaxLogLines(int maxInfo, int maxWarning, int maxError, int maxFatal)
|
||||
{
|
||||
maxInfoLines = Mathf.Max(1, maxInfo);
|
||||
maxWarningLines = Mathf.Max(1, maxWarning);
|
||||
maxErrorLines = Mathf.Max(1, maxError);
|
||||
maxFatalLines = Mathf.Max(1, maxFatal);
|
||||
Debug.Log($"[ConsoleModule] 设置缓存池大小 - Info:{maxInfoLines}, Warning:{maxWarningLines}, Error:{maxErrorLines}, Fatal:{maxFatalLines}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取各类型日志的最大缓存数量
|
||||
/// </summary>
|
||||
public void GetMaxLogLines(out int maxInfo, out int maxWarning, out int maxError, out int maxFatal)
|
||||
{
|
||||
maxInfo = maxInfoLines;
|
||||
maxWarning = maxWarningLines;
|
||||
maxError = maxErrorLines;
|
||||
maxFatal = maxFatalLines;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新(每帧调用)
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
if (!uiInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果页面未激活,跳过更新
|
||||
if (consolePage == null || !consolePage.activeSelf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 先处理延迟刷新
|
||||
if (needRefresh)
|
||||
{
|
||||
needRefresh = false;
|
||||
lastRefreshFrame = Time.frameCount;
|
||||
RefreshLogDisplay();
|
||||
}
|
||||
|
||||
// 如果锁定滚动,自动滚动到底部
|
||||
// 只在刷新后的下一帧设置,避免rebuild loop
|
||||
if (lockScroll && logScrollRect != null && Time.frameCount > lastRefreshFrame + 1)
|
||||
{
|
||||
logScrollRect.verticalNormalizedPosition = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁
|
||||
/// </summary>
|
||||
public void Shutdown()
|
||||
{
|
||||
if (hasRegisteredLogCallback)
|
||||
{
|
||||
Application.logMessageReceived -= OnLogMessageReceived;
|
||||
hasRegisteredLogCallback = false;
|
||||
}
|
||||
|
||||
ClearAllLogs();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
private void EnsureLogCaptureRegistered()
|
||||
{
|
||||
if (hasRegisteredLogCallback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Application.logMessageReceived += OnLogMessageReceived;
|
||||
hasRegisteredLogCallback = true;
|
||||
}
|
||||
|
||||
private void OnLogMessageReceived(string logMessage, string stackTrace, LogType logType)
|
||||
{
|
||||
// 将Assert转换为Error
|
||||
if (logType == LogType.Assert)
|
||||
{
|
||||
logType = LogType.Error;
|
||||
}
|
||||
|
||||
// 创建日志节点
|
||||
LogNode logNode = LogNode.Create(logType, logMessage, stackTrace);
|
||||
|
||||
// 根据类型添加到对应的缓存池
|
||||
Queue<LogNode> targetQueue = null;
|
||||
int maxLines = 0;
|
||||
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Log:
|
||||
targetQueue = infoLogNodes;
|
||||
maxLines = maxInfoLines;
|
||||
break;
|
||||
case LogType.Warning:
|
||||
targetQueue = warningLogNodes;
|
||||
maxLines = maxWarningLines;
|
||||
break;
|
||||
case LogType.Error:
|
||||
targetQueue = errorLogNodes;
|
||||
maxLines = maxErrorLines;
|
||||
break;
|
||||
case LogType.Exception:
|
||||
targetQueue = fatalLogNodes;
|
||||
maxLines = maxFatalLines;
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetQueue != null)
|
||||
{
|
||||
targetQueue.Enqueue(logNode);
|
||||
|
||||
// 限制该类型的最大行数
|
||||
while (targetQueue.Count > maxLines)
|
||||
{
|
||||
targetQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
// 标记需要刷新,而不是立即刷新(避免rebuild loop)
|
||||
needRefresh = true;
|
||||
}
|
||||
|
||||
private void RefreshLogDisplay()
|
||||
{
|
||||
if (!uiInitialized)
|
||||
{
|
||||
needRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果页面未激活,延迟刷新到下次页面激活时
|
||||
if (consolePage == null || !consolePage.activeSelf)
|
||||
{
|
||||
needRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (logContent == null)
|
||||
{
|
||||
Debug.LogError("[ConsoleModule] logContent is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (logItemPrefab == null)
|
||||
{
|
||||
Debug.LogError("[ConsoleModule] logItemPrefab is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 回收所有激活的日志项
|
||||
foreach (var item in activeLogItems)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
item.SetActive(false);
|
||||
if (!logItemPool.Contains(item))
|
||||
{
|
||||
logItemPool.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
activeLogItems.Clear();
|
||||
|
||||
// 遍历日志节点并创建UI(性能优化:只为需要显示的日志创建LogItem)
|
||||
int index = 0;
|
||||
int displayCount = 0;
|
||||
|
||||
// 合并所有缓存池的日志,按时间排序
|
||||
List<LogNode> allLogs = new List<LogNode>();
|
||||
allLogs.AddRange(infoLogNodes);
|
||||
allLogs.AddRange(warningLogNodes);
|
||||
allLogs.AddRange(errorLogNodes);
|
||||
allLogs.AddRange(fatalLogNodes);
|
||||
allLogs.Sort((a, b) => a.LogTime.CompareTo(b.LogTime));
|
||||
|
||||
foreach (LogNode logNode in allLogs)
|
||||
{
|
||||
// 根据过滤器判断是否显示,如果不显示则跳过创建LogItem
|
||||
if (!ShouldShowLog(logNode))
|
||||
continue;
|
||||
|
||||
// 从对象池获取或创建日志项
|
||||
GameObject logItem = GetLogItemFromPool();
|
||||
if (logItem == null)
|
||||
{
|
||||
Debug.LogError("[ConsoleModule] Failed to get log item from pool!");
|
||||
continue;
|
||||
}
|
||||
|
||||
logItem.transform.SetParent(logContent, false);
|
||||
logItem.SetActive(true);
|
||||
activeLogItems.Add(logItem);
|
||||
|
||||
// 调试:确认对象状态
|
||||
if (!logItem.activeSelf)
|
||||
{
|
||||
Debug.LogWarning($"[ConsoleModule] LogItem {logItem.name} is not active after SetActive(true)!");
|
||||
}
|
||||
|
||||
// 设置日志项内容
|
||||
SetupLogItem(logItem, logNode, index);
|
||||
|
||||
index++;
|
||||
displayCount++;
|
||||
}
|
||||
|
||||
UpdateFilterToggleText();
|
||||
}
|
||||
|
||||
private bool ShouldShowLog(LogNode logNode)
|
||||
{
|
||||
// 首先检查类型筛选
|
||||
bool typeMatch = false;
|
||||
switch (logNode.LogType)
|
||||
{
|
||||
case LogType.Log:
|
||||
typeMatch = infoFilter;
|
||||
break;
|
||||
case LogType.Warning:
|
||||
typeMatch = warningFilter;
|
||||
break;
|
||||
case LogType.Error:
|
||||
typeMatch = errorFilter;
|
||||
break;
|
||||
case LogType.Exception:
|
||||
typeMatch = fatalFilter;
|
||||
break;
|
||||
default:
|
||||
typeMatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!typeMatch)
|
||||
return false;
|
||||
|
||||
// 然后检查文字筛选
|
||||
if (!string.IsNullOrEmpty(textFilter))
|
||||
{
|
||||
// 如果日志消息不包含筛选文字,则不显示
|
||||
if (!logNode.LogMessage.Contains(textFilter))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private GameObject GetLogItemFromPool()
|
||||
{
|
||||
if (logItemPool.Count > 0)
|
||||
{
|
||||
GameObject item = logItemPool[0];
|
||||
logItemPool.RemoveAt(0);
|
||||
return item;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logItemPrefab == null)
|
||||
{
|
||||
Debug.LogError("[ConsoleModule] logItemPrefab is null!");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 创建新的日志项
|
||||
GameObject newItem = UnityEngine.Object.Instantiate(logItemPrefab);
|
||||
newItem.name = "LogItem_" + activeLogItems.Count;
|
||||
return newItem;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupLogItem(GameObject logItem, LogNode logNode, int index)
|
||||
{
|
||||
if (logItem == null)
|
||||
{
|
||||
Debug.LogError("[ConsoleModule] logItem is null in SetupLogItem!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取日志项的Toggle和Text组件
|
||||
Toggle toggle = logItem.GetComponent<Toggle>();
|
||||
TMP_Text text = logItem.GetComponentInChildren<TMP_Text>();
|
||||
|
||||
if (toggle == null)
|
||||
{
|
||||
Debug.LogWarning($"[ConsoleModule] Toggle component not found on {logItem.name}!");
|
||||
}
|
||||
|
||||
if (text == null)
|
||||
{
|
||||
Debug.LogWarning($"[ConsoleModule] TMP_Text component not found on {logItem.name}!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置文本内容和颜色
|
||||
Color32 color = GetLogStringColor(logNode.LogType);
|
||||
string logText = GetLogString(logNode);
|
||||
|
||||
text.text = logText;
|
||||
text.color = color;
|
||||
|
||||
// 应用字体
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
text.font = savedFontAsset;
|
||||
}
|
||||
|
||||
if (toggle != null)
|
||||
{
|
||||
// 设置Toggle状态
|
||||
toggle.isOn = (selectedNode == logNode);
|
||||
|
||||
// 设置Toggle事件
|
||||
toggle.onValueChanged.RemoveAllListeners();
|
||||
toggle.onValueChanged.AddListener((isOn) =>
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
OnLogItemSelected(logNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLogItemSelected(LogNode logNode)
|
||||
{
|
||||
selectedNode = logNode;
|
||||
|
||||
// 显示详细信息
|
||||
if (detailText != null && logNode != null)
|
||||
{
|
||||
Color32 color = GetLogStringColor(logNode.LogType);
|
||||
string colorHex = ColorUtility.ToHtmlStringRGBA(color);
|
||||
|
||||
string detailInfo = $"<color=#{colorHex}><b>{logNode.LogMessage}</b></color>\n\n";
|
||||
detailInfo += $"<color=#888888>时间: {logNode.LogTime.ToLocalTime():HH:mm:ss.fff}\n";
|
||||
detailInfo += $"帧数: {logNode.LogFrameCount}\n";
|
||||
detailInfo += $"类型: {logNode.LogType}</color>\n\n";
|
||||
|
||||
if (!string.IsNullOrEmpty(logNode.StackTrace))
|
||||
{
|
||||
detailInfo += $"<color=#AAAAAA>堆栈跟踪:\n{logNode.StackTrace}</color>";
|
||||
}
|
||||
|
||||
detailText.text = detailInfo;
|
||||
}
|
||||
|
||||
// 重置详情滚动位置
|
||||
if (detailScrollRect != null)
|
||||
{
|
||||
detailScrollRect.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetLogString(LogNode logNode)
|
||||
{
|
||||
return $"[{logNode.LogTime.ToLocalTime():HH:mm:ss.fff}][{logNode.LogFrameCount}] {logNode.LogMessage}";
|
||||
}
|
||||
|
||||
private Color32 GetLogStringColor(LogType logType)
|
||||
{
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Log:
|
||||
return infoColor;
|
||||
case LogType.Warning:
|
||||
return warningColor;
|
||||
case LogType.Error:
|
||||
return errorColor;
|
||||
case LogType.Exception:
|
||||
return fatalColor;
|
||||
default:
|
||||
return Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshCount()
|
||||
{
|
||||
infoCount = infoLogNodes.Count;
|
||||
warningCount = warningLogNodes.Count;
|
||||
errorCount = errorLogNodes.Count;
|
||||
fatalCount = fatalLogNodes.Count;
|
||||
}
|
||||
|
||||
private void UpdateFilterToggleText()
|
||||
{
|
||||
if (!uiInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshCount();
|
||||
|
||||
UpdateFilterLabel(infoFilterLabel, "Info", infoCount, ref lastDisplayedInfoCount);
|
||||
UpdateFilterLabel(warningFilterLabel, "Warning", warningCount, ref lastDisplayedWarningCount);
|
||||
UpdateFilterLabel(errorFilterLabel, "Error", errorCount, ref lastDisplayedErrorCount);
|
||||
UpdateFilterLabel(fatalFilterLabel, "Fatal", fatalCount, ref lastDisplayedFatalCount);
|
||||
}
|
||||
|
||||
private void UpdateFilterLabel(TMP_Text label, string prefix, int count, ref int lastDisplayedCount)
|
||||
{
|
||||
if (label == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastDisplayedCount == count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
label.text = $"{prefix} ({count})";
|
||||
lastDisplayedCount = count;
|
||||
}
|
||||
|
||||
private void ClearAllLogs()
|
||||
{
|
||||
infoLogNodes.Clear();
|
||||
warningLogNodes.Clear();
|
||||
errorLogNodes.Clear();
|
||||
fatalLogNodes.Clear();
|
||||
selectedNode = null;
|
||||
lastDisplayedInfoCount = -1;
|
||||
lastDisplayedWarningCount = -1;
|
||||
lastDisplayedErrorCount = -1;
|
||||
lastDisplayedFatalCount = -1;
|
||||
|
||||
if (detailText != null)
|
||||
detailText.text = "点击日志查看详细信息...";
|
||||
|
||||
RefreshLogDisplay();
|
||||
|
||||
Debug.Log("[ConsoleModule] 已清空所有日志");
|
||||
}
|
||||
|
||||
private void OnLockScrollChanged(bool value)
|
||||
{
|
||||
lockScroll = value;
|
||||
}
|
||||
|
||||
private void OnInfoFilterChanged(bool value)
|
||||
{
|
||||
infoFilter = value;
|
||||
needRefresh = true;
|
||||
}
|
||||
|
||||
private void OnWarningFilterChanged(bool value)
|
||||
{
|
||||
warningFilter = value;
|
||||
needRefresh = true;
|
||||
}
|
||||
|
||||
private void OnErrorFilterChanged(bool value)
|
||||
{
|
||||
errorFilter = value;
|
||||
needRefresh = true;
|
||||
}
|
||||
|
||||
private void OnFatalFilterChanged(bool value)
|
||||
{
|
||||
fatalFilter = value;
|
||||
needRefresh = true;
|
||||
}
|
||||
|
||||
private void OnTextFilterChanged(string value)
|
||||
{
|
||||
textFilter = value;
|
||||
needRefresh = true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1660ec87345f07e4992b23d662f497dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b567af0f535ece48be5c25d68c5a311
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,727 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义复选框模块 - 通过反射加载标记为DebugCheckBox的方法
|
||||
/// </summary>
|
||||
public class CustomCheckBoxesModule : IDebugModule
|
||||
{
|
||||
#region 字段
|
||||
private const float SubTabCellWidth = 200f;
|
||||
private const float SubTabCellHeight = 70f;
|
||||
private const float SubTabSpacingX = 8f;
|
||||
private const float SubTabSpacingY = 8f;
|
||||
private const int SubTabPaddingHorizontal = 20;
|
||||
private const int SubTabPaddingVertical = 20;
|
||||
|
||||
private GameObject customCheckBoxesPage;
|
||||
private RectTransform checkBoxContainer;
|
||||
private GameObject checkBoxPrefab;
|
||||
private ScrollRect checkBoxesScrollRect;
|
||||
|
||||
// 保存的SDF字体资源
|
||||
private TMP_FontAsset savedFontAsset = null;
|
||||
|
||||
// 保存每个复选框的状态
|
||||
private Dictionary<string, bool> checkBoxStates = new Dictionary<string, bool>();
|
||||
|
||||
// Tab相关
|
||||
private Dictionary<string, List<CheckBoxInfo>> tabGroups = new Dictionary<string, List<CheckBoxInfo>>();
|
||||
private Dictionary<string, GameObject> tabPanels = new Dictionary<string, GameObject>();
|
||||
private Dictionary<string, Color> tabColors = new Dictionary<string, Color>();
|
||||
private List<Button> subTabButtons = new List<Button>();
|
||||
private string currentSubTab = string.Empty;
|
||||
private bool checkBoxDefinitionsDirty = true;
|
||||
private bool checkBoxViewInitialized = false;
|
||||
private HashSet<string> builtSubTabs = new HashSet<string>();
|
||||
private GameObject subTabBarObject;
|
||||
private GameObject tabContentRootObject;
|
||||
#endregion
|
||||
|
||||
#region 内部类
|
||||
private class CheckBoxInfo
|
||||
{
|
||||
public MethodInfo Method;
|
||||
public DebugCheckBoxAttribute Attribute;
|
||||
public string TabName;
|
||||
}
|
||||
#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] 初始化自定义复选框模块...");
|
||||
checkBoxDefinitionsDirty = true;
|
||||
checkBoxViewInitialized = false;
|
||||
}
|
||||
|
||||
public GameObject GetPage()
|
||||
{
|
||||
return customCheckBoxesPage;
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return "开关";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 公共方法
|
||||
/// <summary>
|
||||
/// 设置SDF字体
|
||||
/// </summary>
|
||||
public void SetSDFFont(TMP_FontAsset fontAsset)
|
||||
{
|
||||
savedFontAsset = fontAsset;
|
||||
ApplyFontToExistingUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新加载自定义复选框
|
||||
/// </summary>
|
||||
public void ReloadCustomCheckBoxes()
|
||||
{
|
||||
ReloadCheckBoxDefinitions();
|
||||
InvalidateCheckBoxView();
|
||||
|
||||
if (customCheckBoxesPage != null && customCheckBoxesPage.activeInHierarchy)
|
||||
{
|
||||
EnsurePageViewInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsurePageViewInitialized()
|
||||
{
|
||||
if (checkBoxDefinitionsDirty)
|
||||
{
|
||||
ReloadCheckBoxDefinitions();
|
||||
}
|
||||
|
||||
if (!checkBoxViewInitialized)
|
||||
{
|
||||
BuildCheckBoxViewSkeleton();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(currentSubTab) && tabGroups.Count > 0)
|
||||
{
|
||||
currentSubTab = tabGroups.OrderBy(kvp => kvp.Key == "默认" ? string.Empty : kvp.Key).First().Key;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(currentSubTab))
|
||||
{
|
||||
EnsureSubTabContentBuilt(currentSubTab);
|
||||
}
|
||||
|
||||
UpdateSubTabButtonStyles();
|
||||
}
|
||||
|
||||
private void ApplyFontToExistingUI()
|
||||
{
|
||||
if (savedFontAsset == null || customCheckBoxesPage == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TMP_Text[] texts = customCheckBoxesPage.GetComponentsInChildren<TMP_Text>(true);
|
||||
foreach (TMP_Text text in texts)
|
||||
{
|
||||
text.font = savedFontAsset;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
/// <summary>
|
||||
/// 加载所有自定义复选框(使用反射)
|
||||
/// </summary>
|
||||
private void ReloadCheckBoxDefinitions()
|
||||
{
|
||||
if (checkBoxContainer == null || checkBoxPrefab == null)
|
||||
{
|
||||
Debug.LogWarning("[CustomCheckBoxesModule] 复选框容器或复选框预制件未设置");
|
||||
return;
|
||||
}
|
||||
|
||||
tabGroups.Clear();
|
||||
tabColors.Clear();
|
||||
|
||||
// 查找所有标记为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<DebugCheckBoxAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
var classAttribute = type.GetCustomAttribute<DebugCheckBoxClassAttribute>(true);
|
||||
string tabName = ResolveTabName(attribute, classAttribute);
|
||||
Color tabColor = ResolveTabColor(classAttribute);
|
||||
|
||||
RegisterTabColor(tabName, tabColor);
|
||||
|
||||
if (!tabGroups.ContainsKey(tabName))
|
||||
{
|
||||
tabGroups[tabName] = new List<CheckBoxInfo>();
|
||||
}
|
||||
|
||||
tabGroups[tabName].Add(new CheckBoxInfo
|
||||
{
|
||||
Method = method,
|
||||
Attribute = attribute,
|
||||
TabName = tabName
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// 某些程序集可能无法访问,跳过
|
||||
Debug.LogWarning($"[CustomCheckBoxesModule] 无法访问程序集 {assembly.FullName}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"[CustomCheckBoxesModule] 共找到 {tabGroups.Count} 个Tab");
|
||||
foreach (var tab in tabGroups)
|
||||
{
|
||||
Debug.Log($" - Tab: {tab.Key}, 开关数: {tab.Value.Count}");
|
||||
}
|
||||
|
||||
checkBoxDefinitionsDirty = false;
|
||||
}
|
||||
|
||||
private string ResolveTabName(DebugCheckBoxAttribute methodAttribute, DebugCheckBoxClassAttribute classAttribute)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(methodAttribute.TabName))
|
||||
{
|
||||
return methodAttribute.TabName;
|
||||
}
|
||||
|
||||
if (classAttribute != null && !string.IsNullOrEmpty(classAttribute.TabName))
|
||||
{
|
||||
return classAttribute.TabName;
|
||||
}
|
||||
|
||||
return "默认";
|
||||
}
|
||||
|
||||
private Color ResolveTabColor(DebugCheckBoxClassAttribute classAttribute)
|
||||
{
|
||||
if (classAttribute != null)
|
||||
{
|
||||
return classAttribute.TabColor;
|
||||
}
|
||||
|
||||
return new Color(0.2f, 0.6f, 1f, 1f);
|
||||
}
|
||||
|
||||
private void RegisterTabColor(string tabName, Color tabColor)
|
||||
{
|
||||
if (!tabColors.ContainsKey(tabName))
|
||||
{
|
||||
tabColors[tabName] = tabColor;
|
||||
return;
|
||||
}
|
||||
|
||||
Color existing = tabColors[tabName];
|
||||
if (!Mathf.Approximately(existing.r, tabColor.r) ||
|
||||
!Mathf.Approximately(existing.g, tabColor.g) ||
|
||||
!Mathf.Approximately(existing.b, tabColor.b) ||
|
||||
!Mathf.Approximately(existing.a, tabColor.a))
|
||||
{
|
||||
Debug.LogWarning($"[CustomCheckBoxesModule] Tab '{tabName}' 检测到多个颜色定义,已保留第一个颜色配置");
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildCheckBoxViewSkeleton()
|
||||
{
|
||||
InvalidateCheckBoxView();
|
||||
SetupCheckBoxContainerLayout();
|
||||
|
||||
if (tabGroups.Count == 0)
|
||||
{
|
||||
GameObject emptyText = new GameObject("EmptyTip");
|
||||
emptyText.transform.SetParent(checkBoxContainer, false);
|
||||
TMP_Text text = emptyText.AddComponent<TextMeshProUGUI>();
|
||||
text.text = "未找到任何 DebugCheckBox";
|
||||
text.fontSize = 28;
|
||||
text.fontStyle = FontStyles.Bold;
|
||||
text.enableAutoSizing = true;
|
||||
text.fontSizeMin = 12;
|
||||
text.fontSizeMax = 72;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.color = new Color(1f, 1f, 1f, 0.8f);
|
||||
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
text.font = savedFontAsset;
|
||||
}
|
||||
|
||||
LayoutElement element = emptyText.AddComponent<LayoutElement>();
|
||||
element.preferredHeight = 80;
|
||||
checkBoxViewInitialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
subTabBarObject = CreateSubTabBar();
|
||||
|
||||
tabContentRootObject = new GameObject("SubTabContentRoot");
|
||||
tabContentRootObject.transform.SetParent(checkBoxContainer, false);
|
||||
|
||||
RectTransform contentRootRect = tabContentRootObject.AddComponent<RectTransform>();
|
||||
contentRootRect.anchorMin = new Vector2(0, 1);
|
||||
contentRootRect.anchorMax = new Vector2(1, 1);
|
||||
contentRootRect.pivot = new Vector2(0.5f, 1f);
|
||||
|
||||
VerticalLayoutGroup contentRootLayout = tabContentRootObject.AddComponent<VerticalLayoutGroup>();
|
||||
contentRootLayout.childForceExpandWidth = true;
|
||||
contentRootLayout.childForceExpandHeight = false;
|
||||
contentRootLayout.childControlWidth = true;
|
||||
contentRootLayout.childControlHeight = false;
|
||||
contentRootLayout.spacing = 0;
|
||||
contentRootLayout.padding = new RectOffset(0, 0, 0, 0);
|
||||
|
||||
ContentSizeFitter contentRootFitter = tabContentRootObject.AddComponent<ContentSizeFitter>();
|
||||
contentRootFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
contentRootFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
|
||||
LayoutElement contentRootElement = tabContentRootObject.AddComponent<LayoutElement>();
|
||||
contentRootElement.flexibleWidth = 1;
|
||||
|
||||
var sortedTabs = tabGroups.OrderBy(kvp => kvp.Key == "默认" ? string.Empty : kvp.Key);
|
||||
bool firstTab = true;
|
||||
|
||||
foreach (var tab in sortedTabs)
|
||||
{
|
||||
string tabName = tab.Key;
|
||||
CreateSubTabButton(tabName, subTabBarObject.transform);
|
||||
|
||||
GameObject tabPanel = CreateTabPanel(tabName, tabContentRootObject.transform);
|
||||
tabPanels[tabName] = tabPanel;
|
||||
|
||||
tabPanel.SetActive(firstTab);
|
||||
if (firstTab)
|
||||
{
|
||||
currentSubTab = tabName;
|
||||
firstTab = false;
|
||||
}
|
||||
}
|
||||
|
||||
Canvas.ForceUpdateCanvases();
|
||||
UpdateSubTabBarHeight(subTabBarObject);
|
||||
|
||||
UpdateSubTabButtonStyles();
|
||||
|
||||
if (checkBoxesScrollRect != null)
|
||||
{
|
||||
Canvas.ForceUpdateCanvases();
|
||||
checkBoxesScrollRect.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
|
||||
checkBoxViewInitialized = true;
|
||||
}
|
||||
|
||||
private void EnsureSubTabContentBuilt(string tabName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tabName) || builtSubTabs.Contains(tabName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tabPanels.TryGetValue(tabName, out GameObject tabPanel) || tabPanel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tabGroups.TryGetValue(tabName, out List<CheckBoxInfo> checkBoxes))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var checkBoxInfo in checkBoxes)
|
||||
{
|
||||
CreateCustomCheckBox(checkBoxInfo.Method, checkBoxInfo.Attribute, tabPanel.transform);
|
||||
}
|
||||
|
||||
builtSubTabs.Add(tabName);
|
||||
Canvas.ForceUpdateCanvases();
|
||||
}
|
||||
|
||||
private void InvalidateCheckBoxView()
|
||||
{
|
||||
if (checkBoxContainer != null)
|
||||
{
|
||||
foreach (Transform child in checkBoxContainer)
|
||||
{
|
||||
UnityEngine.Object.Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
tabPanels.Clear();
|
||||
subTabButtons.Clear();
|
||||
builtSubTabs.Clear();
|
||||
currentSubTab = string.Empty;
|
||||
subTabBarObject = null;
|
||||
tabContentRootObject = null;
|
||||
checkBoxViewInitialized = false;
|
||||
}
|
||||
|
||||
private GameObject CreateSubTabBar()
|
||||
{
|
||||
GameObject subTabBar = new GameObject("SubTabBar");
|
||||
subTabBar.transform.SetParent(checkBoxContainer, false);
|
||||
|
||||
RectTransform rectTransform = subTabBar.AddComponent<RectTransform>();
|
||||
rectTransform.anchorMin = new Vector2(0, 1);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
rectTransform.pivot = new Vector2(0.5f, 1f);
|
||||
|
||||
Image bg = subTabBar.AddComponent<Image>();
|
||||
bg.color = new Color(0.15f, 0.15f, 0.15f, 0.8f);
|
||||
|
||||
GridLayoutGroup layout = subTabBar.AddComponent<GridLayoutGroup>();
|
||||
layout.cellSize = new Vector2(SubTabCellWidth, SubTabCellHeight);
|
||||
layout.spacing = new Vector2(SubTabSpacingX, SubTabSpacingY);
|
||||
layout.padding = new RectOffset(10, 10, 10, 10);
|
||||
layout.constraint = GridLayoutGroup.Constraint.Flexible;
|
||||
layout.startAxis = GridLayoutGroup.Axis.Horizontal;
|
||||
layout.startCorner = GridLayoutGroup.Corner.UpperLeft;
|
||||
layout.childAlignment = TextAnchor.UpperLeft;
|
||||
|
||||
ContentSizeFitter fitter = subTabBar.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
|
||||
LayoutElement element = subTabBar.AddComponent<LayoutElement>();
|
||||
element.minHeight = 80;
|
||||
element.preferredHeight = 80;
|
||||
element.flexibleWidth = 1;
|
||||
|
||||
return subTabBar;
|
||||
}
|
||||
|
||||
private void CreateSubTabButton(string tabName, Transform parent)
|
||||
{
|
||||
GameObject tabButtonObj = new GameObject($"SubTab_{tabName}");
|
||||
tabButtonObj.transform.SetParent(parent, false);
|
||||
|
||||
RectTransform rect = tabButtonObj.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = new Vector2(200, 56);
|
||||
|
||||
Image image = tabButtonObj.AddComponent<Image>();
|
||||
image.color = GetInactiveTabColor(tabName);
|
||||
|
||||
Button button = tabButtonObj.AddComponent<Button>();
|
||||
|
||||
GameObject textObj = new GameObject("Text");
|
||||
textObj.transform.SetParent(tabButtonObj.transform, false);
|
||||
RectTransform textRect = textObj.AddComponent<RectTransform>();
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.offsetMin = Vector2.zero;
|
||||
textRect.offsetMax = Vector2.zero;
|
||||
|
||||
TMP_Text text = textObj.AddComponent<TextMeshProUGUI>();
|
||||
text.text = tabName;
|
||||
text.fontSize = 26;
|
||||
text.fontStyle = FontStyles.Bold;
|
||||
text.enableAutoSizing = true;
|
||||
text.fontSizeMin = 12;
|
||||
text.fontSizeMax = 72;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.color = Color.white;
|
||||
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
text.font = savedFontAsset;
|
||||
}
|
||||
|
||||
LayoutElement element = tabButtonObj.AddComponent<LayoutElement>();
|
||||
element.preferredWidth = SubTabCellWidth;
|
||||
element.minWidth = SubTabCellWidth;
|
||||
element.preferredHeight = SubTabCellHeight;
|
||||
|
||||
button.onClick.AddListener(() => SelectSubTab(tabName));
|
||||
subTabButtons.Add(button);
|
||||
}
|
||||
|
||||
private void UpdateSubTabBarHeight(GameObject subTabBar)
|
||||
{
|
||||
if (subTabBar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RectTransform subTabRect = subTabBar.GetComponent<RectTransform>();
|
||||
LayoutElement layoutElement = subTabBar.GetComponent<LayoutElement>();
|
||||
if (subTabRect == null || layoutElement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float availableWidth = subTabRect.rect.width;
|
||||
if (availableWidth <= 0f && checkBoxContainer != null)
|
||||
{
|
||||
availableWidth = checkBoxContainer.rect.width;
|
||||
}
|
||||
|
||||
if (availableWidth <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float usableWidth = Mathf.Max(1f, availableWidth - SubTabPaddingHorizontal);
|
||||
int columnCount = Mathf.Max(1, Mathf.FloorToInt((usableWidth + SubTabSpacingX) / (SubTabCellWidth + SubTabSpacingX)));
|
||||
int rowCount = Mathf.Max(1, Mathf.CeilToInt((float)subTabButtons.Count / columnCount));
|
||||
float preferredHeight = SubTabPaddingVertical + rowCount * SubTabCellHeight + Mathf.Max(0, rowCount - 1) * SubTabSpacingY;
|
||||
|
||||
layoutElement.minHeight = preferredHeight;
|
||||
layoutElement.preferredHeight = preferredHeight;
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(subTabRect);
|
||||
}
|
||||
|
||||
private GameObject CreateTabPanel(string tabName, Transform parent)
|
||||
{
|
||||
GameObject panel = new GameObject($"Panel_{tabName}");
|
||||
panel.transform.SetParent(parent, false);
|
||||
|
||||
RectTransform rectTransform = panel.AddComponent<RectTransform>();
|
||||
rectTransform.anchorMin = new Vector2(0, 1);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
rectTransform.pivot = new Vector2(0.5f, 1f);
|
||||
|
||||
VerticalLayoutGroup layout = panel.AddComponent<VerticalLayoutGroup>();
|
||||
layout.childForceExpandWidth = true;
|
||||
layout.childForceExpandHeight = false;
|
||||
layout.childControlWidth = true;
|
||||
layout.childControlHeight = false;
|
||||
layout.spacing = 15;
|
||||
layout.padding = new RectOffset(0, 0, 10, 10);
|
||||
|
||||
ContentSizeFitter fitter = panel.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
|
||||
LayoutElement element = panel.AddComponent<LayoutElement>();
|
||||
element.flexibleWidth = 1;
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void SelectSubTab(string tabName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tabName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureSubTabContentBuilt(tabName);
|
||||
|
||||
if (currentSubTab == tabName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentSubTab = tabName;
|
||||
|
||||
foreach (var kvp in tabPanels)
|
||||
{
|
||||
kvp.Value.SetActive(kvp.Key == tabName);
|
||||
}
|
||||
|
||||
UpdateSubTabButtonStyles();
|
||||
|
||||
if (checkBoxesScrollRect != null)
|
||||
{
|
||||
Canvas.ForceUpdateCanvases();
|
||||
checkBoxesScrollRect.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSubTabButtonStyles()
|
||||
{
|
||||
foreach (var button in subTabButtons)
|
||||
{
|
||||
if (button == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string tabName = button.gameObject.name.Replace("SubTab_", string.Empty);
|
||||
Image image = button.GetComponent<Image>();
|
||||
if (image != null)
|
||||
{
|
||||
image.color = tabName == currentSubTab
|
||||
? GetActiveTabColor(tabName)
|
||||
: GetInactiveTabColor(tabName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Color GetActiveTabColor(string tabName)
|
||||
{
|
||||
if (tabColors.TryGetValue(tabName, out var color))
|
||||
{
|
||||
color.a = 0.95f;
|
||||
return color;
|
||||
}
|
||||
|
||||
return new Color(0.2f, 0.6f, 1f, 0.95f);
|
||||
}
|
||||
|
||||
private Color GetInactiveTabColor(string tabName)
|
||||
{
|
||||
Color activeColor = GetActiveTabColor(tabName);
|
||||
Color inactive = Color.Lerp(new Color(0.18f, 0.18f, 0.18f, 0.9f), activeColor, 0.35f);
|
||||
inactive.a = 0.9f;
|
||||
return inactive;
|
||||
}
|
||||
|
||||
private void SetupCheckBoxContainerLayout()
|
||||
{
|
||||
if (checkBoxContainer == null)
|
||||
{
|
||||
Debug.LogError("[CustomCheckBoxesModule] checkBoxContainer 为 null,无法设置布局");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject containerObject = checkBoxContainer.gameObject;
|
||||
|
||||
GridLayoutGroup gridLayout = containerObject.GetComponent<GridLayoutGroup>();
|
||||
if (gridLayout != null)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(gridLayout);
|
||||
}
|
||||
|
||||
HorizontalLayoutGroup horizontalLayout = containerObject.GetComponent<HorizontalLayoutGroup>();
|
||||
if (horizontalLayout != null)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(horizontalLayout);
|
||||
}
|
||||
|
||||
VerticalLayoutGroup verticalLayout = containerObject.GetComponent<VerticalLayoutGroup>();
|
||||
if (verticalLayout == null)
|
||||
{
|
||||
verticalLayout = containerObject.AddComponent<VerticalLayoutGroup>();
|
||||
}
|
||||
|
||||
verticalLayout.childForceExpandWidth = true;
|
||||
verticalLayout.childForceExpandHeight = false;
|
||||
verticalLayout.childControlWidth = true;
|
||||
verticalLayout.childControlHeight = false;
|
||||
verticalLayout.spacing = 15;
|
||||
verticalLayout.padding = new RectOffset(20, 20, 20, 20);
|
||||
|
||||
ContentSizeFitter sizeFitter = containerObject.GetComponent<ContentSizeFitter>();
|
||||
if (sizeFitter == null)
|
||||
{
|
||||
sizeFitter = containerObject.AddComponent<ContentSizeFitter>();
|
||||
}
|
||||
|
||||
sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
sizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
}
|
||||
|
||||
private void CreateCustomCheckBox(MethodInfo method, DebugCheckBoxAttribute attribute, Transform parent)
|
||||
{
|
||||
// 验证方法签名:必须接受一个 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, parent);
|
||||
RectTransform checkBoxRect = checkBoxObj.GetComponent<RectTransform>();
|
||||
if (checkBoxRect != null)
|
||||
{
|
||||
LayoutElement layoutElement = checkBoxObj.GetComponent<LayoutElement>();
|
||||
if (layoutElement == null)
|
||||
{
|
||||
layoutElement = checkBoxObj.AddComponent<LayoutElement>();
|
||||
}
|
||||
|
||||
layoutElement.preferredHeight = checkBoxRect.sizeDelta.y > 0 ? checkBoxRect.sizeDelta.y : 80f;
|
||||
layoutElement.flexibleWidth = 1f;
|
||||
}
|
||||
|
||||
Toggle toggle = checkBoxObj.GetComponent<Toggle>();
|
||||
TMP_Text labelText = checkBoxObj.GetComponentInChildren<TMP_Text>();
|
||||
Image backgroundImage = checkBoxObj.GetComponent<Image>();
|
||||
|
||||
// 设置复选框文本
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8d7e036c6d4b2d4083addffa8c87eb8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,992 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义数值模块 - 通过反射加载标记为DebugValue的方法
|
||||
/// </summary>
|
||||
public class CustomValuesModule : IDebugModule
|
||||
{
|
||||
#region 字段
|
||||
private const float SubTabCellWidth = 200f;
|
||||
private const float SubTabCellHeight = 70f;
|
||||
private const float SubTabSpacingX = 8f;
|
||||
private const float SubTabSpacingY = 8f;
|
||||
private const int SubTabPaddingHorizontal = 20;
|
||||
private const int SubTabPaddingVertical = 20;
|
||||
|
||||
private GameObject customValuesPage;
|
||||
private RectTransform valueContainer;
|
||||
private GameObject valuePrefab;
|
||||
private ScrollRect valuesScrollRect;
|
||||
|
||||
// 保存的SDF字体资源
|
||||
private TMP_FontAsset savedFontAsset = null;
|
||||
|
||||
// 保存每个数值的当前值
|
||||
private Dictionary<string, int> valueStates = new Dictionary<string, int>();
|
||||
|
||||
// 保存每个数值的滑动条和输入框引用(用于动态更新范围)
|
||||
private Dictionary<string, ValueControlData> valueControls = new Dictionary<string, ValueControlData>();
|
||||
|
||||
// Tab相关
|
||||
private Dictionary<string, List<ValueInfo>> tabGroups = new Dictionary<string, List<ValueInfo>>();
|
||||
private Dictionary<string, GameObject> tabPanels = new Dictionary<string, GameObject>();
|
||||
private Dictionary<string, Color> tabColors = new Dictionary<string, Color>();
|
||||
private List<Button> subTabButtons = new List<Button>();
|
||||
private string currentSubTab = string.Empty;
|
||||
private bool valueDefinitionsDirty = true;
|
||||
private bool valueViewInitialized = false;
|
||||
private HashSet<string> builtSubTabs = new HashSet<string>();
|
||||
private GameObject subTabBarObject;
|
||||
private GameObject tabContentRootObject;
|
||||
|
||||
// 关闭窗口回调
|
||||
private Action onCloseWindowCallback;
|
||||
|
||||
/// <summary>
|
||||
/// 数值控件数据结构
|
||||
/// </summary>
|
||||
private class ValueControlData
|
||||
{
|
||||
public Slider slider;
|
||||
public TMP_InputField inputField;
|
||||
public MethodInfo method;
|
||||
public DebugValueAttribute attribute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数值信息
|
||||
/// </summary>
|
||||
private class ValueInfo
|
||||
{
|
||||
public MethodInfo Method;
|
||||
public DebugValueAttribute Attribute;
|
||||
public string TabName;
|
||||
}
|
||||
#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] 初始化自定义数值模块...");
|
||||
valueDefinitionsDirty = true;
|
||||
valueViewInitialized = false;
|
||||
}
|
||||
|
||||
public GameObject GetPage()
|
||||
{
|
||||
return customValuesPage;
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return "数值";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 公共方法
|
||||
/// <summary>
|
||||
/// 设置SDF字体
|
||||
/// </summary>
|
||||
public void SetSDFFont(TMP_FontAsset fontAsset)
|
||||
{
|
||||
savedFontAsset = fontAsset;
|
||||
ApplyFontToExistingUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新加载自定义数值
|
||||
/// </summary>
|
||||
public void ReloadCustomValues()
|
||||
{
|
||||
ReloadValueDefinitions();
|
||||
InvalidateValueView();
|
||||
|
||||
if (customValuesPage != null && customValuesPage.activeInHierarchy)
|
||||
{
|
||||
EnsurePageViewInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsurePageViewInitialized()
|
||||
{
|
||||
if (valueDefinitionsDirty)
|
||||
{
|
||||
ReloadValueDefinitions();
|
||||
}
|
||||
|
||||
if (!valueViewInitialized)
|
||||
{
|
||||
BuildValueViewSkeleton();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(currentSubTab) && tabGroups.Count > 0)
|
||||
{
|
||||
currentSubTab = tabGroups.OrderBy(kvp => kvp.Key == "默认" ? string.Empty : kvp.Key).First().Key;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(currentSubTab))
|
||||
{
|
||||
EnsureSubTabContentBuilt(currentSubTab);
|
||||
}
|
||||
|
||||
UpdateSubTabButtonStyles();
|
||||
}
|
||||
|
||||
private void ApplyFontToExistingUI()
|
||||
{
|
||||
if (savedFontAsset == null || customValuesPage == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TMP_Text[] texts = customValuesPage.GetComponentsInChildren<TMP_Text>(true);
|
||||
foreach (TMP_Text text in texts)
|
||||
{
|
||||
text.font = savedFontAsset;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定方法的数值范围
|
||||
/// </summary>
|
||||
/// <param name="methodName">方法名称(类名.方法名 或 方法名)</param>
|
||||
/// <param name="minValue">新的最小值</param>
|
||||
/// <param name="maxValue">新的最大值</param>
|
||||
/// <returns>是否成功更新</returns>
|
||||
public bool UpdateValueRange(string methodName, int minValue, int maxValue)
|
||||
{
|
||||
if (minValue >= maxValue)
|
||||
{
|
||||
Debug.LogWarning($"[CustomValuesModule] 无效的范围: minValue({minValue}) >= maxValue({maxValue})");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 尝试精确匹配
|
||||
if (valueControls.ContainsKey(methodName))
|
||||
{
|
||||
return UpdateValueRangeInternal(methodName, minValue, maxValue);
|
||||
}
|
||||
|
||||
// 尝试模糊匹配(只用方法名)
|
||||
foreach (var kvp in valueControls)
|
||||
{
|
||||
string key = kvp.Key;
|
||||
string simpleMethodName = key.Substring(key.LastIndexOf('.') + 1);
|
||||
|
||||
if (simpleMethodName == methodName)
|
||||
{
|
||||
return UpdateValueRangeInternal(key, minValue, maxValue);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogWarning($"[CustomValuesModule] 未找到方法: {methodName}");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新指定方法的当前值
|
||||
/// </summary>
|
||||
/// <param name="methodName">方法名称(类名.方法名 或 方法名)</param>
|
||||
/// <param name="value">新的值</param>
|
||||
/// <returns>是否成功更新</returns>
|
||||
public bool UpdateValue(string methodName, int value)
|
||||
{
|
||||
// 尝试精确匹配
|
||||
if (valueControls.ContainsKey(methodName))
|
||||
{
|
||||
return UpdateValueInternal(methodName, value);
|
||||
}
|
||||
|
||||
// 尝试模糊匹配(只用方法名)
|
||||
foreach (var kvp in valueControls)
|
||||
{
|
||||
string key = kvp.Key;
|
||||
string simpleMethodName = key.Substring(key.LastIndexOf('.') + 1);
|
||||
|
||||
if (simpleMethodName == methodName)
|
||||
{
|
||||
return UpdateValueInternal(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogWarning($"[CustomValuesModule] 未找到方法: {methodName}");
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool UpdateValueRangeInternal(string methodKey, int minValue, int maxValue)
|
||||
{
|
||||
var data = valueControls[methodKey];
|
||||
|
||||
// 更新attribute的范围
|
||||
data.attribute.MinValue = minValue;
|
||||
data.attribute.MaxValue = maxValue;
|
||||
|
||||
// 更新slider的范围
|
||||
if (data.slider != null)
|
||||
{
|
||||
data.slider.minValue = minValue;
|
||||
data.slider.maxValue = maxValue;
|
||||
|
||||
// 确保当前值在新范围内
|
||||
int currentValue = valueStates[methodKey];
|
||||
int clampedValue = Mathf.Clamp(currentValue, minValue, maxValue);
|
||||
|
||||
if (currentValue != clampedValue)
|
||||
{
|
||||
valueStates[methodKey] = clampedValue;
|
||||
data.slider.value = clampedValue;
|
||||
|
||||
if (data.inputField != null)
|
||||
{
|
||||
data.inputField.text = clampedValue.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"[CustomValuesModule] 已更新 {methodKey} 的范围: [{minValue}, {maxValue}]");
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool UpdateValueInternal(string methodKey, int value)
|
||||
{
|
||||
var data = valueControls[methodKey];
|
||||
|
||||
// 确保值在范围内
|
||||
int clampedValue = Mathf.Clamp(value, data.attribute.MinValue, data.attribute.MaxValue);
|
||||
|
||||
if (clampedValue != value)
|
||||
{
|
||||
Debug.LogWarning($"[CustomValuesModule] 值 {value} 超出范围 [{data.attribute.MinValue}, {data.attribute.MaxValue}],已限制为 {clampedValue}");
|
||||
}
|
||||
|
||||
// 更新保存的状态
|
||||
valueStates[methodKey] = clampedValue;
|
||||
|
||||
// 更新slider
|
||||
if (data.slider != null)
|
||||
{
|
||||
data.slider.value = clampedValue;
|
||||
}
|
||||
|
||||
// 更新输入框
|
||||
if (data.inputField != null)
|
||||
{
|
||||
data.inputField.text = clampedValue.ToString();
|
||||
}
|
||||
|
||||
Debug.Log($"[CustomValuesModule] 已更新 {methodKey} 的值: {clampedValue}");
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
/// <summary>
|
||||
/// 加载所有自定义数值(使用反射)
|
||||
/// </summary>
|
||||
private void ReloadValueDefinitions()
|
||||
{
|
||||
if (valueContainer == null || valuePrefab == null)
|
||||
{
|
||||
Debug.LogWarning("[CustomValuesModule] 数值容器或数值预制件未设置");
|
||||
return;
|
||||
}
|
||||
|
||||
// 清空控件引用
|
||||
valueControls.Clear();
|
||||
tabGroups.Clear();
|
||||
tabColors.Clear();
|
||||
|
||||
// 查找所有标记为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<DebugValueAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
var classAttribute = type.GetCustomAttribute<DebugValueClassAttribute>(true);
|
||||
string tabName = ResolveTabName(attribute, classAttribute);
|
||||
Color tabColor = ResolveTabColor(classAttribute);
|
||||
|
||||
RegisterTabColor(tabName, tabColor);
|
||||
|
||||
if (!tabGroups.ContainsKey(tabName))
|
||||
{
|
||||
tabGroups[tabName] = new List<ValueInfo>();
|
||||
}
|
||||
|
||||
tabGroups[tabName].Add(new ValueInfo
|
||||
{
|
||||
Method = method,
|
||||
Attribute = attribute,
|
||||
TabName = tabName
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// 某些程序集可能无法访问,跳过
|
||||
Debug.LogWarning($"[CustomValuesModule] 无法访问程序集 {assembly.FullName}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"[CustomValuesModule] 共找到 {tabGroups.Count} 个Tab");
|
||||
foreach (var tab in tabGroups)
|
||||
{
|
||||
Debug.Log($" - Tab: {tab.Key}, 数值数: {tab.Value.Count}");
|
||||
}
|
||||
|
||||
valueDefinitionsDirty = false;
|
||||
}
|
||||
|
||||
private string ResolveTabName(DebugValueAttribute methodAttribute, DebugValueClassAttribute classAttribute)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(methodAttribute.TabName))
|
||||
{
|
||||
return methodAttribute.TabName;
|
||||
}
|
||||
|
||||
if (classAttribute != null && !string.IsNullOrEmpty(classAttribute.TabName))
|
||||
{
|
||||
return classAttribute.TabName;
|
||||
}
|
||||
|
||||
return "默认";
|
||||
}
|
||||
|
||||
private Color ResolveTabColor(DebugValueClassAttribute classAttribute)
|
||||
{
|
||||
if (classAttribute != null)
|
||||
{
|
||||
return classAttribute.TabColor;
|
||||
}
|
||||
|
||||
return new Color(0.2f, 0.6f, 1f, 1f);
|
||||
}
|
||||
|
||||
private void RegisterTabColor(string tabName, Color tabColor)
|
||||
{
|
||||
if (!tabColors.ContainsKey(tabName))
|
||||
{
|
||||
tabColors[tabName] = tabColor;
|
||||
return;
|
||||
}
|
||||
|
||||
Color existing = tabColors[tabName];
|
||||
if (!Mathf.Approximately(existing.r, tabColor.r) ||
|
||||
!Mathf.Approximately(existing.g, tabColor.g) ||
|
||||
!Mathf.Approximately(existing.b, tabColor.b) ||
|
||||
!Mathf.Approximately(existing.a, tabColor.a))
|
||||
{
|
||||
Debug.LogWarning($"[CustomValuesModule] Tab '{tabName}' 检测到多个颜色定义,已保留第一个颜色配置");
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildValueViewSkeleton()
|
||||
{
|
||||
InvalidateValueView();
|
||||
SetupValueContainerLayout();
|
||||
|
||||
if (tabGroups.Count == 0)
|
||||
{
|
||||
GameObject emptyText = new GameObject("EmptyTip");
|
||||
emptyText.transform.SetParent(valueContainer, false);
|
||||
TMP_Text text = emptyText.AddComponent<TextMeshProUGUI>();
|
||||
text.text = "未找到任何 DebugValue";
|
||||
text.fontSize = 28;
|
||||
text.fontStyle = FontStyles.Bold;
|
||||
text.enableAutoSizing = true;
|
||||
text.fontSizeMin = 12;
|
||||
text.fontSizeMax = 72;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.color = new Color(1f, 1f, 1f, 0.8f);
|
||||
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
text.font = savedFontAsset;
|
||||
}
|
||||
|
||||
LayoutElement element = emptyText.AddComponent<LayoutElement>();
|
||||
element.preferredHeight = 80;
|
||||
valueViewInitialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
subTabBarObject = CreateSubTabBar();
|
||||
|
||||
tabContentRootObject = new GameObject("SubTabContentRoot");
|
||||
tabContentRootObject.transform.SetParent(valueContainer, false);
|
||||
|
||||
RectTransform contentRootRect = tabContentRootObject.AddComponent<RectTransform>();
|
||||
contentRootRect.anchorMin = new Vector2(0, 1);
|
||||
contentRootRect.anchorMax = new Vector2(1, 1);
|
||||
contentRootRect.pivot = new Vector2(0.5f, 1f);
|
||||
|
||||
VerticalLayoutGroup contentRootLayout = tabContentRootObject.AddComponent<VerticalLayoutGroup>();
|
||||
contentRootLayout.childForceExpandWidth = true;
|
||||
contentRootLayout.childForceExpandHeight = false;
|
||||
contentRootLayout.childControlWidth = true;
|
||||
contentRootLayout.childControlHeight = false;
|
||||
contentRootLayout.spacing = 0;
|
||||
contentRootLayout.padding = new RectOffset(0, 0, 0, 0);
|
||||
|
||||
ContentSizeFitter contentRootFitter = tabContentRootObject.AddComponent<ContentSizeFitter>();
|
||||
contentRootFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
contentRootFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
|
||||
LayoutElement contentRootElement = tabContentRootObject.AddComponent<LayoutElement>();
|
||||
contentRootElement.flexibleWidth = 1;
|
||||
|
||||
var sortedTabs = tabGroups.OrderBy(kvp => kvp.Key == "默认" ? string.Empty : kvp.Key);
|
||||
bool firstTab = true;
|
||||
|
||||
foreach (var tab in sortedTabs)
|
||||
{
|
||||
string tabName = tab.Key;
|
||||
CreateSubTabButton(tabName, subTabBarObject.transform);
|
||||
|
||||
GameObject tabPanel = CreateTabPanel(tabName, tabContentRootObject.transform);
|
||||
tabPanels[tabName] = tabPanel;
|
||||
|
||||
tabPanel.SetActive(firstTab);
|
||||
if (firstTab)
|
||||
{
|
||||
currentSubTab = tabName;
|
||||
firstTab = false;
|
||||
}
|
||||
}
|
||||
|
||||
Canvas.ForceUpdateCanvases();
|
||||
UpdateSubTabBarHeight(subTabBarObject);
|
||||
|
||||
UpdateSubTabButtonStyles();
|
||||
|
||||
if (valuesScrollRect != null)
|
||||
{
|
||||
Canvas.ForceUpdateCanvases();
|
||||
valuesScrollRect.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
|
||||
valueViewInitialized = true;
|
||||
}
|
||||
|
||||
private void EnsureSubTabContentBuilt(string tabName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tabName) || builtSubTabs.Contains(tabName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tabPanels.TryGetValue(tabName, out GameObject tabPanel) || tabPanel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tabGroups.TryGetValue(tabName, out List<ValueInfo> values))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var valueInfo in values)
|
||||
{
|
||||
CreateCustomValue(valueInfo.Method, valueInfo.Attribute, tabPanel.transform);
|
||||
}
|
||||
|
||||
builtSubTabs.Add(tabName);
|
||||
Canvas.ForceUpdateCanvases();
|
||||
}
|
||||
|
||||
private void InvalidateValueView()
|
||||
{
|
||||
if (valueContainer != null)
|
||||
{
|
||||
foreach (Transform child in valueContainer)
|
||||
{
|
||||
UnityEngine.Object.Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
valueControls.Clear();
|
||||
tabPanels.Clear();
|
||||
subTabButtons.Clear();
|
||||
builtSubTabs.Clear();
|
||||
currentSubTab = string.Empty;
|
||||
subTabBarObject = null;
|
||||
tabContentRootObject = null;
|
||||
valueViewInitialized = false;
|
||||
}
|
||||
|
||||
private GameObject CreateSubTabBar()
|
||||
{
|
||||
GameObject subTabBar = new GameObject("SubTabBar");
|
||||
subTabBar.transform.SetParent(valueContainer, false);
|
||||
|
||||
RectTransform rectTransform = subTabBar.AddComponent<RectTransform>();
|
||||
rectTransform.anchorMin = new Vector2(0, 1);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
rectTransform.pivot = new Vector2(0.5f, 1f);
|
||||
|
||||
Image bg = subTabBar.AddComponent<Image>();
|
||||
bg.color = new Color(0.15f, 0.15f, 0.15f, 0.8f);
|
||||
|
||||
GridLayoutGroup layout = subTabBar.AddComponent<GridLayoutGroup>();
|
||||
layout.cellSize = new Vector2(SubTabCellWidth, SubTabCellHeight);
|
||||
layout.spacing = new Vector2(SubTabSpacingX, SubTabSpacingY);
|
||||
layout.padding = new RectOffset(10, 10, 10, 10);
|
||||
layout.constraint = GridLayoutGroup.Constraint.Flexible;
|
||||
layout.startAxis = GridLayoutGroup.Axis.Horizontal;
|
||||
layout.startCorner = GridLayoutGroup.Corner.UpperLeft;
|
||||
layout.childAlignment = TextAnchor.UpperLeft;
|
||||
|
||||
ContentSizeFitter fitter = subTabBar.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
|
||||
LayoutElement element = subTabBar.AddComponent<LayoutElement>();
|
||||
element.minHeight = 80;
|
||||
element.preferredHeight = 80;
|
||||
element.flexibleWidth = 1;
|
||||
|
||||
return subTabBar;
|
||||
}
|
||||
|
||||
private void CreateSubTabButton(string tabName, Transform parent)
|
||||
{
|
||||
GameObject tabButtonObj = new GameObject($"SubTab_{tabName}");
|
||||
tabButtonObj.transform.SetParent(parent, false);
|
||||
|
||||
RectTransform rect = tabButtonObj.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = new Vector2(200, 56);
|
||||
|
||||
Image image = tabButtonObj.AddComponent<Image>();
|
||||
image.color = GetInactiveTabColor(tabName);
|
||||
|
||||
Button button = tabButtonObj.AddComponent<Button>();
|
||||
|
||||
GameObject textObj = new GameObject("Text");
|
||||
textObj.transform.SetParent(tabButtonObj.transform, false);
|
||||
RectTransform textRect = textObj.AddComponent<RectTransform>();
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.offsetMin = Vector2.zero;
|
||||
textRect.offsetMax = Vector2.zero;
|
||||
|
||||
TMP_Text text = textObj.AddComponent<TextMeshProUGUI>();
|
||||
text.text = tabName;
|
||||
text.fontSize = 26;
|
||||
text.fontStyle = FontStyles.Bold;
|
||||
text.enableAutoSizing = true;
|
||||
text.fontSizeMin = 12;
|
||||
text.fontSizeMax = 72;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.color = Color.white;
|
||||
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
text.font = savedFontAsset;
|
||||
}
|
||||
|
||||
LayoutElement element = tabButtonObj.AddComponent<LayoutElement>();
|
||||
element.preferredWidth = SubTabCellWidth;
|
||||
element.minWidth = SubTabCellWidth;
|
||||
element.preferredHeight = SubTabCellHeight;
|
||||
|
||||
button.onClick.AddListener(() => SelectSubTab(tabName));
|
||||
subTabButtons.Add(button);
|
||||
}
|
||||
|
||||
private void UpdateSubTabBarHeight(GameObject subTabBar)
|
||||
{
|
||||
if (subTabBar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RectTransform subTabRect = subTabBar.GetComponent<RectTransform>();
|
||||
LayoutElement layoutElement = subTabBar.GetComponent<LayoutElement>();
|
||||
if (subTabRect == null || layoutElement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float availableWidth = subTabRect.rect.width;
|
||||
if (availableWidth <= 0f && valueContainer != null)
|
||||
{
|
||||
availableWidth = valueContainer.rect.width;
|
||||
}
|
||||
|
||||
if (availableWidth <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float usableWidth = Mathf.Max(1f, availableWidth - SubTabPaddingHorizontal);
|
||||
int columnCount = Mathf.Max(1, Mathf.FloorToInt((usableWidth + SubTabSpacingX) / (SubTabCellWidth + SubTabSpacingX)));
|
||||
int rowCount = Mathf.Max(1, Mathf.CeilToInt((float)subTabButtons.Count / columnCount));
|
||||
float preferredHeight = SubTabPaddingVertical + rowCount * SubTabCellHeight + Mathf.Max(0, rowCount - 1) * SubTabSpacingY;
|
||||
|
||||
layoutElement.minHeight = preferredHeight;
|
||||
layoutElement.preferredHeight = preferredHeight;
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(subTabRect);
|
||||
}
|
||||
|
||||
private GameObject CreateTabPanel(string tabName, Transform parent)
|
||||
{
|
||||
GameObject panel = new GameObject($"Panel_{tabName}");
|
||||
panel.transform.SetParent(parent, false);
|
||||
|
||||
RectTransform rectTransform = panel.AddComponent<RectTransform>();
|
||||
rectTransform.anchorMin = new Vector2(0, 1);
|
||||
rectTransform.anchorMax = new Vector2(1, 1);
|
||||
rectTransform.pivot = new Vector2(0.5f, 1f);
|
||||
|
||||
VerticalLayoutGroup layout = panel.AddComponent<VerticalLayoutGroup>();
|
||||
layout.childForceExpandWidth = true;
|
||||
layout.childForceExpandHeight = false;
|
||||
layout.childControlWidth = true;
|
||||
layout.childControlHeight = false;
|
||||
layout.spacing = 20;
|
||||
layout.padding = new RectOffset(0, 0, 10, 10);
|
||||
|
||||
ContentSizeFitter fitter = panel.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
|
||||
LayoutElement element = panel.AddComponent<LayoutElement>();
|
||||
element.flexibleWidth = 1;
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void SelectSubTab(string tabName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tabName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureSubTabContentBuilt(tabName);
|
||||
|
||||
if (currentSubTab == tabName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentSubTab = tabName;
|
||||
|
||||
foreach (var kvp in tabPanels)
|
||||
{
|
||||
kvp.Value.SetActive(kvp.Key == tabName);
|
||||
}
|
||||
|
||||
UpdateSubTabButtonStyles();
|
||||
|
||||
if (valuesScrollRect != null)
|
||||
{
|
||||
Canvas.ForceUpdateCanvases();
|
||||
valuesScrollRect.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSubTabButtonStyles()
|
||||
{
|
||||
foreach (var button in subTabButtons)
|
||||
{
|
||||
if (button == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string tabName = button.gameObject.name.Replace("SubTab_", string.Empty);
|
||||
Image image = button.GetComponent<Image>();
|
||||
if (image != null)
|
||||
{
|
||||
image.color = tabName == currentSubTab
|
||||
? GetActiveTabColor(tabName)
|
||||
: GetInactiveTabColor(tabName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Color GetActiveTabColor(string tabName)
|
||||
{
|
||||
if (tabColors.TryGetValue(tabName, out var color))
|
||||
{
|
||||
color.a = 0.95f;
|
||||
return color;
|
||||
}
|
||||
|
||||
return new Color(0.2f, 0.6f, 1f, 0.95f);
|
||||
}
|
||||
|
||||
private Color GetInactiveTabColor(string tabName)
|
||||
{
|
||||
Color activeColor = GetActiveTabColor(tabName);
|
||||
Color inactive = Color.Lerp(new Color(0.18f, 0.18f, 0.18f, 0.9f), activeColor, 0.35f);
|
||||
inactive.a = 0.9f;
|
||||
return inactive;
|
||||
}
|
||||
|
||||
private void SetupValueContainerLayout()
|
||||
{
|
||||
if (valueContainer == null)
|
||||
{
|
||||
Debug.LogError("[CustomValuesModule] valueContainer 为 null,无法设置布局");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject containerObject = valueContainer.gameObject;
|
||||
|
||||
GridLayoutGroup gridLayout = containerObject.GetComponent<GridLayoutGroup>();
|
||||
if (gridLayout != null)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(gridLayout);
|
||||
}
|
||||
|
||||
HorizontalLayoutGroup horizontalLayout = containerObject.GetComponent<HorizontalLayoutGroup>();
|
||||
if (horizontalLayout != null)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(horizontalLayout);
|
||||
}
|
||||
|
||||
VerticalLayoutGroup verticalLayout = containerObject.GetComponent<VerticalLayoutGroup>();
|
||||
if (verticalLayout == null)
|
||||
{
|
||||
verticalLayout = containerObject.AddComponent<VerticalLayoutGroup>();
|
||||
}
|
||||
|
||||
verticalLayout.childForceExpandWidth = true;
|
||||
verticalLayout.childForceExpandHeight = false;
|
||||
verticalLayout.childControlWidth = true;
|
||||
verticalLayout.childControlHeight = false;
|
||||
verticalLayout.spacing = 20;
|
||||
verticalLayout.padding = new RectOffset(20, 20, 20, 20);
|
||||
|
||||
ContentSizeFitter sizeFitter = containerObject.GetComponent<ContentSizeFitter>();
|
||||
if (sizeFitter == null)
|
||||
{
|
||||
sizeFitter = containerObject.AddComponent<ContentSizeFitter>();
|
||||
}
|
||||
|
||||
sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
sizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
}
|
||||
|
||||
private void CreateCustomValue(MethodInfo method, DebugValueAttribute attribute, Transform parent)
|
||||
{
|
||||
// 验证方法签名:必须接受一个 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, parent);
|
||||
RectTransform valueRect = valueObj.GetComponent<RectTransform>();
|
||||
if (valueRect != null)
|
||||
{
|
||||
LayoutElement layoutElement = valueObj.GetComponent<LayoutElement>();
|
||||
if (layoutElement == null)
|
||||
{
|
||||
layoutElement = valueObj.AddComponent<LayoutElement>();
|
||||
}
|
||||
|
||||
layoutElement.preferredHeight = valueRect.sizeDelta.y > 0 ? valueRect.sizeDelta.y : 140f;
|
||||
layoutElement.flexibleWidth = 1f;
|
||||
}
|
||||
|
||||
// 获取组件
|
||||
TMP_Text labelText = valueObj.transform.Find("Label")?.GetComponent<TMP_Text>();
|
||||
Slider slider = valueObj.transform.Find("Slider")?.GetComponent<Slider>();
|
||||
TMP_InputField inputField = valueObj.transform.Find("InputField")?.GetComponent<TMP_InputField>();
|
||||
Button confirmButton = valueObj.transform.Find("ConfirmButton")?.GetComponent<Button>();
|
||||
Image backgroundImage = valueObj.GetComponent<Image>();
|
||||
|
||||
// 设置标签文本
|
||||
if (labelText != null)
|
||||
{
|
||||
labelText.text = string.IsNullOrEmpty(attribute.DisplayName) ? method.Name : attribute.DisplayName;
|
||||
|
||||
// 应用保存的字体
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
labelText.font = savedFontAsset;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置背景颜色
|
||||
if (backgroundImage != null && attribute.ValueColor != default(Color))
|
||||
{
|
||||
backgroundImage.color = attribute.ValueColor;
|
||||
}
|
||||
|
||||
// 获取或初始化状态(使用默认值)
|
||||
string methodKey = $"{method.DeclaringType?.FullName}.{method.Name}";
|
||||
if (!valueStates.ContainsKey(methodKey))
|
||||
{
|
||||
valueStates[methodKey] = attribute.DefaultValue;
|
||||
}
|
||||
|
||||
int currentValue = valueStates[methodKey];
|
||||
|
||||
// 保存控件引用
|
||||
valueControls[methodKey] = new ValueControlData
|
||||
{
|
||||
slider = slider,
|
||||
inputField = inputField,
|
||||
method = method,
|
||||
attribute = attribute
|
||||
};
|
||||
|
||||
// 设置滑动条
|
||||
if (slider != null)
|
||||
{
|
||||
slider.minValue = attribute.MinValue;
|
||||
slider.maxValue = attribute.MaxValue;
|
||||
slider.wholeNumbers = true;
|
||||
slider.value = currentValue;
|
||||
|
||||
// 滑动条值改变时更新输入框和保存状态
|
||||
slider.onValueChanged.AddListener((float value) =>
|
||||
{
|
||||
int intValue = Mathf.RoundToInt(value);
|
||||
if (inputField != null)
|
||||
{
|
||||
inputField.text = intValue.ToString();
|
||||
}
|
||||
valueStates[methodKey] = intValue;
|
||||
});
|
||||
}
|
||||
|
||||
// 设置输入框
|
||||
if (inputField != null)
|
||||
{
|
||||
inputField.text = currentValue.ToString();
|
||||
// 根据最小值判断是否允许负数
|
||||
// 如果最小值小于0,使用Standard类型并限制只能输入数字和负号
|
||||
inputField.contentType = attribute.MinValue < 0
|
||||
? TMP_InputField.ContentType.Standard
|
||||
: TMP_InputField.ContentType.IntegerNumber;
|
||||
|
||||
// 如果允许负数,需要设置字符验证来只允许数字和负号
|
||||
if (attribute.MinValue < 0)
|
||||
{
|
||||
inputField.characterValidation = TMP_InputField.CharacterValidation.None;
|
||||
inputField.inputType = TMP_InputField.InputType.Standard;
|
||||
inputField.keyboardType = TouchScreenKeyboardType.NumbersAndPunctuation;
|
||||
}
|
||||
|
||||
// 应用保存的字体
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
inputField.textComponent.font = savedFontAsset;
|
||||
}
|
||||
|
||||
// 输入框值改变时更新滑动条和保存状态
|
||||
inputField.onValueChanged.AddListener((string text) =>
|
||||
{
|
||||
// 允许输入过程中暂时为空或只有负号
|
||||
if (string.IsNullOrEmpty(text) || text == "-")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.TryParse(text, out int intValue))
|
||||
{
|
||||
// 限制范围
|
||||
intValue = Mathf.Clamp(intValue, attribute.MinValue, attribute.MaxValue);
|
||||
|
||||
if (slider != null)
|
||||
{
|
||||
slider.value = intValue;
|
||||
}
|
||||
valueStates[methodKey] = intValue;
|
||||
}
|
||||
});
|
||||
|
||||
// 输入框失去焦点时确保值在范围内
|
||||
inputField.onEndEdit.AddListener((string text) =>
|
||||
{
|
||||
if (int.TryParse(text, out int intValue))
|
||||
{
|
||||
intValue = Mathf.Clamp(intValue, attribute.MinValue, attribute.MaxValue);
|
||||
inputField.text = intValue.ToString();
|
||||
valueStates[methodKey] = intValue;
|
||||
|
||||
if (slider != null)
|
||||
{
|
||||
slider.value = intValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果输入无效,恢复为当前保存的值
|
||||
inputField.text = valueStates[methodKey].ToString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 设置确认按钮
|
||||
if (confirmButton != null)
|
||||
{
|
||||
// 应用保存的字体到按钮文本
|
||||
if (savedFontAsset != null)
|
||||
{
|
||||
TMP_Text btnText = confirmButton.GetComponentInChildren<TMP_Text>();
|
||||
if (btnText != null)
|
||||
{
|
||||
btnText.font = savedFontAsset;
|
||||
}
|
||||
}
|
||||
|
||||
confirmButton.onClick.AddListener(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int finalValue = valueStates[methodKey];
|
||||
|
||||
// 调用方法,传递数值
|
||||
method.Invoke(null, new object[] { finalValue });
|
||||
Debug.Log($"[CustomValuesModule] 执行调试方法: {method.Name}, 数值: {finalValue}");
|
||||
// 点击确认按钮后关闭主窗口
|
||||
onCloseWindowCallback?.Invoke(); }
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[CustomValuesModule] 执行调试方法 {method.Name} 时出错: {e.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e9a59724c256d243a97df1857fdc89e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,352 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 可拖动的悬浮按钮
|
||||
/// 点击打开调试工具,可以在屏幕上自由拖动
|
||||
/// </summary>
|
||||
public class DraggableFloatingButton : MonoBehaviour, IPointerDownHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
|
||||
{
|
||||
[Header("设置")]
|
||||
[Tooltip("是否启用拖动功能")]
|
||||
public bool enableDragging = false;
|
||||
|
||||
[Tooltip("是否限制在屏幕范围内")]
|
||||
public bool clampToScreen = true;
|
||||
|
||||
[Tooltip("与屏幕边缘的最小距离")]
|
||||
public float edgePadding = 20f;
|
||||
|
||||
[Header("自动吸附")]
|
||||
[Tooltip("是否自动吸附到屏幕边缘")]
|
||||
public bool snapToEdge = true;
|
||||
|
||||
[Tooltip("吸附动画时间")]
|
||||
public float snapDuration = 0.1f;
|
||||
|
||||
private RectTransform rectTransform;
|
||||
private Canvas canvas;
|
||||
private Vector2 dragOffset;
|
||||
private bool isDragging = false;
|
||||
private Vector2 targetPosition;
|
||||
private bool isSnapping = false;
|
||||
|
||||
// 用于区分点击和拖动
|
||||
private bool hasDragged = false; // 标记本次操作是否进行了拖动
|
||||
private Vector2 dragStartPosition; // 拖动起始位置
|
||||
private const float dragThreshold = 5f; // 拖动阈值,移动超过这个距离才算拖动
|
||||
private const float FpsRefreshInterval = 0.25f;
|
||||
|
||||
private TMP_Text titleText;
|
||||
private TMP_Text fpsText;
|
||||
private TMP_Text fallbackText;
|
||||
private float smoothedUnscaledDeltaTime = 1f / 60f;
|
||||
private float nextFpsRefreshTime = 0f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
rectTransform = GetComponent<RectTransform>();
|
||||
canvas = GetComponentInParent<Canvas>();
|
||||
|
||||
if (canvas == null)
|
||||
{
|
||||
Debug.LogError("DraggableFloatingButton 必须在Canvas下!");
|
||||
}
|
||||
|
||||
targetPosition = rectTransform.anchoredPosition;
|
||||
titleText = transform.Find("ContentCanvas/TitleText")?.GetComponent<TMP_Text>()
|
||||
?? transform.Find("TitleText")?.GetComponent<TMP_Text>();
|
||||
fpsText = transform.Find("ContentCanvas/FpsText")?.GetComponent<TMP_Text>()
|
||||
?? transform.Find("FpsText")?.GetComponent<TMP_Text>();
|
||||
fallbackText = transform.Find("Text")?.GetComponent<TMP_Text>();
|
||||
UpdateFpsDisplay(true);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
smoothedUnscaledDeltaTime = Mathf.Lerp(smoothedUnscaledDeltaTime, Time.unscaledDeltaTime, 0.12f);
|
||||
if (Time.unscaledTime >= nextFpsRefreshTime)
|
||||
{
|
||||
nextFpsRefreshTime = Time.unscaledTime + FpsRefreshInterval;
|
||||
UpdateFpsDisplay(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFpsDisplay(bool force)
|
||||
{
|
||||
if (!force && !gameObject.activeInHierarchy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int fps = Mathf.Clamp(Mathf.RoundToInt(1f / Mathf.Max(0.0001f, smoothedUnscaledDeltaTime)), 0, 999);
|
||||
|
||||
if (titleText != null)
|
||||
{
|
||||
titleText.text = "调试";
|
||||
}
|
||||
|
||||
if (fpsText != null)
|
||||
{
|
||||
fpsText.text = $"{fps} FPS";
|
||||
return;
|
||||
}
|
||||
|
||||
if (fallbackText != null)
|
||||
{
|
||||
fallbackText.text = $"调试\n{fps} FPS";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每次按下时重置拖动标记(在OnBeginDrag之前触发)
|
||||
/// </summary>
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
hasDragged = false; // 重置拖动标记
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!enableDragging)
|
||||
{
|
||||
// 如果禁用拖动,将事件传递给父级,让其他UI元素能够接收拖动事件
|
||||
PassEventToParent(eventData, ExecuteEvents.beginDragHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
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 (!enableDragging)
|
||||
{
|
||||
// 如果禁用拖动,将事件传递给父级
|
||||
PassEventToParent(eventData, ExecuteEvents.dragHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isDragging) return;
|
||||
|
||||
// 检查是否超过拖动阈值
|
||||
float dragDistance = Vector2.Distance(dragStartPosition, eventData.position);
|
||||
if (dragDistance > dragThreshold)
|
||||
{
|
||||
hasDragged = true; // 标记已经拖动
|
||||
}
|
||||
|
||||
// 转换屏幕坐标到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)
|
||||
{
|
||||
if (!enableDragging)
|
||||
{
|
||||
// 如果禁用拖动,将事件传递给父级
|
||||
PassEventToParent(eventData, ExecuteEvents.endDragHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
isDragging = false;
|
||||
|
||||
// 自动吸附到最近的边缘
|
||||
if (snapToEdge)
|
||||
{
|
||||
SnapToNearestEdge();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理点击事件 - 只有在没有拖动时才打开窗口
|
||||
/// </summary>
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
// 如果进行了拖动,不执行点击操作
|
||||
if (hasDragged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 纯点击操作,打开调试窗口
|
||||
UniversalDebugTool debugTool = FindObjectOfType<UniversalDebugTool>();
|
||||
if (debugTool != null)
|
||||
{
|
||||
debugTool.OpenDebugWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[X] 未找到 UniversalDebugTool 实例!");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置悬浮按钮位置
|
||||
/// </summary>
|
||||
public void SetPosition(Vector2 position)
|
||||
{
|
||||
if (clampToScreen)
|
||||
{
|
||||
position = ClampToScreen(position);
|
||||
}
|
||||
rectTransform.anchoredPosition = position;
|
||||
targetPosition = position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前位置
|
||||
/// </summary>
|
||||
public Vector2 GetPosition()
|
||||
{
|
||||
return rectTransform.anchoredPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将事件传递给父级或下层的UI元素
|
||||
/// 当拖动功能被禁用时,确保其他UI元素仍能接收拖动事件
|
||||
/// </summary>
|
||||
private void PassEventToParent<T>(PointerEventData eventData, ExecuteEvents.EventFunction<T> eventFunction) where T : IEventSystemHandler
|
||||
{
|
||||
Transform parent = transform.parent;
|
||||
while (parent != null)
|
||||
{
|
||||
// 尝试执行父级对象上的事件
|
||||
if (ExecuteEvents.Execute(parent.gameObject, eventData, eventFunction))
|
||||
{
|
||||
// 如果父级处理了事件,停止传递
|
||||
return;
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
// 如果父级都没有处理,尝试传递给射线检测到的下一个对象
|
||||
var raycastResults = new System.Collections.Generic.List<RaycastResult>();
|
||||
EventSystem.current.RaycastAll(eventData, raycastResults);
|
||||
|
||||
// 跳过当前对象,找到下一个可以处理事件的对象
|
||||
foreach (var result in raycastResults)
|
||||
{
|
||||
if (result.gameObject == gameObject)
|
||||
continue;
|
||||
|
||||
if (ExecuteEvents.Execute(result.gameObject, eventData, eventFunction))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2dcf1746b56f2ed478ee60e12c45a209
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,25 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试模块接口
|
||||
/// </summary>
|
||||
public interface IDebugModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化模块
|
||||
/// </summary>
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// 获取模块页面
|
||||
/// </summary>
|
||||
GameObject GetPage();
|
||||
|
||||
/// <summary>
|
||||
/// 模块名称
|
||||
/// </summary>
|
||||
string GetModuleName();
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1053c580c7f549d4ea082c1f92e2349c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志节点
|
||||
/// </summary>
|
||||
public class LogNode
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志类型
|
||||
/// </summary>
|
||||
public LogType LogType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志消息
|
||||
/// </summary>
|
||||
public string LogMessage { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 堆栈跟踪
|
||||
/// </summary>
|
||||
public string StackTrace { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志时间
|
||||
/// </summary>
|
||||
public DateTime LogTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志帧数
|
||||
/// </summary>
|
||||
public int LogFrameCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建日志节点
|
||||
/// </summary>
|
||||
public static LogNode Create(LogType logType, string logMessage, string stackTrace)
|
||||
{
|
||||
LogNode logNode = new LogNode();
|
||||
logNode.LogType = logType;
|
||||
logNode.LogMessage = logMessage;
|
||||
logNode.StackTrace = stackTrace;
|
||||
logNode.LogTime = DateTime.UtcNow;
|
||||
logNode.LogFrameCount = Time.frameCount;
|
||||
return logNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 664e008aa85114d4abe0e031e4ce2da5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,978 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using TMPro;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数查看模块 - 仿 GameFramework Debugger 风格,带多级子标签页
|
||||
/// 一级标签: Information / Profiler / Language
|
||||
/// Information 子标签: System / Environment / Screen / Input / Other / Quality
|
||||
/// Profiler 子标签: Summary / Memory
|
||||
/// Language 标签: 中英文切换
|
||||
/// </summary>
|
||||
public class ParametersModule : IDebugModule
|
||||
{
|
||||
#region 字段
|
||||
|
||||
private GameObject parametersPage;
|
||||
// UI 根容器(由外部传入或内部构建)
|
||||
private RectTransform rootContainer;
|
||||
|
||||
// ---- 一级标签 ----
|
||||
private readonly List<Button> primaryTabButtons = new List<Button>();
|
||||
private readonly List<GameObject> primaryPages = new List<GameObject>();
|
||||
private int activePrimaryIndex = 0;
|
||||
|
||||
// ---- Information 二级标签 ----
|
||||
private readonly List<Button> infoSubTabButtons = new List<Button>();
|
||||
private readonly List<GameObject> infoSubPages = new List<GameObject>();
|
||||
private int activeInfoSubIndex = 0;
|
||||
|
||||
// ---- Profiler 二级标签 ----
|
||||
private readonly List<Button> profilerSubTabButtons = new List<Button>();
|
||||
private readonly List<GameObject> profilerSubPages = new List<GameObject>();
|
||||
private int activeProfilerSubIndex = 0;
|
||||
|
||||
// ---- Language ----
|
||||
private bool showChinese = false;
|
||||
|
||||
// 用于存储所有 info 文本控件,以便切换语言时刷新
|
||||
private readonly List<TMP_Text> allInfoTexts = new List<TMP_Text>();
|
||||
|
||||
// 标签页名称映射 (英文, 中文)
|
||||
private static readonly string[][] PrimaryTabNames = {
|
||||
new[] { "Information", "信息" },
|
||||
new[] { "Profiler", "性能分析" },
|
||||
new[] { "Language", "语言" }
|
||||
};
|
||||
private static readonly string[][] InfoSubTabNames = {
|
||||
new[] { "System", "系统" },
|
||||
new[] { "Environment", "环境" },
|
||||
new[] { "Screen", "屏幕" },
|
||||
new[] { "Input", "输入" },
|
||||
new[] { "Other", "其他" },
|
||||
new[] { "Quality", "画质" }
|
||||
};
|
||||
private static readonly string[][] ProfilerSubTabNames = {
|
||||
new[] { "Summary", "概览" },
|
||||
new[] { "Memory", "内存" }
|
||||
};
|
||||
|
||||
// 颜色
|
||||
private static readonly Color ActiveTabColor = new Color(0.2f, 0.6f, 0.2f, 1f);
|
||||
private static readonly Color InactiveTabColor = new Color(0.25f, 0.25f, 0.25f, 1f);
|
||||
private static readonly Color SubActiveTabColor = new Color(0.25f, 0.5f, 0.7f, 1f);
|
||||
private static readonly Color SubInactiveTabColor = new Color(0.2f, 0.2f, 0.2f, 1f);
|
||||
|
||||
// Profiler 刷新计数
|
||||
private float lastProfilerRefreshTime;
|
||||
private const float PROFILER_REFRESH_INTERVAL = 1f;
|
||||
|
||||
// 各 info 文本引用
|
||||
private TMP_Text systemInfoText;
|
||||
private TMP_Text environmentInfoText;
|
||||
private TMP_Text screenInfoText;
|
||||
private TMP_Text inputInfoText;
|
||||
private TMP_Text otherInfoText;
|
||||
private TMP_Text qualityInfoText;
|
||||
private TMP_Text profilerSummaryText;
|
||||
private TMP_Text profilerMemoryText;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
|
||||
public ParametersModule(GameObject page)
|
||||
{
|
||||
parametersPage = page;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDebugModule 实现
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
Debug.Log("[ParametersModule] 初始化参数查看模块...");
|
||||
BuildUI();
|
||||
RefreshAllInfo();
|
||||
}
|
||||
|
||||
public GameObject GetPage()
|
||||
{
|
||||
return parametersPage;
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return "参数";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每帧更新(由外部调用),用于刷新 Profiler 实时数据
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
if (activePrimaryIndex == 1 && Time.unscaledTime - lastProfilerRefreshTime > PROFILER_REFRESH_INTERVAL)
|
||||
{
|
||||
lastProfilerRefreshTime = Time.unscaledTime;
|
||||
RefreshProfilerSummary();
|
||||
RefreshProfilerMemory();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 公共方法
|
||||
|
||||
public void RefreshAllInfo()
|
||||
{
|
||||
RefreshSystemInfo();
|
||||
RefreshEnvironmentInfo();
|
||||
RefreshScreenInfo();
|
||||
RefreshInputInfo();
|
||||
RefreshOtherInfo();
|
||||
RefreshQualityInfo();
|
||||
RefreshProfilerSummary();
|
||||
RefreshProfilerMemory();
|
||||
}
|
||||
|
||||
public void CopyAllInfoToClipboard()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (var t in allInfoTexts)
|
||||
{
|
||||
if (t != null && !string.IsNullOrEmpty(t.text))
|
||||
{
|
||||
sb.AppendLine(t.text);
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
GUIUtility.systemCopyBuffer = sb.ToString();
|
||||
Debug.Log("[ParametersModule] 所有信息已复制到剪贴板");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI 构建
|
||||
|
||||
private void BuildUI()
|
||||
{
|
||||
if (parametersPage == null) return;
|
||||
|
||||
// 清空已有子对象
|
||||
for (int i = parametersPage.transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
UnityEngine.Object.Destroy(parametersPage.transform.GetChild(i).gameObject);
|
||||
}
|
||||
|
||||
// 根垂直布局
|
||||
VerticalLayoutGroup rootLayout = parametersPage.GetComponent<VerticalLayoutGroup>();
|
||||
if (rootLayout == null) rootLayout = parametersPage.AddComponent<VerticalLayoutGroup>();
|
||||
rootLayout.spacing = 0;
|
||||
rootLayout.padding = new RectOffset(0, 0, 0, 0);
|
||||
rootLayout.childControlWidth = true;
|
||||
rootLayout.childControlHeight = true;
|
||||
rootLayout.childForceExpandWidth = true;
|
||||
rootLayout.childForceExpandHeight = false;
|
||||
|
||||
// ===== 一级标签栏 =====
|
||||
GameObject primaryTabBar = CreateTabBar(parametersPage.transform, "PrimaryTabBar", 90);
|
||||
|
||||
for (int i = 0; i < PrimaryTabNames.Length; i++)
|
||||
{
|
||||
int idx = i;
|
||||
Button btn = CreateTabButton(primaryTabBar.transform, GetTabLabel(PrimaryTabNames[i]));
|
||||
btn.onClick.AddListener(() => SwitchPrimaryTab(idx));
|
||||
primaryTabButtons.Add(btn);
|
||||
}
|
||||
|
||||
// ===== 一级页面容器 =====
|
||||
// --- Information Page ---
|
||||
GameObject infoPage = CreatePageContainer(parametersPage.transform, "InformationPage");
|
||||
primaryPages.Add(infoPage);
|
||||
BuildInformationPage(infoPage);
|
||||
|
||||
// --- Profiler Page ---
|
||||
GameObject profilerPage = CreatePageContainer(parametersPage.transform, "ProfilerPage");
|
||||
primaryPages.Add(profilerPage);
|
||||
BuildProfilerPage(profilerPage);
|
||||
|
||||
// --- Language Page ---
|
||||
GameObject languagePage = CreatePageContainer(parametersPage.transform, "LanguagePage");
|
||||
primaryPages.Add(languagePage);
|
||||
BuildLanguagePage(languagePage);
|
||||
|
||||
// 操作栏
|
||||
GameObject actionBar = CreateActionBar(parametersPage.transform);
|
||||
|
||||
// 默认选中 Information
|
||||
SwitchPrimaryTab(0);
|
||||
}
|
||||
|
||||
private void BuildInformationPage(GameObject parent)
|
||||
{
|
||||
VerticalLayoutGroup vl = parent.AddComponent<VerticalLayoutGroup>();
|
||||
vl.spacing = 0;
|
||||
vl.padding = new RectOffset(0, 0, 0, 0);
|
||||
vl.childControlWidth = true;
|
||||
vl.childControlHeight = true;
|
||||
vl.childForceExpandWidth = true;
|
||||
vl.childForceExpandHeight = false;
|
||||
|
||||
// 二级标签栏
|
||||
GameObject subTabBar = CreateTabBar(parent.transform, "InfoSubTabBar", 80);
|
||||
|
||||
for (int i = 0; i < InfoSubTabNames.Length; i++)
|
||||
{
|
||||
int idx = i;
|
||||
Button btn = CreateTabButton(subTabBar.transform, GetTabLabel(InfoSubTabNames[i]), 26);
|
||||
btn.onClick.AddListener(() => SwitchInfoSubTab(idx));
|
||||
infoSubTabButtons.Add(btn);
|
||||
}
|
||||
|
||||
// 子页面
|
||||
systemInfoText = CreateScrollInfoPage(parent.transform, "SystemPage", out GameObject sysPage);
|
||||
infoSubPages.Add(sysPage);
|
||||
|
||||
environmentInfoText = CreateScrollInfoPage(parent.transform, "EnvironmentPage", out GameObject envPage);
|
||||
infoSubPages.Add(envPage);
|
||||
|
||||
screenInfoText = CreateScrollInfoPage(parent.transform, "ScreenPage", out GameObject scrPage);
|
||||
infoSubPages.Add(scrPage);
|
||||
|
||||
inputInfoText = CreateScrollInfoPage(parent.transform, "InputPage", out GameObject inputPage);
|
||||
infoSubPages.Add(inputPage);
|
||||
|
||||
otherInfoText = CreateScrollInfoPage(parent.transform, "OtherPage", out GameObject otherPage);
|
||||
infoSubPages.Add(otherPage);
|
||||
|
||||
qualityInfoText = CreateScrollInfoPage(parent.transform, "QualityPage", out GameObject qualPage);
|
||||
infoSubPages.Add(qualPage);
|
||||
|
||||
allInfoTexts.AddRange(new[] { systemInfoText, environmentInfoText, screenInfoText, inputInfoText, otherInfoText, qualityInfoText });
|
||||
|
||||
SwitchInfoSubTab(0);
|
||||
}
|
||||
|
||||
private void BuildProfilerPage(GameObject parent)
|
||||
{
|
||||
VerticalLayoutGroup vl = parent.AddComponent<VerticalLayoutGroup>();
|
||||
vl.spacing = 0;
|
||||
vl.padding = new RectOffset(0, 0, 0, 0);
|
||||
vl.childControlWidth = true;
|
||||
vl.childControlHeight = true;
|
||||
vl.childForceExpandWidth = true;
|
||||
vl.childForceExpandHeight = false;
|
||||
|
||||
// 二级标签栏
|
||||
GameObject subTabBar = CreateTabBar(parent.transform, "ProfilerSubTabBar", 80);
|
||||
|
||||
for (int i = 0; i < ProfilerSubTabNames.Length; i++)
|
||||
{
|
||||
int idx = i;
|
||||
Button btn = CreateTabButton(subTabBar.transform, GetTabLabel(ProfilerSubTabNames[i]), 26);
|
||||
btn.onClick.AddListener(() => SwitchProfilerSubTab(idx));
|
||||
profilerSubTabButtons.Add(btn);
|
||||
}
|
||||
|
||||
profilerSummaryText = CreateScrollInfoPage(parent.transform, "SummaryPage", out GameObject summaryPage);
|
||||
profilerSubPages.Add(summaryPage);
|
||||
// 添加嵌套 Canvas 隔离频繁文本刷新,避免整棵 UI 树 rebatch
|
||||
summaryPage.AddComponent<Canvas>();
|
||||
summaryPage.AddComponent<GraphicRaycaster>();
|
||||
|
||||
profilerMemoryText = CreateScrollInfoPage(parent.transform, "MemoryPage", out GameObject memoryPage);
|
||||
profilerSubPages.Add(memoryPage);
|
||||
// 同上:隔离 Profiler Memory 页的文本刷新
|
||||
memoryPage.AddComponent<Canvas>();
|
||||
memoryPage.AddComponent<GraphicRaycaster>();
|
||||
|
||||
allInfoTexts.Add(profilerSummaryText);
|
||||
allInfoTexts.Add(profilerMemoryText);
|
||||
|
||||
SwitchProfilerSubTab(0);
|
||||
}
|
||||
|
||||
private void BuildLanguagePage(GameObject parent)
|
||||
{
|
||||
VerticalLayoutGroup vl = parent.AddComponent<VerticalLayoutGroup>();
|
||||
vl.spacing = 20;
|
||||
vl.padding = new RectOffset(40, 40, 40, 40);
|
||||
vl.childControlWidth = true;
|
||||
vl.childControlHeight = false;
|
||||
vl.childForceExpandWidth = true;
|
||||
|
||||
// 标题
|
||||
GameObject title = CreateLabel(parent.transform, "LanguageTitle", "Language / 语言设置", 34);
|
||||
title.GetComponent<RectTransform>().sizeDelta = new Vector2(0, 60);
|
||||
LayoutElement titleLE = title.AddComponent<LayoutElement>();
|
||||
titleLE.preferredHeight = 60;
|
||||
|
||||
// 中文开关
|
||||
GameObject chnToggleObj = CreateLanguageToggle(parent.transform, "ChineseToggle",
|
||||
"显示中文 / Show Chinese", showChinese, (val) =>
|
||||
{
|
||||
showChinese = val;
|
||||
RefreshTabLabels();
|
||||
RefreshAllInfo();
|
||||
});
|
||||
|
||||
// 说明文字
|
||||
GameObject desc = CreateLabel(parent.transform, "LanguageDesc",
|
||||
"开启后信息页面将同时显示英文原文和中文翻译。\nWhen enabled, info pages show both English and Chinese translations.", 22);
|
||||
desc.GetComponent<TextMeshProUGUI>().color = new Color(0.7f, 0.7f, 0.7f, 1f);
|
||||
desc.GetComponent<RectTransform>().sizeDelta = new Vector2(0, 100);
|
||||
LayoutElement descLE = desc.AddComponent<LayoutElement>();
|
||||
descLE.preferredHeight = 100;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 标签切换
|
||||
|
||||
private void SwitchPrimaryTab(int index)
|
||||
{
|
||||
activePrimaryIndex = index;
|
||||
for (int i = 0; i < primaryPages.Count; i++)
|
||||
{
|
||||
primaryPages[i].SetActive(i == index);
|
||||
}
|
||||
for (int i = 0; i < primaryTabButtons.Count; i++)
|
||||
{
|
||||
primaryTabButtons[i].GetComponent<Image>().color = i == index ? ActiveTabColor : InactiveTabColor;
|
||||
}
|
||||
|
||||
if (index == 0) RefreshCurrentInfoSubTab();
|
||||
if (index == 1)
|
||||
{
|
||||
lastProfilerRefreshTime = 0;
|
||||
RefreshProfilerSummary();
|
||||
RefreshProfilerMemory();
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchInfoSubTab(int index)
|
||||
{
|
||||
activeInfoSubIndex = index;
|
||||
for (int i = 0; i < infoSubPages.Count; i++)
|
||||
{
|
||||
infoSubPages[i].SetActive(i == index);
|
||||
}
|
||||
for (int i = 0; i < infoSubTabButtons.Count; i++)
|
||||
{
|
||||
infoSubTabButtons[i].GetComponent<Image>().color = i == index ? SubActiveTabColor : SubInactiveTabColor;
|
||||
}
|
||||
RefreshCurrentInfoSubTab();
|
||||
}
|
||||
|
||||
private void SwitchProfilerSubTab(int index)
|
||||
{
|
||||
activeProfilerSubIndex = index;
|
||||
for (int i = 0; i < profilerSubPages.Count; i++)
|
||||
{
|
||||
profilerSubPages[i].SetActive(i == index);
|
||||
}
|
||||
for (int i = 0; i < profilerSubTabButtons.Count; i++)
|
||||
{
|
||||
profilerSubTabButtons[i].GetComponent<Image>().color = i == index ? SubActiveTabColor : SubInactiveTabColor;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshCurrentInfoSubTab()
|
||||
{
|
||||
switch (activeInfoSubIndex)
|
||||
{
|
||||
case 0: RefreshSystemInfo(); break;
|
||||
case 1: RefreshEnvironmentInfo(); break;
|
||||
case 2: RefreshScreenInfo(); break;
|
||||
case 3: RefreshInputInfo(); break;
|
||||
case 4: RefreshOtherInfo(); break;
|
||||
case 5: RefreshQualityInfo(); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshTabLabels()
|
||||
{
|
||||
for (int i = 0; i < primaryTabButtons.Count && i < PrimaryTabNames.Length; i++)
|
||||
{
|
||||
TMP_Text txt = primaryTabButtons[i].GetComponentInChildren<TMP_Text>();
|
||||
if (txt != null)
|
||||
txt.text = GetTabLabel(PrimaryTabNames[i]);
|
||||
}
|
||||
for (int i = 0; i < infoSubTabButtons.Count && i < InfoSubTabNames.Length; i++)
|
||||
{
|
||||
TMP_Text txt = infoSubTabButtons[i].GetComponentInChildren<TMP_Text>();
|
||||
if (txt != null)
|
||||
txt.text = GetTabLabel(InfoSubTabNames[i]);
|
||||
}
|
||||
for (int i = 0; i < profilerSubTabButtons.Count && i < ProfilerSubTabNames.Length; i++)
|
||||
{
|
||||
TMP_Text txt = profilerSubTabButtons[i].GetComponentInChildren<TMP_Text>();
|
||||
if (txt != null)
|
||||
txt.text = GetTabLabel(ProfilerSubTabNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回标签显示文字。中文模式: "English/中文",英文模式: "English"
|
||||
/// </summary>
|
||||
private string GetTabLabel(string[] pair)
|
||||
{
|
||||
return showChinese ? $"{pair[0]}/{pair[1]}" : pair[0];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 信息刷新 - Information
|
||||
|
||||
private void RefreshSystemInfo()
|
||||
{
|
||||
if (systemInfoText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(L("Device Name / 设备名称", SystemInfo.deviceName));
|
||||
sb.AppendLine(L("Device Model / 设备型号", SystemInfo.deviceModel));
|
||||
sb.AppendLine(L("Device Type / 设备类型", SystemInfo.deviceType.ToString()));
|
||||
sb.AppendLine(L("Device Unique Identifier / 设备唯一标识", SystemInfo.deviceUniqueIdentifier));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Operating System / 操作系统", SystemInfo.operatingSystem));
|
||||
sb.AppendLine(L("Operating System Family / 操作系统系列", SystemInfo.operatingSystemFamily.ToString()));
|
||||
sb.AppendLine(L("Processor Type / 处理器类型", SystemInfo.processorType));
|
||||
sb.AppendLine(L("Processor Count / 处理器核心数", SystemInfo.processorCount.ToString()));
|
||||
sb.AppendLine(L("Processor Frequency / 处理器频率", $"{SystemInfo.processorFrequency} MHz"));
|
||||
sb.AppendLine(L("System Memory Size / 系统内存大小", $"{SystemInfo.systemMemorySize} MB"));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Graphics Device Name / 显卡名称", SystemInfo.graphicsDeviceName));
|
||||
sb.AppendLine(L("Graphics Device Vendor / 显卡厂商", SystemInfo.graphicsDeviceVendor));
|
||||
sb.AppendLine(L("Graphics Device Type / 图形API类型", SystemInfo.graphicsDeviceType.ToString()));
|
||||
sb.AppendLine(L("Graphics Device Version / 图形API版本", SystemInfo.graphicsDeviceVersion));
|
||||
sb.AppendLine(L("Graphics Memory Size / 显存大小", $"{SystemInfo.graphicsMemorySize} MB"));
|
||||
sb.AppendLine(L("Graphics Shader Level / 着色器等级", SystemInfo.graphicsShaderLevel.ToString()));
|
||||
sb.AppendLine(L("Graphics Multi Threaded / 多线程渲染", SystemInfo.graphicsMultiThreaded.ToString()));
|
||||
sb.AppendLine(L("Max Texture Size / 最大纹理尺寸", SystemInfo.maxTextureSize.ToString()));
|
||||
|
||||
systemInfoText.text = sb.ToString();
|
||||
}
|
||||
|
||||
private void RefreshEnvironmentInfo()
|
||||
{
|
||||
if (environmentInfoText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(L("Unity Version / Unity版本", Application.unityVersion));
|
||||
sb.AppendLine(L("Platform / 运行平台", Application.platform.ToString()));
|
||||
sb.AppendLine(L("System Language / 系统语言", Application.systemLanguage.ToString()));
|
||||
sb.AppendLine(L("Internet Reachability / 网络可达性", Application.internetReachability.ToString()));
|
||||
sb.AppendLine(L("Run In Background / 允许后台运行", Application.runInBackground.ToString()));
|
||||
sb.AppendLine(L("Install Mode / 安装模式", Application.installMode.ToString()));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Product Name / 产品名称", Application.productName));
|
||||
sb.AppendLine(L("Company Name / 公司名称", Application.companyName));
|
||||
sb.AppendLine(L("Identifier / 应用标识", Application.identifier));
|
||||
sb.AppendLine(L("Version / 版本号", Application.version));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Data Path / 数据路径", Application.dataPath));
|
||||
sb.AppendLine(L("Persistent Data Path / 持久化数据路径", Application.persistentDataPath));
|
||||
sb.AppendLine(L("Temporary Cache Path / 临时缓存路径", Application.temporaryCachePath));
|
||||
sb.AppendLine(L("Streaming Assets Path / 流式资源路径", Application.streamingAssetsPath));
|
||||
|
||||
environmentInfoText.text = sb.ToString();
|
||||
}
|
||||
|
||||
private void RefreshScreenInfo()
|
||||
{
|
||||
if (screenInfoText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(L("Screen Width / 屏幕宽度", Screen.width.ToString()));
|
||||
sb.AppendLine(L("Screen Height / 屏幕高度", Screen.height.ToString()));
|
||||
sb.AppendLine(L("DPI / 屏幕DPI", Screen.dpi.ToString("F1")));
|
||||
sb.AppendLine(L("Full Screen / 是否全屏", Screen.fullScreen.ToString()));
|
||||
sb.AppendLine(L("Full Screen Mode / 全屏模式", Screen.fullScreenMode.ToString()));
|
||||
sb.AppendLine(L("Orientation / 屏幕方向", Screen.orientation.ToString()));
|
||||
sb.AppendLine(L("Sleep Timeout / 休眠超时", Screen.sleepTimeout.ToString()));
|
||||
sb.AppendLine(L("Brightness / 屏幕亮度", Screen.brightness.ToString("F2")));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Current Resolution / 当前分辨率", $"{Screen.currentResolution.width} x {Screen.currentResolution.height}"));
|
||||
sb.AppendLine(L("Refresh Rate / 刷新率", $"{Screen.currentResolution.refreshRateRatio.value:F2} Hz"));
|
||||
sb.AppendLine();
|
||||
Rect safeArea = Screen.safeArea;
|
||||
sb.AppendLine(L("Safe Area / 安全区域", $"x:{safeArea.x:F0} y:{safeArea.y:F0} w:{safeArea.width:F0} h:{safeArea.height:F0}"));
|
||||
|
||||
screenInfoText.text = sb.ToString();
|
||||
}
|
||||
|
||||
private void RefreshInputInfo()
|
||||
{
|
||||
if (inputInfoText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(L("Supports Accelerometer / 支持加速度计", SystemInfo.supportsAccelerometer.ToString()));
|
||||
sb.AppendLine(L("Supports Gyroscope / 支持陀螺仪", SystemInfo.supportsGyroscope.ToString()));
|
||||
sb.AppendLine(L("Supports Location Service / 支持定位服务", SystemInfo.supportsLocationService.ToString()));
|
||||
sb.AppendLine(L("Supports Vibration / 支持振动", SystemInfo.supportsVibration.ToString()));
|
||||
sb.AppendLine(L("Supports Audio / 支持音频", SystemInfo.supportsAudio.ToString()));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Device Supports Multi Touch / 支持多点触控", Input.multiTouchEnabled.ToString()));
|
||||
sb.AppendLine(L("Touch Supported / 触屏支持", Input.touchSupported.ToString()));
|
||||
sb.AppendLine(L("Touch Count / 当前触摸点数", Input.touchCount.ToString()));
|
||||
sb.AppendLine(L("Mouse Present / 鼠标可用", Input.mousePresent.ToString()));
|
||||
sb.AppendLine();
|
||||
|
||||
// 当前触摸信息
|
||||
if (Input.touchCount > 0)
|
||||
{
|
||||
sb.AppendLine(L("--- Touch Details / 触摸详情 ---", ""));
|
||||
for (int i = 0; i < Input.touchCount; i++)
|
||||
{
|
||||
Touch t = Input.GetTouch(i);
|
||||
sb.AppendLine($" Touch[{i}]: pos=({t.position.x:F0},{t.position.y:F0}) phase={t.phase}");
|
||||
}
|
||||
}
|
||||
|
||||
// 加速度计
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Acceleration / 加速度", Input.acceleration.ToString("F3")));
|
||||
sb.AppendLine(L("Compass Enabled / 指南针启用", Input.compass.enabled.ToString()));
|
||||
|
||||
inputInfoText.text = sb.ToString();
|
||||
}
|
||||
|
||||
private void RefreshOtherInfo()
|
||||
{
|
||||
if (otherInfoText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(L("Battery Status / 电池状态", SystemInfo.batteryStatus.ToString()));
|
||||
sb.AppendLine(L("Battery Level / 电池电量",
|
||||
SystemInfo.batteryLevel < 0f ? "Unknown / 未知" : $"{SystemInfo.batteryLevel * 100f:F0}%"));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("Supports Compute Shaders / 支持计算着色器", SystemInfo.supportsComputeShaders.ToString()));
|
||||
sb.AppendLine(L("Supports Instancing / 支持GPU实例化", SystemInfo.supportsInstancing.ToString()));
|
||||
sb.AppendLine(L("Supports 3D Textures / 支持3D纹理", SystemInfo.supports3DTextures.ToString()));
|
||||
sb.AppendLine(L("Supports 3D Render Textures / 支持3D渲染纹理", SystemInfo.supports3DRenderTextures.ToString()));
|
||||
sb.AppendLine(L("Supports Raw Shadow Depth Sampling / 支持阴影深度采样", SystemInfo.supportsRawShadowDepthSampling.ToString()));
|
||||
sb.AppendLine(L("NPOT Support / NPOT纹理支持", SystemInfo.npotSupport.ToString()));
|
||||
sb.AppendLine(L("Copy Texture Support / 纹理拷贝支持", SystemInfo.copyTextureSupport.ToString()));
|
||||
sb.AppendLine(L("Supported Render Target Count / 支持渲染目标数", SystemInfo.supportedRenderTargetCount.ToString()));
|
||||
sb.AppendLine(L("Supported Random Write Target Count / 支持随机写入目标数", SystemInfo.supportedRandomWriteTargetCount.ToString()));
|
||||
sb.AppendLine(L("Uses Reversed ZBuffer / 使用反向ZBuffer", SystemInfo.usesReversedZBuffer.ToString()));
|
||||
sb.AppendLine(L("Graphics UV Starts At Top / 图形UV起点在顶部", SystemInfo.graphicsUVStartsAtTop.ToString()));
|
||||
|
||||
otherInfoText.text = sb.ToString();
|
||||
}
|
||||
|
||||
private void RefreshQualityInfo()
|
||||
{
|
||||
if (qualityInfoText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
string qualityLevel = QualitySettings.names.Length > 0
|
||||
? QualitySettings.names[Mathf.Clamp(QualitySettings.GetQualityLevel(), 0, QualitySettings.names.Length - 1)]
|
||||
: "Unknown";
|
||||
|
||||
sb.AppendLine(L("Quality Level / 画质等级", qualityLevel));
|
||||
sb.AppendLine(L("Target Frame Rate / 目标帧率", Application.targetFrameRate.ToString()));
|
||||
int fps = Mathf.RoundToInt(1f / Mathf.Max(0.0001f, Time.unscaledDeltaTime));
|
||||
sb.AppendLine(L("Current FPS / 当前帧率", fps.ToString()));
|
||||
sb.AppendLine(L("VSync Count / 垂直同步", QualitySettings.vSyncCount.ToString()));
|
||||
sb.AppendLine(L("Anti Aliasing / 抗锯齿", QualitySettings.antiAliasing.ToString()));
|
||||
sb.AppendLine(L("Pixel Light Count / 像素灯数量", QualitySettings.pixelLightCount.ToString()));
|
||||
sb.AppendLine(L("Shadow Distance / 阴影距离", QualitySettings.shadowDistance.ToString("F1")));
|
||||
sb.AppendLine(L("Shadow Resolution / 阴影分辨率", QualitySettings.shadowResolution.ToString()));
|
||||
sb.AppendLine(L("Shadow Cascades / 阴影级联数", QualitySettings.shadowCascades.ToString()));
|
||||
sb.AppendLine(L("LOD Bias / LOD偏移", QualitySettings.lodBias.ToString("F2")));
|
||||
sb.AppendLine(L("Maximum LOD Level / 最大LOD等级", QualitySettings.maximumLODLevel.ToString()));
|
||||
sb.AppendLine(L("Anisotropic Filtering / 各向异性过滤", QualitySettings.anisotropicFiltering.ToString()));
|
||||
sb.AppendLine(L("Texture Quality / 贴图质量", QualitySettings.globalTextureMipmapLimit.ToString()));
|
||||
|
||||
qualityInfoText.text = sb.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 信息刷新 - Profiler
|
||||
|
||||
private void RefreshProfilerSummary()
|
||||
{
|
||||
if (profilerSummaryText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int fps = Mathf.RoundToInt(1f / Mathf.Max(0.0001f, Time.unscaledDeltaTime));
|
||||
sb.AppendLine(L("FPS / 帧率", fps.ToString()));
|
||||
sb.AppendLine(L("Frame Time / 帧耗时", $"{Time.unscaledDeltaTime * 1000f:F2} ms"));
|
||||
sb.AppendLine(L("Time Since Startup / 应用运行时间", $"{Time.realtimeSinceStartup:F1} s"));
|
||||
sb.AppendLine(L("Time Scale / 时间缩放", Time.timeScale.ToString("F2")));
|
||||
sb.AppendLine(L("Frame Count / 总帧数", Time.frameCount.ToString()));
|
||||
sb.AppendLine();
|
||||
|
||||
long totalAllocated = Profiler.GetTotalAllocatedMemoryLong();
|
||||
long totalReserved = Profiler.GetTotalReservedMemoryLong();
|
||||
long totalUnused = Profiler.GetTotalUnusedReservedMemoryLong();
|
||||
long monoHeap = Profiler.GetMonoHeapSizeLong();
|
||||
long monoUsed = Profiler.GetMonoUsedSizeLong();
|
||||
|
||||
sb.AppendLine(L("Total Allocated Memory / 总分配内存", FormatBytes(totalAllocated)));
|
||||
sb.AppendLine(L("Total Reserved Memory / 总保留内存", FormatBytes(totalReserved)));
|
||||
sb.AppendLine(L("Total Unused Reserved / 未使用保留内存", FormatBytes(totalUnused)));
|
||||
sb.AppendLine(L("Mono Heap Size / Mono堆大小", FormatBytes(monoHeap)));
|
||||
sb.AppendLine(L("Mono Used Size / Mono已用大小", FormatBytes(monoUsed)));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("GC Collection Count (Gen0) / GC回收次数(第0代)", GC.CollectionCount(0).ToString()));
|
||||
sb.AppendLine(L("GC Collection Count (Gen1) / GC回收次数(第1代)", GC.CollectionCount(1).ToString()));
|
||||
sb.AppendLine(L("GC Collection Count (Gen2) / GC回收次数(第2代)", GC.CollectionCount(2).ToString()));
|
||||
|
||||
profilerSummaryText.text = sb.ToString();
|
||||
}
|
||||
|
||||
private void RefreshProfilerMemory()
|
||||
{
|
||||
if (profilerMemoryText == null) return;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
long totalAllocated = Profiler.GetTotalAllocatedMemoryLong();
|
||||
long totalReserved = Profiler.GetTotalReservedMemoryLong();
|
||||
long totalUnused = Profiler.GetTotalUnusedReservedMemoryLong();
|
||||
long monoHeap = Profiler.GetMonoHeapSizeLong();
|
||||
long monoUsed = Profiler.GetMonoUsedSizeLong();
|
||||
long gcTotalMemory = GC.GetTotalMemory(false);
|
||||
|
||||
sb.AppendLine(L("=== Unity Memory / Unity内存 ===", ""));
|
||||
sb.AppendLine(L("Total Allocated / 总分配", FormatBytes(totalAllocated)));
|
||||
sb.AppendLine(L("Total Reserved / 总保留", FormatBytes(totalReserved)));
|
||||
sb.AppendLine(L("Unused Reserved / 未用保留", FormatBytes(totalUnused)));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("=== Mono / Managed Memory / 托管内存 ===", ""));
|
||||
sb.AppendLine(L("Mono Heap / Mono堆", FormatBytes(monoHeap)));
|
||||
sb.AppendLine(L("Mono Used / Mono已用", FormatBytes(monoUsed)));
|
||||
sb.AppendLine(L("GC Total Memory / GC总内存", FormatBytes(gcTotalMemory)));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(L("=== System / 系统 ===", ""));
|
||||
sb.AppendLine(L("System Memory Size / 系统内存", $"{SystemInfo.systemMemorySize} MB"));
|
||||
sb.AppendLine(L("Graphics Memory Size / 显存", $"{SystemInfo.graphicsMemorySize} MB"));
|
||||
|
||||
profilerMemoryText.text = sb.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI 辅助方法
|
||||
|
||||
private GameObject CreateTabBar(Transform parent, string name, float height)
|
||||
{
|
||||
GameObject bar = new GameObject(name);
|
||||
bar.transform.SetParent(parent, false);
|
||||
RectTransform rect = bar.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = new Vector2(0, height);
|
||||
LayoutElement le = bar.AddComponent<LayoutElement>();
|
||||
le.preferredHeight = height;
|
||||
le.flexibleHeight = 0;
|
||||
|
||||
HorizontalLayoutGroup hl = bar.AddComponent<HorizontalLayoutGroup>();
|
||||
hl.spacing = 8;
|
||||
hl.padding = new RectOffset(8, 8, 4, 4);
|
||||
hl.childControlWidth = true;
|
||||
hl.childControlHeight = true;
|
||||
hl.childForceExpandWidth = true;
|
||||
hl.childForceExpandHeight = true;
|
||||
|
||||
Image bg = bar.AddComponent<Image>();
|
||||
bg.color = new Color(0.12f, 0.12f, 0.12f, 1f);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
private Button CreateTabButton(Transform parent, string text, int fontSize = 30)
|
||||
{
|
||||
GameObject btnObj = new GameObject($"Tab_{text}");
|
||||
btnObj.transform.SetParent(parent, false);
|
||||
RectTransform rect = btnObj.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = new Vector2(0, 0);
|
||||
|
||||
Image img = btnObj.AddComponent<Image>();
|
||||
img.color = InactiveTabColor;
|
||||
|
||||
Button btn = btnObj.AddComponent<Button>();
|
||||
btn.targetGraphic = img;
|
||||
|
||||
GameObject txtObj = new GameObject("Text");
|
||||
txtObj.transform.SetParent(btnObj.transform, false);
|
||||
RectTransform txtRect = txtObj.AddComponent<RectTransform>();
|
||||
txtRect.anchorMin = Vector2.zero;
|
||||
txtRect.anchorMax = Vector2.one;
|
||||
txtRect.offsetMin = new Vector2(4, 2);
|
||||
txtRect.offsetMax = new Vector2(-4, -2);
|
||||
|
||||
TextMeshProUGUI tmp = txtObj.AddComponent<TextMeshProUGUI>();
|
||||
tmp.text = text;
|
||||
tmp.fontSize = fontSize;
|
||||
tmp.fontStyle = FontStyles.Bold;
|
||||
tmp.alignment = TextAlignmentOptions.Center;
|
||||
tmp.color = Color.white;
|
||||
tmp.enableAutoSizing = true;
|
||||
tmp.fontSizeMin = 12;
|
||||
tmp.fontSizeMax = 72;
|
||||
tmp.enableWordWrapping = false;
|
||||
|
||||
TMP_FontAsset font = TMP_Settings.defaultFontAsset;
|
||||
if (font == null) font = Resources.Load<TMP_FontAsset>("Fonts & Materials/LiberationSans SDF");
|
||||
if (font != null) tmp.font = font;
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
private GameObject CreatePageContainer(Transform parent, string name)
|
||||
{
|
||||
GameObject page = new GameObject(name);
|
||||
page.transform.SetParent(parent, false);
|
||||
RectTransform rect = page.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = Vector2.zero;
|
||||
|
||||
LayoutElement le = page.AddComponent<LayoutElement>();
|
||||
le.flexibleHeight = 1;
|
||||
|
||||
page.SetActive(false);
|
||||
return page;
|
||||
}
|
||||
|
||||
private TMP_Text CreateScrollInfoPage(Transform parent, string name, out GameObject pageObj)
|
||||
{
|
||||
pageObj = new GameObject(name);
|
||||
pageObj.transform.SetParent(parent, false);
|
||||
RectTransform rect = pageObj.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = Vector2.zero;
|
||||
|
||||
LayoutElement le = pageObj.AddComponent<LayoutElement>();
|
||||
le.flexibleHeight = 1;
|
||||
|
||||
// ScrollView
|
||||
ScrollRect scroll = pageObj.AddComponent<ScrollRect>();
|
||||
scroll.horizontal = false;
|
||||
scroll.vertical = true;
|
||||
|
||||
GameObject viewport = new GameObject("Viewport");
|
||||
viewport.transform.SetParent(pageObj.transform, false);
|
||||
RectTransform vpRect = viewport.AddComponent<RectTransform>();
|
||||
vpRect.anchorMin = Vector2.zero;
|
||||
vpRect.anchorMax = Vector2.one;
|
||||
vpRect.sizeDelta = Vector2.zero;
|
||||
viewport.AddComponent<Image>().color = new Color(0.06f, 0.06f, 0.08f, 0.6f);
|
||||
viewport.AddComponent<Mask>().showMaskGraphic = true;
|
||||
|
||||
GameObject content = new GameObject("Content");
|
||||
content.transform.SetParent(viewport.transform, false);
|
||||
RectTransform contentRect = content.AddComponent<RectTransform>();
|
||||
contentRect.anchorMin = new Vector2(0, 1);
|
||||
contentRect.anchorMax = new Vector2(1, 1);
|
||||
contentRect.pivot = new Vector2(0.5f, 1);
|
||||
contentRect.sizeDelta = Vector2.zero;
|
||||
|
||||
ContentSizeFitter fitter = content.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
VerticalLayoutGroup vl = content.AddComponent<VerticalLayoutGroup>();
|
||||
vl.padding = new RectOffset(20, 20, 16, 16);
|
||||
vl.childControlWidth = true;
|
||||
vl.childControlHeight = true;
|
||||
vl.childForceExpandWidth = true;
|
||||
vl.childForceExpandHeight = false;
|
||||
|
||||
scroll.viewport = vpRect;
|
||||
scroll.content = contentRect;
|
||||
|
||||
// 文本
|
||||
GameObject textObj = new GameObject("InfoText");
|
||||
textObj.transform.SetParent(content.transform, false);
|
||||
|
||||
TextMeshProUGUI tmp = textObj.AddComponent<TextMeshProUGUI>();
|
||||
tmp.text = "";
|
||||
tmp.fontSize = 28;
|
||||
tmp.fontStyle = FontStyles.Bold;
|
||||
tmp.alignment = TextAlignmentOptions.TopLeft;
|
||||
tmp.color = new Color(0.9f, 0.92f, 0.94f, 1f);
|
||||
tmp.enableWordWrapping = true;
|
||||
tmp.richText = true;
|
||||
|
||||
ContentSizeFitter textFitter = textObj.AddComponent<ContentSizeFitter>();
|
||||
textFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
TMP_FontAsset font = TMP_Settings.defaultFontAsset;
|
||||
if (font == null) font = Resources.Load<TMP_FontAsset>("Fonts & Materials/LiberationSans SDF");
|
||||
if (font != null) tmp.font = font;
|
||||
|
||||
pageObj.SetActive(false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private GameObject CreateActionBar(Transform parent)
|
||||
{
|
||||
GameObject bar = new GameObject("ActionBar");
|
||||
bar.transform.SetParent(parent, false);
|
||||
RectTransform rect = bar.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = new Vector2(0, 80);
|
||||
LayoutElement le = bar.AddComponent<LayoutElement>();
|
||||
le.preferredHeight = 80;
|
||||
le.flexibleHeight = 0;
|
||||
|
||||
HorizontalLayoutGroup hl = bar.AddComponent<HorizontalLayoutGroup>();
|
||||
hl.spacing = 12;
|
||||
hl.padding = new RectOffset(16, 16, 8, 8);
|
||||
hl.childControlWidth = true;
|
||||
hl.childControlHeight = true;
|
||||
hl.childForceExpandWidth = true;
|
||||
hl.childForceExpandHeight = true;
|
||||
|
||||
// 刷新按钮
|
||||
Button refreshBtn = CreateTabButton(bar.transform, showChinese ? "Refresh / 刷新" : "Refresh", 24);
|
||||
refreshBtn.GetComponent<Image>().color = new Color(0.32f, 0.38f, 0.46f, 1f);
|
||||
refreshBtn.onClick.AddListener(() => RefreshAllInfo());
|
||||
|
||||
// 复制全部按钮
|
||||
Button copyBtn = CreateTabButton(bar.transform, showChinese ? "Copy All / 复制全部" : "Copy All", 24);
|
||||
copyBtn.GetComponent<Image>().color = new Color(0.42f, 0.48f, 0.56f, 1f);
|
||||
copyBtn.onClick.AddListener(() => CopyAllInfoToClipboard());
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
private GameObject CreateLabel(Transform parent, string name, string text, int fontSize)
|
||||
{
|
||||
GameObject obj = new GameObject(name);
|
||||
obj.transform.SetParent(parent, false);
|
||||
RectTransform rect = obj.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = new Vector2(0, 50);
|
||||
|
||||
TextMeshProUGUI tmp = obj.AddComponent<TextMeshProUGUI>();
|
||||
tmp.text = text;
|
||||
tmp.fontSize = fontSize;
|
||||
tmp.fontStyle = FontStyles.Bold;
|
||||
tmp.enableAutoSizing = true;
|
||||
tmp.fontSizeMin = 12;
|
||||
tmp.fontSizeMax = 72;
|
||||
tmp.alignment = TextAlignmentOptions.Left;
|
||||
tmp.color = Color.white;
|
||||
tmp.enableWordWrapping = true;
|
||||
|
||||
TMP_FontAsset font = TMP_Settings.defaultFontAsset;
|
||||
if (font == null) font = Resources.Load<TMP_FontAsset>("Fonts & Materials/LiberationSans SDF");
|
||||
if (font != null) tmp.font = font;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private GameObject CreateLanguageToggle(Transform parent, string name, string label, bool defaultValue, System.Action<bool> onChanged)
|
||||
{
|
||||
GameObject toggleObj = new GameObject(name);
|
||||
toggleObj.transform.SetParent(parent, false);
|
||||
RectTransform rect = toggleObj.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = new Vector2(0, 80);
|
||||
LayoutElement le = toggleObj.AddComponent<LayoutElement>();
|
||||
le.preferredHeight = 80;
|
||||
|
||||
Image bg = toggleObj.AddComponent<Image>();
|
||||
bg.color = new Color(0.18f, 0.18f, 0.18f, 1f);
|
||||
|
||||
Toggle toggle = toggleObj.AddComponent<Toggle>();
|
||||
toggle.isOn = defaultValue;
|
||||
|
||||
// Checkbox背景
|
||||
GameObject checkBg = new GameObject("Background");
|
||||
checkBg.transform.SetParent(toggleObj.transform, false);
|
||||
RectTransform checkBgRect = checkBg.AddComponent<RectTransform>();
|
||||
checkBgRect.anchorMin = new Vector2(0, 0.5f);
|
||||
checkBgRect.anchorMax = new Vector2(0, 0.5f);
|
||||
checkBgRect.pivot = new Vector2(0, 0.5f);
|
||||
checkBgRect.sizeDelta = new Vector2(50, 50);
|
||||
checkBgRect.anchoredPosition = new Vector2(16, 0);
|
||||
Image checkBgImg = checkBg.AddComponent<Image>();
|
||||
checkBgImg.color = new Color(0.8f, 0.8f, 0.8f, 1f);
|
||||
|
||||
// Checkmark
|
||||
GameObject checkmark = new GameObject("Checkmark");
|
||||
checkmark.transform.SetParent(checkBg.transform, false);
|
||||
RectTransform cmRect = checkmark.AddComponent<RectTransform>();
|
||||
cmRect.anchorMin = Vector2.zero;
|
||||
cmRect.anchorMax = Vector2.one;
|
||||
cmRect.sizeDelta = new Vector2(-8, -8);
|
||||
Image cmImg = checkmark.AddComponent<Image>();
|
||||
cmImg.color = new Color(0.2f, 0.8f, 0.2f, 1f);
|
||||
|
||||
toggle.targetGraphic = checkBgImg;
|
||||
toggle.graphic = cmImg;
|
||||
|
||||
// Label
|
||||
GameObject labelObj = new GameObject("Label");
|
||||
labelObj.transform.SetParent(toggleObj.transform, false);
|
||||
RectTransform labelRect = labelObj.AddComponent<RectTransform>();
|
||||
labelRect.anchorMin = new Vector2(0, 0);
|
||||
labelRect.anchorMax = new Vector2(1, 1);
|
||||
labelRect.offsetMin = new Vector2(80, 0);
|
||||
labelRect.offsetMax = new Vector2(-16, 0);
|
||||
|
||||
TextMeshProUGUI labelTmp = labelObj.AddComponent<TextMeshProUGUI>();
|
||||
labelTmp.text = label;
|
||||
labelTmp.fontSize = 28;
|
||||
labelTmp.fontStyle = FontStyles.Bold;
|
||||
labelTmp.enableAutoSizing = true;
|
||||
labelTmp.fontSizeMin = 12;
|
||||
labelTmp.fontSizeMax = 72;
|
||||
labelTmp.alignment = TextAlignmentOptions.MidlineLeft;
|
||||
labelTmp.color = Color.white;
|
||||
|
||||
TMP_FontAsset font = TMP_Settings.defaultFontAsset;
|
||||
if (font == null) font = Resources.Load<TMP_FontAsset>("Fonts & Materials/LiberationSans SDF");
|
||||
if (font != null) labelTmp.font = font;
|
||||
|
||||
toggle.onValueChanged.AddListener((val) => onChanged?.Invoke(val));
|
||||
|
||||
return toggleObj;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 工具方法
|
||||
|
||||
/// <summary>
|
||||
/// 根据语言设置格式化一行信息。
|
||||
/// 如果开启中文: "English / 中文: value"
|
||||
/// 如果关闭中文 (纯英文): 仅显示 / 前的英文部分
|
||||
/// </summary>
|
||||
private string L(string bilingualKey, string value)
|
||||
{
|
||||
string key;
|
||||
if (showChinese)
|
||||
{
|
||||
key = bilingualKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 取 "/" 之前的英文部分
|
||||
int slashIdx = bilingualKey.IndexOf('/');
|
||||
key = slashIdx > 0 ? bilingualKey.Substring(0, slashIdx).TrimEnd() : bilingualKey;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return key;
|
||||
|
||||
return $"{key}: {value}";
|
||||
}
|
||||
|
||||
private static string FormatBytes(long bytes)
|
||||
{
|
||||
if (bytes < 1024) return $"{bytes} B";
|
||||
if (bytes < 1024 * 1024) return $"{bytes / 1024f:F2} KB";
|
||||
if (bytes < 1024 * 1024 * 1024) return $"{bytes / (1024f * 1024f):F2} MB";
|
||||
return $"{bytes / (1024f * 1024f * 1024f):F2} GB";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee0f30848472b844c87ba31a39a3fca5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ddf96f73f2918f64f908000cd6d4de2e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,221 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置模块 - 提供窗口全屏布局与缓存池设置功能
|
||||
/// </summary>
|
||||
public class SettingsModule : IDebugModule
|
||||
{
|
||||
#region 字段
|
||||
private GameObject settingsPage;
|
||||
private TMP_InputField widthInputField;
|
||||
private TMP_InputField heightInputField;
|
||||
private Button applyResolutionButton;
|
||||
private Button resetResolutionButton;
|
||||
private TMP_Text currentResolutionText;
|
||||
|
||||
// Console Log缓存池设置
|
||||
private TMP_InputField infoBufferInputField;
|
||||
private TMP_InputField warningBufferInputField;
|
||||
private TMP_InputField errorBufferInputField;
|
||||
private TMP_InputField fatalBufferInputField;
|
||||
private Button applyBufferButton;
|
||||
private Button resetBufferButton;
|
||||
private ConsoleModule consoleModule;
|
||||
|
||||
// 主窗口引用
|
||||
private RectTransform mainWindow;
|
||||
|
||||
private Vector2 detectedScreenResolution;
|
||||
|
||||
// 默认缓存池大小
|
||||
private const int DEFAULT_BUFFER_SIZE = 50;
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
public SettingsModule(GameObject page, TMP_InputField widthInput, TMP_InputField heightInput,
|
||||
Button applyButton, Button resetButton, TMP_Text resolutionText,
|
||||
TMP_InputField infoBufferInput, TMP_InputField warningBufferInput,
|
||||
TMP_InputField errorBufferInput, TMP_InputField fatalBufferInput,
|
||||
Button applyBufferBtn, Button resetBufferBtn,
|
||||
RectTransform mainWin)
|
||||
{
|
||||
settingsPage = page;
|
||||
widthInputField = widthInput;
|
||||
heightInputField = heightInput;
|
||||
applyResolutionButton = applyButton;
|
||||
resetResolutionButton = resetButton;
|
||||
currentResolutionText = resolutionText;
|
||||
|
||||
infoBufferInputField = infoBufferInput;
|
||||
warningBufferInputField = warningBufferInput;
|
||||
errorBufferInputField = errorBufferInput;
|
||||
fatalBufferInputField = fatalBufferInput;
|
||||
applyBufferButton = applyBufferBtn;
|
||||
resetBufferButton = resetBufferBtn;
|
||||
|
||||
mainWindow = mainWin;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDebugModule 实现
|
||||
public void Initialize()
|
||||
{
|
||||
Debug.Log("[SettingsModule] 初始化设置模块...");
|
||||
|
||||
if (widthInputField != null)
|
||||
widthInputField.readOnly = true;
|
||||
|
||||
if (heightInputField != null)
|
||||
heightInputField.readOnly = true;
|
||||
|
||||
if (applyResolutionButton != null)
|
||||
applyResolutionButton.interactable = false;
|
||||
|
||||
if (resetResolutionButton != null)
|
||||
resetResolutionButton.onClick.AddListener(RefreshAutoResolution);
|
||||
|
||||
if (applyBufferButton != null)
|
||||
applyBufferButton.onClick.AddListener(ApplyBufferSize);
|
||||
|
||||
if (resetBufferButton != null)
|
||||
resetBufferButton.onClick.AddListener(ResetBufferSize);
|
||||
|
||||
// 自动识别并应用当前屏幕全屏布局
|
||||
RefreshAutoResolution();
|
||||
|
||||
// 设置默认缓存池大小
|
||||
ResetBufferSize();
|
||||
}
|
||||
|
||||
public GameObject GetPage()
|
||||
{
|
||||
return settingsPage;
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return "设置";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新识别并应用当前屏幕分辨率
|
||||
/// </summary>
|
||||
public void RefreshAutoResolution()
|
||||
{
|
||||
detectedScreenResolution = new Vector2(Screen.width, Screen.height);
|
||||
UpdateResolutionInputs(detectedScreenResolution);
|
||||
ApplyResolution();
|
||||
|
||||
Debug.Log($"[SettingsModule] 已刷新设备分辨率: {detectedScreenResolution.x} x {detectedScreenResolution.y},调试窗口使用全屏拉伸布局,不处理SafeArea");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置 Console Module 引用
|
||||
/// </summary>
|
||||
public void SetConsoleModule(ConsoleModule module)
|
||||
{
|
||||
consoleModule = module;
|
||||
|
||||
// 更新输入框显示当前值
|
||||
if (consoleModule != null)
|
||||
{
|
||||
consoleModule.GetMaxLogLines(out int maxInfo, out int maxWarning, out int maxError, out int maxFatal);
|
||||
if (infoBufferInputField != null)
|
||||
infoBufferInputField.text = maxInfo.ToString();
|
||||
if (warningBufferInputField != null)
|
||||
warningBufferInputField.text = maxWarning.ToString();
|
||||
if (errorBufferInputField != null)
|
||||
errorBufferInputField.text = maxError.ToString();
|
||||
if (fatalBufferInputField != null)
|
||||
fatalBufferInputField.text = maxFatal.ToString();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
private void ApplyResolution()
|
||||
{
|
||||
FitMainWindowToFullScreen();
|
||||
|
||||
if (currentResolutionText != null)
|
||||
{
|
||||
currentResolutionText.text = $"设备: {detectedScreenResolution.x:0} x {detectedScreenResolution.y:0} / 调试窗口: 全屏拉伸";
|
||||
}
|
||||
|
||||
// 不需要强制刷新Canvas,会导致rebuild loop
|
||||
// Canvas会自动在下一帧更新
|
||||
}
|
||||
|
||||
private void UpdateResolutionInputs(Vector2 resolution)
|
||||
{
|
||||
if (widthInputField != null)
|
||||
widthInputField.text = Mathf.RoundToInt(resolution.x).ToString();
|
||||
|
||||
if (heightInputField != null)
|
||||
heightInputField.text = Mathf.RoundToInt(resolution.y).ToString();
|
||||
}
|
||||
|
||||
private void FitMainWindowToFullScreen()
|
||||
{
|
||||
if (mainWindow == null)
|
||||
return;
|
||||
|
||||
mainWindow.anchorMin = Vector2.zero;
|
||||
mainWindow.anchorMax = Vector2.one;
|
||||
mainWindow.pivot = new Vector2(0.5f, 0.5f);
|
||||
mainWindow.anchoredPosition = Vector2.zero;
|
||||
mainWindow.sizeDelta = Vector2.zero;
|
||||
mainWindow.offsetMin = Vector2.zero;
|
||||
mainWindow.offsetMax = Vector2.zero;
|
||||
}
|
||||
|
||||
private void ApplyBufferSize()
|
||||
{
|
||||
if (consoleModule == null)
|
||||
{
|
||||
Debug.LogWarning("[SettingsModule] ConsoleModule未设置,无法应用缓存池大小");
|
||||
return;
|
||||
}
|
||||
|
||||
int maxInfo = DEFAULT_BUFFER_SIZE;
|
||||
int maxWarning = DEFAULT_BUFFER_SIZE;
|
||||
int maxError = DEFAULT_BUFFER_SIZE;
|
||||
int maxFatal = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
if (infoBufferInputField != null && int.TryParse(infoBufferInputField.text, out int info) && info > 0)
|
||||
maxInfo = info;
|
||||
if (warningBufferInputField != null && int.TryParse(warningBufferInputField.text, out int warning) && warning > 0)
|
||||
maxWarning = warning;
|
||||
if (errorBufferInputField != null && int.TryParse(errorBufferInputField.text, out int error) && error > 0)
|
||||
maxError = error;
|
||||
if (fatalBufferInputField != null && int.TryParse(fatalBufferInputField.text, out int fatal) && fatal > 0)
|
||||
maxFatal = fatal;
|
||||
|
||||
consoleModule.SetMaxLogLines(maxInfo, maxWarning, maxError, maxFatal);
|
||||
Debug.Log($"[SettingsModule] 已应用缓存池大小 - Info:{maxInfo}, Warning:{maxWarning}, Error:{maxError}, Fatal:{maxFatal}");
|
||||
}
|
||||
|
||||
private void ResetBufferSize()
|
||||
{
|
||||
if (infoBufferInputField != null)
|
||||
infoBufferInputField.text = DEFAULT_BUFFER_SIZE.ToString();
|
||||
if (warningBufferInputField != null)
|
||||
warningBufferInputField.text = DEFAULT_BUFFER_SIZE.ToString();
|
||||
if (errorBufferInputField != null)
|
||||
errorBufferInputField.text = DEFAULT_BUFFER_SIZE.ToString();
|
||||
if (fatalBufferInputField != null)
|
||||
fatalBufferInputField.text = DEFAULT_BUFFER_SIZE.ToString();
|
||||
|
||||
if (consoleModule != null)
|
||||
{
|
||||
consoleModule.SetMaxLogLines(DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
|
||||
Debug.Log($"[SettingsModule] 已重置缓存池大小为默认值: {DEFAULT_BUFFER_SIZE}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ad06ef8252844e478314f4dac5759ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,142 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 工具栏模块 - 提供时间调整等工具
|
||||
/// </summary>
|
||||
public class ToolbarModule : IDebugModule
|
||||
{
|
||||
#region 字段
|
||||
private GameObject toolbarPage;
|
||||
private Slider timeAdjustSlider;
|
||||
private TMP_Text timeAdjustValueText;
|
||||
private Button timeIncreaseButton;
|
||||
private Button timeDecreaseButton;
|
||||
|
||||
private float timeAdjustValue = 60f; // 当前设置的时间调整值(秒)
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
public ToolbarModule(GameObject page, Slider slider, TMP_Text valueText,
|
||||
Button increaseButton, Button decreaseButton)
|
||||
{
|
||||
toolbarPage = page;
|
||||
timeAdjustSlider = slider;
|
||||
timeAdjustValueText = valueText;
|
||||
timeIncreaseButton = increaseButton;
|
||||
timeDecreaseButton = decreaseButton;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDebugModule 实现
|
||||
public void Initialize()
|
||||
{
|
||||
Debug.Log("[ToolbarModule] 初始化工具栏模块...");
|
||||
|
||||
// 设置时间调整工具
|
||||
if (timeAdjustSlider != null)
|
||||
{
|
||||
timeAdjustSlider.onValueChanged.AddListener(OnTimeAdjustValueChanged);
|
||||
// 初始化显示
|
||||
UpdateTimeAdjustDisplay(timeAdjustSlider.value);
|
||||
}
|
||||
|
||||
if (timeIncreaseButton != null)
|
||||
timeIncreaseButton.onClick.AddListener(OnIncreaseTime);
|
||||
|
||||
if (timeDecreaseButton != null)
|
||||
timeDecreaseButton.onClick.AddListener(OnDecreaseTime);
|
||||
}
|
||||
|
||||
public GameObject GetPage()
|
||||
{
|
||||
return toolbarPage;
|
||||
}
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return "工具栏";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
/// <summary>
|
||||
/// 时间调整Slider值改变回调(只更新显示,不改变时间)
|
||||
/// </summary>
|
||||
private void OnTimeAdjustValueChanged(float value)
|
||||
{
|
||||
timeAdjustValue = value;
|
||||
UpdateTimeAdjustDisplay(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间调整显示
|
||||
/// </summary>
|
||||
private void UpdateTimeAdjustDisplay(float seconds)
|
||||
{
|
||||
if (timeAdjustValueText != null)
|
||||
{
|
||||
if (seconds < 60)
|
||||
{
|
||||
timeAdjustValueText.text = $"{seconds:F0}秒";
|
||||
}
|
||||
else
|
||||
{
|
||||
float minutes = seconds / 60f;
|
||||
timeAdjustValueText.text = $"{minutes:F1}分钟";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加时间
|
||||
/// </summary>
|
||||
private void OnIncreaseTime()
|
||||
{
|
||||
// 修改系统时间(这里演示修改Time.time的偏移)
|
||||
float adjustSeconds = timeAdjustValue;
|
||||
|
||||
// 注意:Time.time本身无法直接修改,这里提供一个可以被重写的方法
|
||||
// 实际项目中,你应该修改游戏内的时间变量
|
||||
AdjustGameTime(adjustSeconds);
|
||||
|
||||
Debug.Log($"⏰ [ToolbarModule] 增加时间: +{adjustSeconds}秒");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 减少时间
|
||||
/// </summary>
|
||||
private void OnDecreaseTime()
|
||||
{
|
||||
float adjustSeconds = -timeAdjustValue;
|
||||
|
||||
AdjustGameTime(adjustSeconds);
|
||||
|
||||
Debug.Log($"⏰ [ToolbarModule] 减少时间: {adjustSeconds}秒");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调整游戏时间(示例方法,需要根据实际项目修改)
|
||||
/// </summary>
|
||||
private void AdjustGameTime(float seconds)
|
||||
{
|
||||
// 方案1: 如果你的项目有全局时间管理器
|
||||
// TimeManager.Instance?.AddTime(seconds);
|
||||
|
||||
// 方案2: 如果你使用DateTime
|
||||
// GameTime.Current = GameTime.Current.AddSeconds(seconds);
|
||||
|
||||
// 方案3: 临时演示 - 修改Time.timeScale来模拟时间变化
|
||||
// 实际项目中应该修改你自己的时间变量
|
||||
Debug.Log($"[!] 提示: 请在AdjustGameTime方法中实现你的时间调整逻辑");
|
||||
Debug.Log($"[!] 建议: 修改游戏内的时间变量,例如 GameTime.Current.AddSeconds({seconds})");
|
||||
|
||||
// 示例:如果你有一个静态的游戏时间偏移量
|
||||
// GameTimeOffset += seconds;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74cdbdc5fe514fd44823b16c1364ef38
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80a694deb5aa7774bad71c6f6edfcc5a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,190 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace MeowmentDebugTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 简单的自动换行布局,用于运行时 Tab 栏。
|
||||
/// </summary>
|
||||
public class WrapLayoutGroup : LayoutGroup
|
||||
{
|
||||
[SerializeField] private float spacing = 8f;
|
||||
[SerializeField] private float lineSpacing = 8f;
|
||||
[SerializeField] private bool childControlWidth = false;
|
||||
[SerializeField] private bool childControlHeight = false;
|
||||
|
||||
public float Spacing
|
||||
{
|
||||
get => spacing;
|
||||
set => spacing = value;
|
||||
}
|
||||
|
||||
public float LineSpacing
|
||||
{
|
||||
get => lineSpacing;
|
||||
set => lineSpacing = value;
|
||||
}
|
||||
|
||||
public override void CalculateLayoutInputHorizontal()
|
||||
{
|
||||
base.CalculateLayoutInputHorizontal();
|
||||
|
||||
float totalMinWidth = padding.horizontal;
|
||||
float totalPreferredWidth = padding.horizontal;
|
||||
|
||||
for (int i = 0; i < rectChildren.Count; i++)
|
||||
{
|
||||
RectTransform child = rectChildren[i];
|
||||
totalMinWidth += GetChildWidth(child);
|
||||
totalPreferredWidth += GetChildWidth(child);
|
||||
|
||||
if (i < rectChildren.Count - 1)
|
||||
{
|
||||
totalMinWidth += spacing;
|
||||
totalPreferredWidth += spacing;
|
||||
}
|
||||
}
|
||||
|
||||
SetLayoutInputForAxis(totalMinWidth, totalPreferredWidth, -1f, 0);
|
||||
}
|
||||
|
||||
public override void CalculateLayoutInputVertical()
|
||||
{
|
||||
float requiredHeight = CalculateRequiredHeight(GetUsableWidth());
|
||||
SetLayoutInputForAxis(requiredHeight, requiredHeight, -1f, 1);
|
||||
}
|
||||
|
||||
public override void SetLayoutHorizontal()
|
||||
{
|
||||
SetChildrenAlongBothAxis();
|
||||
}
|
||||
|
||||
public override void SetLayoutVertical()
|
||||
{
|
||||
SetChildrenAlongBothAxis();
|
||||
}
|
||||
|
||||
private float GetContainerWidth()
|
||||
{
|
||||
float selfWidth = rectTransform.rect.width;
|
||||
float parentWidth = 0f;
|
||||
|
||||
if (rectTransform.parent is RectTransform parentRect)
|
||||
{
|
||||
parentWidth = parentRect.rect.width;
|
||||
if (parentWidth > 0f)
|
||||
{
|
||||
if (selfWidth > 0f)
|
||||
{
|
||||
return Mathf.Min(selfWidth, parentWidth);
|
||||
}
|
||||
|
||||
return parentWidth;
|
||||
}
|
||||
}
|
||||
|
||||
if (selfWidth > 0f)
|
||||
{
|
||||
return selfWidth;
|
||||
}
|
||||
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
private float GetUsableWidth()
|
||||
{
|
||||
float width = GetContainerWidth() - padding.horizontal;
|
||||
return width > 0f ? width : float.MaxValue;
|
||||
}
|
||||
|
||||
private float CalculateRequiredHeight(float usableWidth)
|
||||
{
|
||||
if (rectChildren.Count == 0)
|
||||
{
|
||||
return padding.vertical;
|
||||
}
|
||||
|
||||
float currentLineWidth = 0f;
|
||||
float currentLineHeight = 0f;
|
||||
float totalHeight = padding.vertical;
|
||||
|
||||
for (int i = 0; i < rectChildren.Count; i++)
|
||||
{
|
||||
RectTransform child = rectChildren[i];
|
||||
float childWidth = GetChildWidth(child);
|
||||
float childHeight = GetChildHeight(child);
|
||||
|
||||
bool needWrap = currentLineWidth > 0f && currentLineWidth + spacing + childWidth > usableWidth;
|
||||
if (needWrap)
|
||||
{
|
||||
totalHeight += currentLineHeight + lineSpacing;
|
||||
currentLineWidth = 0f;
|
||||
currentLineHeight = 0f;
|
||||
}
|
||||
|
||||
if (currentLineWidth > 0f)
|
||||
{
|
||||
currentLineWidth += spacing;
|
||||
}
|
||||
|
||||
currentLineWidth += childWidth;
|
||||
currentLineHeight = Mathf.Max(currentLineHeight, childHeight);
|
||||
}
|
||||
|
||||
totalHeight += currentLineHeight;
|
||||
return totalHeight;
|
||||
}
|
||||
|
||||
private void SetChildrenAlongBothAxis()
|
||||
{
|
||||
float usableWidth = GetUsableWidth();
|
||||
float containerRight = padding.left + usableWidth;
|
||||
float x = padding.left;
|
||||
float y = padding.top;
|
||||
float currentLineHeight = 0f;
|
||||
|
||||
for (int i = 0; i < rectChildren.Count; i++)
|
||||
{
|
||||
RectTransform child = rectChildren[i];
|
||||
float childWidth = GetChildWidth(child);
|
||||
float childHeight = GetChildHeight(child);
|
||||
|
||||
bool needWrap = x > padding.left && x + childWidth > containerRight;
|
||||
if (needWrap)
|
||||
{
|
||||
x = padding.left;
|
||||
y += currentLineHeight + lineSpacing;
|
||||
currentLineHeight = 0f;
|
||||
}
|
||||
|
||||
SetChildAlongAxis(child, 0, x, childWidth);
|
||||
SetChildAlongAxis(child, 1, y, childHeight);
|
||||
|
||||
x += childWidth + spacing;
|
||||
currentLineHeight = Mathf.Max(currentLineHeight, childHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetChildWidth(RectTransform child)
|
||||
{
|
||||
return childControlWidth ? LayoutUtility.GetPreferredWidth(child) : GetPreferredOrRectWidth(child);
|
||||
}
|
||||
|
||||
private float GetChildHeight(RectTransform child)
|
||||
{
|
||||
return childControlHeight ? LayoutUtility.GetPreferredHeight(child) : GetPreferredOrRectHeight(child);
|
||||
}
|
||||
|
||||
private static float GetPreferredOrRectWidth(RectTransform child)
|
||||
{
|
||||
float preferredWidth = LayoutUtility.GetPreferredWidth(child);
|
||||
return preferredWidth > 0f ? preferredWidth : child.rect.width;
|
||||
}
|
||||
|
||||
private static float GetPreferredOrRectHeight(RectTransform child)
|
||||
{
|
||||
float preferredHeight = LayoutUtility.GetPreferredHeight(child);
|
||||
return preferredHeight > 0f ? preferredHeight : child.rect.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eba6056d771daf841913257026594b60
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "com.bywaystudios.meowmentdebugtool",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.TextMeshPro"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de9c38beb5c3ed94e83a7a91fbde340d
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4b915b71b15b3d40a7a2056ad678c43
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,257 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &3881209765909230299
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6728429640391017404}
|
||||
- component: {fileID: 2352417316950775027}
|
||||
- component: {fileID: 5769386640954096008}
|
||||
- component: {fileID: 1325501293128207700}
|
||||
m_Layer: 0
|
||||
m_Name: CustomButtonPrefab
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6728429640391017404
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3881209765909230299}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 6074569528420963325}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 80}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2352417316950775027
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3881209765909230299}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5769386640954096008
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3881209765909230299}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.3, g: 0.3, b: 0.8, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &1325501293128207700
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3881209765909230299}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 5769386640954096008}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &7577830103234660160
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6074569528420963325}
|
||||
- component: {fileID: 2278016343231618367}
|
||||
- component: {fileID: 5732067431234824322}
|
||||
m_Layer: 0
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6074569528420963325
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7577830103234660160}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6728429640391017404}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: -20, y: -20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2278016343231618367
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7577830103234660160}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5732067431234824322
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7577830103234660160}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Button
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 24
|
||||
m_fontSizeBase: 24
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5e7b8108eee01d46bf68ed912756e67
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebfed08dbcdc460408e3c502052e7881
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,241 +0,0 @@
|
||||
using UnityEngine;
|
||||
using MeowmentDebugTool;
|
||||
/// <summary>
|
||||
/// 示例调试函数集合
|
||||
/// 使用 [DebugButton] 特性来标记方法,它们会自动出现在调试工具中
|
||||
/// </summary>
|
||||
public static class SampleDebugFunctions
|
||||
{
|
||||
// 基础示例
|
||||
[DebugButton("打印Hello World")]
|
||||
public static void PrintHelloWorld()
|
||||
{
|
||||
Debug.Log("Hello World from Debug Tool!");
|
||||
}
|
||||
|
||||
// 带颜色的按钮
|
||||
[DebugButton("绿色按钮示例", 0.2f, 0.8f, 0.2f)]
|
||||
public static void GreenButtonExample()
|
||||
{
|
||||
Debug.Log("这是一个绿色按钮");
|
||||
}
|
||||
|
||||
[DebugButton("红色按钮示例", 0.8f, 0.2f, 0.2f)]
|
||||
public static void RedButtonExample()
|
||||
{
|
||||
Debug.LogWarning("这是一个红色按钮 - 通常用于危险操作");
|
||||
}
|
||||
|
||||
[DebugButton("蓝色按钮示例", 0.2f, 0.5f, 0.8f)]
|
||||
public static void BlueButtonExample()
|
||||
{
|
||||
Debug.Log("这是一个蓝色按钮");
|
||||
}
|
||||
|
||||
// 时间相关
|
||||
[DebugButton("显示当前时间", 0.7f, 0.7f, 0.2f)]
|
||||
public static void ShowCurrentTime()
|
||||
{
|
||||
Debug.Log($"当前时间: {System.DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
||||
}
|
||||
|
||||
[DebugButton("暂停游戏", 0.9f, 0.5f, 0.2f)]
|
||||
public static void PauseGame()
|
||||
{
|
||||
Time.timeScale = 0f;
|
||||
Debug.Log("游戏已暂停");
|
||||
}
|
||||
|
||||
[DebugButton("恢复游戏", 0.2f, 0.9f, 0.5f)]
|
||||
public static void ResumeGame()
|
||||
{
|
||||
Time.timeScale = 1f;
|
||||
Debug.Log("游戏已恢复");
|
||||
}
|
||||
|
||||
// 系统信息
|
||||
[DebugButton("打印系统信息")]
|
||||
public static void PrintSystemInfo()
|
||||
{
|
||||
Debug.Log($"平台: {Application.platform}");
|
||||
Debug.Log($"Unity版本: {Application.unityVersion}");
|
||||
Debug.Log($"设备型号: {SystemInfo.deviceModel}");
|
||||
Debug.Log($"操作系统: {SystemInfo.operatingSystem}");
|
||||
}
|
||||
|
||||
// 内存管理
|
||||
[DebugButton("强制GC", 0.9f, 0.3f, 0.3f)]
|
||||
public static void ForceGarbageCollection()
|
||||
{
|
||||
System.GC.Collect();
|
||||
Debug.Log("已触发垃圾回收");
|
||||
}
|
||||
|
||||
[DebugButton("清理未使用资源", 0.9f, 0.5f, 0.3f)]
|
||||
public static void UnloadUnusedAssets()
|
||||
{
|
||||
Resources.UnloadUnusedAssets();
|
||||
Debug.Log("已清理未使用的资源");
|
||||
}
|
||||
|
||||
// 场景管理
|
||||
[DebugButton("重新加载当前场景", 0.8f, 0.4f, 0.2f)]
|
||||
public static void ReloadCurrentScene()
|
||||
{
|
||||
UnityEngine.SceneManagement.SceneManager.LoadScene(
|
||||
UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
|
||||
Debug.Log("正在重新加载当前场景");
|
||||
}
|
||||
|
||||
// 屏幕设置
|
||||
[DebugButton("切换全屏")]
|
||||
public static void ToggleFullscreen()
|
||||
{
|
||||
Screen.fullScreen = !Screen.fullScreen;
|
||||
Debug.Log($"全屏模式: {Screen.fullScreen}");
|
||||
}
|
||||
|
||||
[DebugButton("设置目标帧率60")]
|
||||
public static void SetTargetFrameRate60()
|
||||
{
|
||||
Application.targetFrameRate = 60;
|
||||
Debug.Log("目标帧率设置为60");
|
||||
}
|
||||
|
||||
[DebugButton("设置目标帧率30")]
|
||||
public static void SetTargetFrameRate30()
|
||||
{
|
||||
Application.targetFrameRate = 30;
|
||||
Debug.Log("目标帧率设置为30");
|
||||
}
|
||||
|
||||
[DebugButton("取消帧率限制")]
|
||||
public static void UnlimitedFrameRate()
|
||||
{
|
||||
Application.targetFrameRate = -1;
|
||||
Debug.Log("已取消帧率限制");
|
||||
}
|
||||
|
||||
// 音频设置
|
||||
[DebugButton("静音", 0.5f, 0.5f, 0.5f)]
|
||||
public static void MuteAudio()
|
||||
{
|
||||
AudioListener.volume = 0f;
|
||||
Debug.Log("已静音");
|
||||
}
|
||||
|
||||
[DebugButton("取消静音", 0.2f, 0.8f, 0.8f)]
|
||||
public static void UnmuteAudio()
|
||||
{
|
||||
AudioListener.volume = 1f;
|
||||
Debug.Log("已取消静音");
|
||||
}
|
||||
|
||||
// 输入对话框示例
|
||||
[DebugButton("输入测试", 0.5f, 0.7f, 0.9f)]
|
||||
public static void ShowInputDialogExample()
|
||||
{
|
||||
UniversalDebugTool.ShowInputDialog("请输入内容", (input) =>
|
||||
{
|
||||
Debug.Log($"你输入了: {input}");
|
||||
}, "默认值");
|
||||
}
|
||||
|
||||
// 数字输入示例
|
||||
[DebugButton("数字输入测试", 0.5f, 0.7f, 0.9f)]
|
||||
public static void ShowNumberInputDialog()
|
||||
{
|
||||
UniversalDebugTool.ShowInputDialog("请输入数字", (input) =>
|
||||
{
|
||||
if (float.TryParse(input, out float value))
|
||||
{
|
||||
Debug.Log($"你输入的数字是: {value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("输入的不是有效数字");
|
||||
}
|
||||
}, "100", TMPro.TMP_InputField.ContentType.DecimalNumber);
|
||||
}
|
||||
|
||||
// PlayerPrefs相关
|
||||
[DebugButton("清空PlayerPrefs", 0.9f, 0.2f, 0.2f)]
|
||||
public static void ClearPlayerPrefs()
|
||||
{
|
||||
PlayerPrefs.DeleteAll();
|
||||
PlayerPrefs.Save();
|
||||
Debug.Log("已清空所有PlayerPrefs数据");
|
||||
}
|
||||
|
||||
[DebugButton("保存PlayerPrefs")]
|
||||
public static void SavePlayerPrefs()
|
||||
{
|
||||
PlayerPrefs.Save();
|
||||
Debug.Log("已保存PlayerPrefs");
|
||||
}
|
||||
|
||||
// 退出游戏
|
||||
[DebugButton("退出应用", 1f, 0f, 0f)]
|
||||
public static void QuitApplication()
|
||||
{
|
||||
Debug.Log("退出应用");
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
#else
|
||||
Application.Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ========== 复选框示例 ==========
|
||||
// 注意:复选框方法必须接受一个 bool 参数
|
||||
|
||||
[DebugCheckBox("显示FPS")]
|
||||
public static void ToggleShowFPS(bool isOn)
|
||||
{
|
||||
Debug.Log($"显示FPS: {isOn}");
|
||||
// 这里可以控制FPS显示组件的开关
|
||||
}
|
||||
|
||||
[DebugCheckBox("上帝模式", 1f, 0.8f, 0.2f)]
|
||||
public static void ToggleGodMode(bool isOn)
|
||||
{
|
||||
Debug.Log($"上帝模式: {isOn}");
|
||||
// 这里可以设置角色无敌等参数
|
||||
}
|
||||
|
||||
[DebugCheckBox("无限金币", 0.2f, 0.8f, 0.2f)]
|
||||
public static void ToggleInfiniteCoin(bool isOn)
|
||||
{
|
||||
Debug.Log($"无限金币: {isOn}");
|
||||
// 这里可以设置金币相关参数
|
||||
}
|
||||
|
||||
[DebugCheckBox("显示碰撞体", 0.5f, 0.5f, 1f)]
|
||||
public static void ToggleShowColliders(bool isOn)
|
||||
{
|
||||
Debug.Log($"显示碰撞体: {isOn}");
|
||||
// 这里可以控制碰撞体的可视化
|
||||
}
|
||||
|
||||
[DebugCheckBox("调试模式", 0.8f, 0.2f, 0.8f)]
|
||||
public static void ToggleDebugMode(bool isOn)
|
||||
{
|
||||
Debug.Log($"调试模式: {isOn}");
|
||||
Debug.unityLogger.logEnabled = isOn;
|
||||
}
|
||||
|
||||
[DebugCheckBox("静音音效")]
|
||||
public static void ToggleMuteSound(bool isOn)
|
||||
{
|
||||
Debug.Log($"静音音效: {isOn}");
|
||||
AudioListener.volume = isOn ? 0f : 1f;
|
||||
}
|
||||
|
||||
[DebugCheckBox("锁定帧率")]
|
||||
public static void ToggleLockFramerate(bool isOn)
|
||||
{
|
||||
Debug.Log($"锁定帧率: {isOn}");
|
||||
Application.targetFrameRate = isOn ? 30 : -1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd5ef1ceee669994d9bb5afcb9ff5131
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,257 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &6819558007183593838
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3842217457948720423}
|
||||
- component: {fileID: 849869106104280388}
|
||||
- component: {fileID: 6447641627266444971}
|
||||
- component: {fileID: 8150773266496098555}
|
||||
m_Layer: 0
|
||||
m_Name: TabButtonPrefab
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3842217457948720423
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6819558007183593838}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 4298862431125743836}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 80}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &849869106104280388
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6819558007183593838}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &6447641627266444971
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6819558007183593838}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &8150773266496098555
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6819558007183593838}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 6447641627266444971}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &7442242341622436878
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4298862431125743836}
|
||||
- component: {fileID: 8634582329154924209}
|
||||
- component: {fileID: 2303096978450003477}
|
||||
m_Layer: 0
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4298862431125743836
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7442242341622436878}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 3842217457948720423}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8634582329154924209
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7442242341622436878}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2303096978450003477
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7442242341622436878}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Tab
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 32
|
||||
m_fontSizeBase: 32
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14784234f6e67a14ca69c3a41c370dd9
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05030b095151b0446b36ce3e52b1945a
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "com.bywaystudios.meowmentdebugtool",
|
||||
"displayName": "MeowmentDebugTool",
|
||||
"version": "0.5.3",
|
||||
"description": "\u8c03\u8bd5\u5de5\u5177\uff0c\u96c6\u6210\u4e86\u5ba2\u6237\u7aef\u6d4b\u8bd5\u65f6\u7684\u5e38\u7528\u529f\u80fd\uff0c\u652f\u6301\u6269\u5c55\u81ea\u5b9a\u4e49\u6309\u94ae\uff0c\u65b9\u4fbf\u5f00\u53d1\u8005\u8c03\u8bd5\u548c\u6d4b\u8bd5\u3002",
|
||||
"samples": [
|
||||
{
|
||||
"displayName": "MeowmentDebugTool Sample",
|
||||
"description": "A simple sample to demonstrate the usage of MeowmentDebugTool.",
|
||||
"path": "Samples~/MeowmentDebugToolSample"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"com.unity.ugui": "1.0.0",
|
||||
"com.unity.textmeshpro": "3.0.7"
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79aacf7240a6ee94fb43e6d58c4082d6
|
||||
PackageManifestImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,73 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.asset-store-validation": "0.6.0",
|
||||
"com.unity.collab-proxy": "2.10.2",
|
||||
"com.unity.editorcoroutines": "1.0.1",
|
||||
"com.unity.feature.development": "1.0.1",
|
||||
"com.unity.ide.rider": "3.0.38",
|
||||
"com.unity.ide.visualstudio": "2.0.25",
|
||||
"com.unity.ide.vscode": "1.2.5",
|
||||
"com.unity.nuget.newtonsoft-json": "3.2.2",
|
||||
"com.unity.performance.profile-analyzer": "1.2.4",
|
||||
"com.unity.settings-manager": "2.1.1",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.testtools.codecoverage": "1.2.7",
|
||||
"com.unity.upm.develop": "0.5.3-exp.1",
|
||||
"com.unity.modules.ai": "1.0.0",
|
||||
"com.unity.modules.androidjni": "1.0.0",
|
||||
"com.unity.modules.animation": "1.0.0",
|
||||
"com.unity.modules.assetbundle": "1.0.0",
|
||||
"com.unity.modules.audio": "1.0.0",
|
||||
"com.unity.modules.cloth": "1.0.0",
|
||||
"com.unity.modules.director": "1.0.0",
|
||||
"com.unity.modules.imageconversion": "1.0.0",
|
||||
"com.unity.modules.imgui": "1.0.0",
|
||||
"com.unity.modules.jsonserialize": "1.0.0",
|
||||
"com.unity.modules.particlesystem": "1.0.0",
|
||||
"com.unity.modules.physics": "1.0.0",
|
||||
"com.unity.modules.physics2d": "1.0.0",
|
||||
"com.unity.modules.screencapture": "1.0.0",
|
||||
"com.unity.modules.terrain": "1.0.0",
|
||||
"com.unity.modules.terrainphysics": "1.0.0",
|
||||
"com.unity.modules.tilemap": "1.0.0",
|
||||
"com.unity.modules.ui": "1.0.0",
|
||||
"com.unity.modules.uielements": "1.0.0",
|
||||
"com.unity.modules.umbra": "1.0.0",
|
||||
"com.unity.modules.unityanalytics": "1.0.0",
|
||||
"com.unity.modules.unitywebrequest": "1.0.0",
|
||||
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
|
||||
"com.unity.modules.unitywebrequestaudio": "1.0.0",
|
||||
"com.unity.modules.unitywebrequesttexture": "1.0.0",
|
||||
"com.unity.modules.unitywebrequestwww": "1.0.0",
|
||||
"com.unity.modules.vehicles": "1.0.0",
|
||||
"com.unity.modules.video": "1.0.0",
|
||||
"com.unity.modules.vr": "1.0.0",
|
||||
"com.unity.modules.wind": "1.0.0",
|
||||
"com.unity.modules.xr": "1.0.0"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "OpenUPM",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.google"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BywayStudios",
|
||||
"url": "https://npm.bywaystudios.com/",
|
||||
"scopes": [
|
||||
"com.bywaystudios"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "AppLovin MAX Unity",
|
||||
"url": "https://unity.packages.applovin.com/",
|
||||
"scopes": [
|
||||
"com.applovin.mediation.ads",
|
||||
"com.applovin.mediation.adapters",
|
||||
"com.applovin.mediation.dsp"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,396 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.bywaystudios.meowmentdebugtool": {
|
||||
"version": "file:com.bywaystudios.meowmentdebugtool",
|
||||
"depth": 0,
|
||||
"source": "embedded",
|
||||
"dependencies": {
|
||||
"com.unity.ugui": "1.0.0",
|
||||
"com.unity.textmeshpro": "3.0.7"
|
||||
}
|
||||
},
|
||||
"com.unity.asset-store-validation": {
|
||||
"version": "0.6.0",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.nuget.newtonsoft-json": "2.0.2"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.collab-proxy": {
|
||||
"version": "2.10.2",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.editorcoroutines": {
|
||||
"version": "1.0.1",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.ext.nunit": {
|
||||
"version": "1.0.6",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.feature.development": {
|
||||
"version": "1.0.1",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.22",
|
||||
"com.unity.ide.rider": "3.0.36",
|
||||
"com.unity.ide.vscode": "1.2.5",
|
||||
"com.unity.editorcoroutines": "1.0.0",
|
||||
"com.unity.performance.profile-analyzer": "1.2.3",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.testtools.codecoverage": "1.2.6"
|
||||
}
|
||||
},
|
||||
"com.unity.ide.rider": {
|
||||
"version": "3.0.38",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.ext.nunit": "1.0.6"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.ide.visualstudio": {
|
||||
"version": "2.0.25",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.test-framework": "1.1.31"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.ide.vscode": {
|
||||
"version": "1.2.5",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.nuget.newtonsoft-json": {
|
||||
"version": "3.2.2",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.performance.profile-analyzer": {
|
||||
"version": "1.2.4",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.settings-manager": {
|
||||
"version": "2.1.1",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.test-framework": {
|
||||
"version": "1.1.33",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.ext.nunit": "1.0.6",
|
||||
"com.unity.modules.imgui": "1.0.0",
|
||||
"com.unity.modules.jsonserialize": "1.0.0"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.testtools.codecoverage": {
|
||||
"version": "1.2.7",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.test-framework": "1.0.16",
|
||||
"com.unity.settings-manager": "1.0.1"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.textmeshpro": {
|
||||
"version": "3.0.7",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.ugui": "1.0.0"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.ugui": {
|
||||
"version": "1.0.0",
|
||||
"depth": 1,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.ui": "1.0.0",
|
||||
"com.unity.modules.imgui": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.upm.develop": {
|
||||
"version": "0.5.3-exp.1",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.test-framework": "1.1.20",
|
||||
"com.unity.nuget.newtonsoft-json": "2.0.2",
|
||||
"com.unity.asset-store-validation": "0.1.3"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.modules.ai": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.androidjni": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.animation": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.assetbundle": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.audio": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.cloth": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.physics": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.director": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.audio": "1.0.0",
|
||||
"com.unity.modules.animation": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.imageconversion": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.imgui": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.jsonserialize": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.particlesystem": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.physics": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.physics2d": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.screencapture": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.imageconversion": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.subsystems": {
|
||||
"version": "1.0.0",
|
||||
"depth": 1,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.jsonserialize": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.terrain": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.terrainphysics": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.physics": "1.0.0",
|
||||
"com.unity.modules.terrain": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.tilemap": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.physics2d": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.ui": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.uielements": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.ui": "1.0.0",
|
||||
"com.unity.modules.imgui": "1.0.0",
|
||||
"com.unity.modules.jsonserialize": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.umbra": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.unityanalytics": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.unitywebrequest": "1.0.0",
|
||||
"com.unity.modules.jsonserialize": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.unitywebrequest": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.unitywebrequestassetbundle": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.assetbundle": "1.0.0",
|
||||
"com.unity.modules.unitywebrequest": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.unitywebrequestaudio": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.unitywebrequest": "1.0.0",
|
||||
"com.unity.modules.audio": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.unitywebrequesttexture": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.unitywebrequest": "1.0.0",
|
||||
"com.unity.modules.imageconversion": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.unitywebrequestwww": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.unitywebrequest": "1.0.0",
|
||||
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
|
||||
"com.unity.modules.unitywebrequestaudio": "1.0.0",
|
||||
"com.unity.modules.audio": "1.0.0",
|
||||
"com.unity.modules.assetbundle": "1.0.0",
|
||||
"com.unity.modules.imageconversion": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.vehicles": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.physics": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.video": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.audio": "1.0.0",
|
||||
"com.unity.modules.ui": "1.0.0",
|
||||
"com.unity.modules.unitywebrequest": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.vr": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.jsonserialize": "1.0.0",
|
||||
"com.unity.modules.physics": "1.0.0",
|
||||
"com.unity.modules.xr": "1.0.0"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.wind": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {}
|
||||
},
|
||||
"com.unity.modules.xr": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
"source": "builtin",
|
||||
"dependencies": {
|
||||
"com.unity.modules.physics": "1.0.0",
|
||||
"com.unity.modules.jsonserialize": "1.0.0",
|
||||
"com.unity.modules.subsystems": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!11 &1
|
||||
AudioManager:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Volume: 1
|
||||
Rolloff Scale: 1
|
||||
Doppler Factor: 1
|
||||
Default Speaker Mode: 2
|
||||
m_SampleRate: 0
|
||||
m_DSPBufferSize: 1024
|
||||
m_VirtualVoiceCount: 512
|
||||
m_RealVoiceCount: 32
|
||||
m_SpatializerPlugin:
|
||||
m_AmbisonicDecoderPlugin:
|
||||
m_DisableAudio: 0
|
||||
m_VirtualizeEffects: 1
|
||||
m_RequestedDSPBufferSize: 1024
|
||||
@ -1,6 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!236 &1
|
||||
ClusterInputManager:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Inputs: []
|
||||
@ -1,34 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!55 &1
|
||||
PhysicsManager:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 11
|
||||
m_Gravity: {x: 0, y: -9.81, z: 0}
|
||||
m_DefaultMaterial: {fileID: 0}
|
||||
m_BounceThreshold: 2
|
||||
m_SleepThreshold: 0.005
|
||||
m_DefaultContactOffset: 0.01
|
||||
m_DefaultSolverIterations: 6
|
||||
m_DefaultSolverVelocityIterations: 1
|
||||
m_QueriesHitBackfaces: 0
|
||||
m_QueriesHitTriggers: 1
|
||||
m_EnableAdaptiveForce: 0
|
||||
m_ClothInterCollisionDistance: 0
|
||||
m_ClothInterCollisionStiffness: 0
|
||||
m_ContactsGeneration: 1
|
||||
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
m_AutoSimulation: 1
|
||||
m_AutoSyncTransforms: 0
|
||||
m_ReuseCollisionCallbacks: 1
|
||||
m_ClothInterCollisionSettingsToggle: 0
|
||||
m_ContactPairsMode: 0
|
||||
m_BroadphaseType: 0
|
||||
m_WorldBounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 250, y: 250, z: 250}
|
||||
m_WorldSubdivisions: 8
|
||||
m_FrictionType: 0
|
||||
m_EnableEnhancedDeterminism: 0
|
||||
m_EnableUnifiedHeightmaps: 1
|
||||
m_DefaultMaxAngluarSpeed: 7
|
||||
@ -1,8 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1045 &1
|
||||
EditorBuildSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Scenes: []
|
||||
m_configObjects: {}
|
||||
@ -1,30 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!159 &1
|
||||
EditorSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 11
|
||||
m_ExternalVersionControlSupport: Visible Meta Files
|
||||
m_SerializationMode: 2
|
||||
m_LineEndingsForNewScripts: 0
|
||||
m_DefaultBehaviorMode: 0
|
||||
m_PrefabRegularEnvironment: {fileID: 0}
|
||||
m_PrefabUIEnvironment: {fileID: 0}
|
||||
m_SpritePackerMode: 0
|
||||
m_SpritePackerPaddingPower: 1
|
||||
m_EtcTextureCompressorBehavior: 1
|
||||
m_EtcTextureFastCompressor: 1
|
||||
m_EtcTextureNormalCompressor: 2
|
||||
m_EtcTextureBestCompressor: 4
|
||||
m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref
|
||||
m_ProjectGenerationRootNamespace:
|
||||
m_CollabEditorSettings:
|
||||
inProgressEnabled: 1
|
||||
m_EnableTextureStreamingInEditMode: 1
|
||||
m_EnableTextureStreamingInPlayMode: 1
|
||||
m_AsyncShaderCompilation: 1
|
||||
m_EnterPlayModeOptionsEnabled: 0
|
||||
m_EnterPlayModeOptions: 3
|
||||
m_ShowLightmapResolutionOverlay: 1
|
||||
m_UseLegacyProbeSampleCount: 0
|
||||
m_SerializeInlineMappingsOnOneLine: 1
|
||||
@ -1,63 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!30 &1
|
||||
GraphicsSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 13
|
||||
m_Deferred:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_DeferredReflections:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ScreenSpaceShadows:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_LegacyDeferred:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_DepthNormals:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_MotionVectors:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_LightHalo:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_LensFlare:
|
||||
m_Mode: 1
|
||||
m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_AlwaysIncludedShaders:
|
||||
- {fileID: 7, guid: 0000000000000000f000000000000000, type: 0}
|
||||
- {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0}
|
||||
- {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0}
|
||||
- {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0}
|
||||
- {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
|
||||
- {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_PreloadedShaders: []
|
||||
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000,
|
||||
type: 0}
|
||||
m_CustomRenderPipeline: {fileID: 0}
|
||||
m_TransparencySortMode: 0
|
||||
m_TransparencySortAxis: {x: 0, y: 0, z: 1}
|
||||
m_DefaultRenderingPath: 1
|
||||
m_DefaultMobileRenderingPath: 1
|
||||
m_TierSettings: []
|
||||
m_LightmapStripping: 0
|
||||
m_FogStripping: 0
|
||||
m_InstancingStripping: 0
|
||||
m_LightmapKeepPlain: 1
|
||||
m_LightmapKeepDirCombined: 1
|
||||
m_LightmapKeepDynamicPlain: 1
|
||||
m_LightmapKeepDynamicDirCombined: 1
|
||||
m_LightmapKeepShadowMask: 1
|
||||
m_LightmapKeepSubtractive: 1
|
||||
m_FogKeepLinear: 1
|
||||
m_FogKeepExp: 1
|
||||
m_FogKeepExp2: 1
|
||||
m_AlbedoSwatchInfos: []
|
||||
m_LightsUseLinearIntensity: 0
|
||||
m_LightsUseColorTemperature: 0
|
||||
m_LogWhenShaderIsCompiled: 0
|
||||
m_AllowEnlightenSupportForUpgradedProject: 0
|
||||
@ -1,295 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!13 &1
|
||||
InputManager:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Axes:
|
||||
- serializedVersion: 3
|
||||
m_Name: Horizontal
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton: left
|
||||
positiveButton: right
|
||||
altNegativeButton: a
|
||||
altPositiveButton: d
|
||||
gravity: 3
|
||||
dead: 0.001
|
||||
sensitivity: 3
|
||||
snap: 1
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Vertical
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton: down
|
||||
positiveButton: up
|
||||
altNegativeButton: s
|
||||
altPositiveButton: w
|
||||
gravity: 3
|
||||
dead: 0.001
|
||||
sensitivity: 3
|
||||
snap: 1
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Fire1
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: left ctrl
|
||||
altNegativeButton:
|
||||
altPositiveButton: mouse 0
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Fire2
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: left alt
|
||||
altNegativeButton:
|
||||
altPositiveButton: mouse 1
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Fire3
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: left shift
|
||||
altNegativeButton:
|
||||
altPositiveButton: mouse 2
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Jump
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: space
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Mouse X
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton:
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 0
|
||||
dead: 0
|
||||
sensitivity: 0.1
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 1
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Mouse Y
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton:
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 0
|
||||
dead: 0
|
||||
sensitivity: 0.1
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 1
|
||||
axis: 1
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Mouse ScrollWheel
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton:
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 0
|
||||
dead: 0
|
||||
sensitivity: 0.1
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 1
|
||||
axis: 2
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Horizontal
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton:
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 0
|
||||
dead: 0.19
|
||||
sensitivity: 1
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 2
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Vertical
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton:
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 0
|
||||
dead: 0.19
|
||||
sensitivity: 1
|
||||
snap: 0
|
||||
invert: 1
|
||||
type: 2
|
||||
axis: 1
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Fire1
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: joystick button 0
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Fire2
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: joystick button 1
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Fire3
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: joystick button 2
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Jump
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: joystick button 3
|
||||
altNegativeButton:
|
||||
altPositiveButton:
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Submit
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: return
|
||||
altNegativeButton:
|
||||
altPositiveButton: joystick button 0
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Submit
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: enter
|
||||
altNegativeButton:
|
||||
altPositiveButton: space
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
- serializedVersion: 3
|
||||
m_Name: Cancel
|
||||
descriptiveName:
|
||||
descriptiveNegativeName:
|
||||
negativeButton:
|
||||
positiveButton: escape
|
||||
altNegativeButton:
|
||||
altPositiveButton: joystick button 1
|
||||
gravity: 1000
|
||||
dead: 0.001
|
||||
sensitivity: 1000
|
||||
snap: 0
|
||||
invert: 0
|
||||
type: 0
|
||||
axis: 0
|
||||
joyNum: 0
|
||||
@ -1,35 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!387306366 &1
|
||||
MemorySettings:
|
||||
m_ObjectHideFlags: 0
|
||||
m_EditorMemorySettings:
|
||||
m_MainAllocatorBlockSize: -1
|
||||
m_ThreadAllocatorBlockSize: -1
|
||||
m_MainGfxBlockSize: -1
|
||||
m_ThreadGfxBlockSize: -1
|
||||
m_CacheBlockSize: -1
|
||||
m_TypetreeBlockSize: -1
|
||||
m_ProfilerBlockSize: -1
|
||||
m_ProfilerEditorBlockSize: -1
|
||||
m_BucketAllocatorGranularity: -1
|
||||
m_BucketAllocatorBucketsCount: -1
|
||||
m_BucketAllocatorBlockSize: -1
|
||||
m_BucketAllocatorBlockCount: -1
|
||||
m_ProfilerBucketAllocatorGranularity: -1
|
||||
m_ProfilerBucketAllocatorBucketsCount: -1
|
||||
m_ProfilerBucketAllocatorBlockSize: -1
|
||||
m_ProfilerBucketAllocatorBlockCount: -1
|
||||
m_TempAllocatorSizeMain: -1
|
||||
m_JobTempAllocatorBlockSize: -1
|
||||
m_BackgroundJobTempAllocatorBlockSize: -1
|
||||
m_JobTempAllocatorReducedBlockSize: -1
|
||||
m_TempAllocatorSizeGIBakingWorker: -1
|
||||
m_TempAllocatorSizeNavMeshWorker: -1
|
||||
m_TempAllocatorSizeAudioWorker: -1
|
||||
m_TempAllocatorSizeCloudWorker: -1
|
||||
m_TempAllocatorSizeGfx: -1
|
||||
m_TempAllocatorSizeJobWorker: -1
|
||||
m_TempAllocatorSizeBackgroundWorker: -1
|
||||
m_TempAllocatorSizePreloadManager: -1
|
||||
m_PlatformMemorySettings: {}
|
||||
@ -1,91 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!126 &1
|
||||
NavMeshProjectSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
areas:
|
||||
- name: Walkable
|
||||
cost: 1
|
||||
- name: Not Walkable
|
||||
cost: 1
|
||||
- name: Jump
|
||||
cost: 2
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
- name:
|
||||
cost: 1
|
||||
m_LastAgentTypeID: -887442657
|
||||
m_Settings:
|
||||
- serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.75
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_SettingNames:
|
||||
- Humanoid
|
||||
@ -1,62 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &1
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 61
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_EnablePreReleasePackages: 0
|
||||
m_AdvancedSettingsExpanded: 1
|
||||
m_ScopedRegistriesSettingsExpanded: 1
|
||||
m_SeeAllPackageVersions: 0
|
||||
m_DismissPreviewPackagesInUse: 0
|
||||
oneTimeWarningShown: 0
|
||||
m_Registries:
|
||||
- m_Id: main
|
||||
m_Name:
|
||||
m_Url: https://packages.unity.com
|
||||
m_Scopes: []
|
||||
m_IsDefault: 1
|
||||
m_Capabilities: 7
|
||||
m_ConfigSource: 0
|
||||
- m_Id: scoped:project:OpenUPM
|
||||
m_Name: OpenUPM
|
||||
m_Url: https://package.openupm.com
|
||||
m_Scopes:
|
||||
- com.google
|
||||
m_IsDefault: 0
|
||||
m_Capabilities: 0
|
||||
m_ConfigSource: 4
|
||||
- m_Id: scoped:project:BywayStudios
|
||||
m_Name: BywayStudios
|
||||
m_Url: https://npm.bywaystudios.com
|
||||
m_Scopes:
|
||||
- com.bywaystudios
|
||||
m_IsDefault: 0
|
||||
m_Capabilities: 0
|
||||
m_ConfigSource: 4
|
||||
- m_Id: scoped:project:AppLovin MAX Unity
|
||||
m_Name: AppLovin MAX Unity
|
||||
m_Url: https://unity.packages.applovin.com
|
||||
m_Scopes:
|
||||
- com.applovin.mediation.ads
|
||||
- com.applovin.mediation.adapters
|
||||
- com.applovin.mediation.dsp
|
||||
m_IsDefault: 0
|
||||
m_Capabilities: 0
|
||||
m_ConfigSource: 4
|
||||
m_UserSelectedRegistryName: OpenUPM
|
||||
m_UserAddingNewScopedRegistry: 0
|
||||
m_RegistryInfoDraft:
|
||||
m_Modified: 0
|
||||
m_ErrorMessage:
|
||||
m_UserModificationsInstanceId: -834
|
||||
m_OriginalInstanceId: -836
|
||||
m_LoadAssets: 0
|
||||
@ -1,5 +0,0 @@
|
||||
{
|
||||
"m_Dictionary": {
|
||||
"m_DictionaryValues": []
|
||||
}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!19 &1
|
||||
Physics2DSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 4
|
||||
m_Gravity: {x: 0, y: -9.81}
|
||||
m_DefaultMaterial: {fileID: 0}
|
||||
m_VelocityIterations: 8
|
||||
m_PositionIterations: 3
|
||||
m_VelocityThreshold: 1
|
||||
m_MaxLinearCorrection: 0.2
|
||||
m_MaxAngularCorrection: 8
|
||||
m_MaxTranslationSpeed: 100
|
||||
m_MaxRotationSpeed: 360
|
||||
m_BaumgarteScale: 0.2
|
||||
m_BaumgarteTimeOfImpactScale: 0.75
|
||||
m_TimeToSleep: 0.5
|
||||
m_LinearSleepTolerance: 0.01
|
||||
m_AngularSleepTolerance: 2
|
||||
m_DefaultContactOffset: 0.01
|
||||
m_JobOptions:
|
||||
serializedVersion: 2
|
||||
useMultithreading: 0
|
||||
useConsistencySorting: 0
|
||||
m_InterpolationPosesPerJob: 100
|
||||
m_NewContactsPerJob: 30
|
||||
m_CollideContactsPerJob: 100
|
||||
m_ClearFlagsPerJob: 200
|
||||
m_ClearBodyForcesPerJob: 200
|
||||
m_SyncDiscreteFixturesPerJob: 50
|
||||
m_SyncContinuousFixturesPerJob: 50
|
||||
m_FindNearestContactsPerJob: 100
|
||||
m_UpdateTriggerContactsPerJob: 100
|
||||
m_IslandSolverCostThreshold: 100
|
||||
m_IslandSolverBodyCostScale: 1
|
||||
m_IslandSolverContactCostScale: 10
|
||||
m_IslandSolverJointCostScale: 10
|
||||
m_IslandSolverBodiesPerJob: 50
|
||||
m_IslandSolverContactsPerJob: 50
|
||||
m_AutoSimulation: 1
|
||||
m_QueriesHitTriggers: 1
|
||||
m_QueriesStartInColliders: 1
|
||||
m_CallbacksOnDisable: 1
|
||||
m_ReuseCollisionCallbacks: 1
|
||||
m_AutoSyncTransforms: 0
|
||||
m_AlwaysShowColliders: 0
|
||||
m_ShowColliderSleep: 1
|
||||
m_ShowColliderContacts: 0
|
||||
m_ShowColliderAABB: 0
|
||||
m_ContactArrowScale: 0.2
|
||||
m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412}
|
||||
m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432}
|
||||
m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745}
|
||||
m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804}
|
||||
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
@ -1,7 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1386491679 &1
|
||||
PresetManager:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_DefaultPresets: {}
|
||||
@ -1,963 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!129 &1
|
||||
PlayerSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 26
|
||||
productGUID: 282a8bc53a357e94fb87cebb24064bb7
|
||||
AndroidProfiler: 0
|
||||
AndroidFilterTouchesWhenObscured: 0
|
||||
AndroidEnableSustainedPerformanceMode: 0
|
||||
defaultScreenOrientation: 4
|
||||
targetDevice: 2
|
||||
useOnDemandResources: 0
|
||||
accelerometerFrequency: 60
|
||||
companyName: DefaultCompany
|
||||
productName: MeowMentDebugTool
|
||||
defaultCursor: {fileID: 0}
|
||||
cursorHotspot: {x: 0, y: 0}
|
||||
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
|
||||
m_ShowUnitySplashScreen: 1
|
||||
m_ShowUnitySplashLogo: 1
|
||||
m_SplashScreenOverlayOpacity: 1
|
||||
m_SplashScreenAnimation: 1
|
||||
m_SplashScreenLogoStyle: 1
|
||||
m_SplashScreenDrawMode: 0
|
||||
m_SplashScreenBackgroundAnimationZoom: 1
|
||||
m_SplashScreenLogoAnimationZoom: 1
|
||||
m_SplashScreenBackgroundLandscapeAspect: 1
|
||||
m_SplashScreenBackgroundPortraitAspect: 1
|
||||
m_SplashScreenBackgroundLandscapeUvs:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
m_SplashScreenBackgroundPortraitUvs:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
m_SplashScreenLogos: []
|
||||
m_VirtualRealitySplashScreen: {fileID: 0}
|
||||
m_HolographicTrackingLossScreen: {fileID: 0}
|
||||
defaultScreenWidth: 1920
|
||||
defaultScreenHeight: 1080
|
||||
defaultScreenWidthWeb: 960
|
||||
defaultScreenHeightWeb: 600
|
||||
m_StereoRenderingPath: 0
|
||||
m_ActiveColorSpace: 1
|
||||
unsupportedMSAAFallback: 0
|
||||
m_SpriteBatchVertexThreshold: 300
|
||||
m_MTRendering: 1
|
||||
mipStripping: 0
|
||||
numberOfMipsStripped: 0
|
||||
numberOfMipsStrippedPerMipmapLimitGroup: {}
|
||||
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
|
||||
iosShowActivityIndicatorOnLoading: -1
|
||||
androidShowActivityIndicatorOnLoading: -1
|
||||
iosUseCustomAppBackgroundBehavior: 0
|
||||
allowedAutorotateToPortrait: 1
|
||||
allowedAutorotateToPortraitUpsideDown: 1
|
||||
allowedAutorotateToLandscapeRight: 1
|
||||
allowedAutorotateToLandscapeLeft: 1
|
||||
useOSAutorotation: 1
|
||||
use32BitDisplayBuffer: 1
|
||||
preserveFramebufferAlpha: 0
|
||||
disableDepthAndStencilBuffers: 0
|
||||
androidStartInFullscreen: 1
|
||||
androidRenderOutsideSafeArea: 1
|
||||
androidUseSwappy: 1
|
||||
androidBlitType: 0
|
||||
androidResizableWindow: 0
|
||||
androidDefaultWindowWidth: 1920
|
||||
androidDefaultWindowHeight: 1080
|
||||
androidMinimumWindowWidth: 400
|
||||
androidMinimumWindowHeight: 300
|
||||
androidFullscreenMode: 1
|
||||
androidAutoRotationBehavior: 1
|
||||
androidPredictiveBackSupport: 1
|
||||
defaultIsNativeResolution: 1
|
||||
macRetinaSupport: 1
|
||||
runInBackground: 1
|
||||
captureSingleScreen: 0
|
||||
muteOtherAudioSources: 0
|
||||
Prepare IOS For Recording: 0
|
||||
Force IOS Speakers When Recording: 0
|
||||
audioSpatialExperience: 0
|
||||
deferSystemGesturesMode: 0
|
||||
hideHomeButton: 0
|
||||
submitAnalytics: 1
|
||||
usePlayerLog: 1
|
||||
dedicatedServerOptimizations: 0
|
||||
bakeCollisionMeshes: 0
|
||||
forceSingleInstance: 0
|
||||
useFlipModelSwapchain: 1
|
||||
resizableWindow: 0
|
||||
useMacAppStoreValidation: 0
|
||||
macAppStoreCategory: public.app-category.games
|
||||
gpuSkinning: 1
|
||||
xboxPIXTextureCapture: 0
|
||||
xboxEnableAvatar: 0
|
||||
xboxEnableKinect: 0
|
||||
xboxEnableKinectAutoTracking: 0
|
||||
xboxEnableFitness: 0
|
||||
visibleInBackground: 1
|
||||
allowFullscreenSwitch: 1
|
||||
fullscreenMode: 1
|
||||
xboxSpeechDB: 0
|
||||
xboxEnableHeadOrientation: 0
|
||||
xboxEnableGuest: 0
|
||||
xboxEnablePIXSampling: 0
|
||||
metalFramebufferOnly: 0
|
||||
xboxOneResolution: 0
|
||||
xboxOneSResolution: 0
|
||||
xboxOneXResolution: 3
|
||||
xboxOneMonoLoggingLevel: 0
|
||||
xboxOneLoggingLevel: 1
|
||||
xboxOneDisableEsram: 0
|
||||
xboxOneEnableTypeOptimization: 0
|
||||
xboxOnePresentImmediateThreshold: 0
|
||||
switchQueueCommandMemory: 0
|
||||
switchQueueControlMemory: 16384
|
||||
switchQueueComputeMemory: 262144
|
||||
switchNVNShaderPoolsGranularity: 33554432
|
||||
switchNVNDefaultPoolsGranularity: 16777216
|
||||
switchNVNOtherPoolsGranularity: 16777216
|
||||
switchGpuScratchPoolGranularity: 2097152
|
||||
switchAllowGpuScratchShrinking: 0
|
||||
switchNVNMaxPublicTextureIDCount: 0
|
||||
switchNVNMaxPublicSamplerIDCount: 0
|
||||
switchNVNGraphicsFirmwareMemory: 32
|
||||
switchMaxWorkerMultiple: 8
|
||||
stadiaPresentMode: 0
|
||||
stadiaTargetFramerate: 0
|
||||
vulkanNumSwapchainBuffers: 3
|
||||
vulkanEnableSetSRGBWrite: 0
|
||||
vulkanEnablePreTransform: 1
|
||||
vulkanEnableLateAcquireNextImage: 0
|
||||
vulkanEnableCommandBufferRecycling: 1
|
||||
loadStoreDebugModeEnabled: 0
|
||||
visionOSBundleVersion: 1.0
|
||||
tvOSBundleVersion: 1.0
|
||||
bundleVersion: 0.1
|
||||
preloadedAssets: []
|
||||
metroInputSource: 0
|
||||
wsaTransparentSwapchain: 0
|
||||
m_HolographicPauseOnTrackingLoss: 1
|
||||
xboxOneDisableKinectGpuReservation: 1
|
||||
xboxOneEnable7thCore: 1
|
||||
vrSettings:
|
||||
enable360StereoCapture: 0
|
||||
isWsaHolographicRemotingEnabled: 0
|
||||
enableFrameTimingStats: 0
|
||||
enableOpenGLProfilerGPURecorders: 1
|
||||
allowHDRDisplaySupport: 0
|
||||
useHDRDisplay: 0
|
||||
hdrBitDepth: 0
|
||||
m_ColorGamuts: 00000000
|
||||
targetPixelDensity: 30
|
||||
resolutionScalingMode: 0
|
||||
resetResolutionOnWindowResize: 0
|
||||
androidSupportedAspectRatio: 1
|
||||
androidMaxAspectRatio: 2.1
|
||||
applicationIdentifier:
|
||||
Standalone: com.DefaultCompany.MeowMentDebugTool
|
||||
buildNumber:
|
||||
Standalone: 0
|
||||
VisionOS: 0
|
||||
iPhone: 0
|
||||
tvOS: 0
|
||||
overrideDefaultApplicationIdentifier: 0
|
||||
AndroidBundleVersionCode: 1
|
||||
AndroidMinSdkVersion: 22
|
||||
AndroidTargetSdkVersion: 0
|
||||
AndroidPreferredInstallLocation: 1
|
||||
aotOptions:
|
||||
stripEngineCode: 1
|
||||
iPhoneStrippingLevel: 0
|
||||
iPhoneScriptCallOptimization: 0
|
||||
ForceInternetPermission: 0
|
||||
ForceSDCardPermission: 0
|
||||
CreateWallpaper: 0
|
||||
APKExpansionFiles: 0
|
||||
keepLoadedShadersAlive: 0
|
||||
StripUnusedMeshComponents: 1
|
||||
strictShaderVariantMatching: 0
|
||||
VertexChannelCompressionMask: 4054
|
||||
iPhoneSdkVersion: 988
|
||||
iOSSimulatorArchitecture: 0
|
||||
iOSTargetOSVersionString: 12.0
|
||||
tvOSSdkVersion: 0
|
||||
tvOSSimulatorArchitecture: 0
|
||||
tvOSRequireExtendedGameController: 0
|
||||
tvOSTargetOSVersionString: 12.0
|
||||
VisionOSSdkVersion: 0
|
||||
VisionOSTargetOSVersionString: 1.0
|
||||
uIPrerenderedIcon: 0
|
||||
uIRequiresPersistentWiFi: 0
|
||||
uIRequiresFullScreen: 1
|
||||
uIStatusBarHidden: 1
|
||||
uIExitOnSuspend: 0
|
||||
uIStatusBarStyle: 0
|
||||
appleTVSplashScreen: {fileID: 0}
|
||||
appleTVSplashScreen2x: {fileID: 0}
|
||||
tvOSSmallIconLayers: []
|
||||
tvOSSmallIconLayers2x: []
|
||||
tvOSLargeIconLayers: []
|
||||
tvOSLargeIconLayers2x: []
|
||||
tvOSTopShelfImageLayers: []
|
||||
tvOSTopShelfImageLayers2x: []
|
||||
tvOSTopShelfImageWideLayers: []
|
||||
tvOSTopShelfImageWideLayers2x: []
|
||||
iOSLaunchScreenType: 0
|
||||
iOSLaunchScreenPortrait: {fileID: 0}
|
||||
iOSLaunchScreenLandscape: {fileID: 0}
|
||||
iOSLaunchScreenBackgroundColor:
|
||||
serializedVersion: 2
|
||||
rgba: 0
|
||||
iOSLaunchScreenFillPct: 100
|
||||
iOSLaunchScreenSize: 100
|
||||
iOSLaunchScreenCustomXibPath:
|
||||
iOSLaunchScreeniPadType: 0
|
||||
iOSLaunchScreeniPadImage: {fileID: 0}
|
||||
iOSLaunchScreeniPadBackgroundColor:
|
||||
serializedVersion: 2
|
||||
rgba: 0
|
||||
iOSLaunchScreeniPadFillPct: 100
|
||||
iOSLaunchScreeniPadSize: 100
|
||||
iOSLaunchScreeniPadCustomXibPath:
|
||||
iOSLaunchScreenCustomStoryboardPath:
|
||||
iOSLaunchScreeniPadCustomStoryboardPath:
|
||||
iOSDeviceRequirements: []
|
||||
iOSURLSchemes: []
|
||||
macOSURLSchemes: []
|
||||
iOSBackgroundModes: 0
|
||||
iOSMetalForceHardShadows: 0
|
||||
metalEditorSupport: 1
|
||||
metalAPIValidation: 1
|
||||
metalCompileShaderBinary: 0
|
||||
iOSRenderExtraFrameOnPause: 0
|
||||
iosCopyPluginsCodeInsteadOfSymlink: 0
|
||||
appleDeveloperTeamID:
|
||||
iOSManualSigningProvisioningProfileID:
|
||||
tvOSManualSigningProvisioningProfileID:
|
||||
VisionOSManualSigningProvisioningProfileID:
|
||||
iOSManualSigningProvisioningProfileType: 0
|
||||
tvOSManualSigningProvisioningProfileType: 0
|
||||
VisionOSManualSigningProvisioningProfileType: 0
|
||||
appleEnableAutomaticSigning: 0
|
||||
iOSRequireARKit: 0
|
||||
iOSAutomaticallyDetectAndAddCapabilities: 1
|
||||
appleEnableProMotion: 0
|
||||
shaderPrecisionModel: 0
|
||||
clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea
|
||||
templatePackageId: com.unity.template.packagetemplate@1.0.0
|
||||
templateDefaultScene: Assets/Scenes/SampleScene.unity
|
||||
useCustomMainManifest: 0
|
||||
useCustomLauncherManifest: 0
|
||||
useCustomMainGradleTemplate: 0
|
||||
useCustomLauncherGradleManifest: 0
|
||||
useCustomBaseGradleTemplate: 0
|
||||
useCustomGradlePropertiesTemplate: 0
|
||||
useCustomGradleSettingsTemplate: 0
|
||||
useCustomProguardFile: 0
|
||||
AndroidTargetArchitectures: 1
|
||||
AndroidTargetDevices: 0
|
||||
AndroidSplashScreenScale: 0
|
||||
androidSplashScreen: {fileID: 0}
|
||||
AndroidKeystoreName:
|
||||
AndroidKeyaliasName:
|
||||
AndroidEnableArmv9SecurityFeatures: 0
|
||||
AndroidBuildApkPerCpuArchitecture: 0
|
||||
AndroidTVCompatibility: 0
|
||||
AndroidIsGame: 1
|
||||
AndroidEnableTango: 0
|
||||
androidEnableBanner: 1
|
||||
androidUseLowAccuracyLocation: 0
|
||||
androidUseCustomKeystore: 0
|
||||
m_AndroidBanners:
|
||||
- width: 320
|
||||
height: 180
|
||||
banner: {fileID: 0}
|
||||
androidGamepadSupportLevel: 0
|
||||
chromeosInputEmulation: 1
|
||||
AndroidMinifyRelease: 0
|
||||
AndroidMinifyDebug: 0
|
||||
AndroidValidateAppBundleSize: 1
|
||||
AndroidAppBundleSizeToValidate: 150
|
||||
m_BuildTargetIcons: []
|
||||
m_BuildTargetPlatformIcons:
|
||||
- m_BuildTarget: iPhone
|
||||
m_Icons:
|
||||
- m_Textures: []
|
||||
m_Width: 180
|
||||
m_Height: 180
|
||||
m_Kind: 0
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 120
|
||||
m_Height: 120
|
||||
m_Kind: 0
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 167
|
||||
m_Height: 167
|
||||
m_Kind: 0
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 152
|
||||
m_Height: 152
|
||||
m_Kind: 0
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 76
|
||||
m_Height: 76
|
||||
m_Kind: 0
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 120
|
||||
m_Height: 120
|
||||
m_Kind: 3
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 80
|
||||
m_Height: 80
|
||||
m_Kind: 3
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 80
|
||||
m_Height: 80
|
||||
m_Kind: 3
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 40
|
||||
m_Height: 40
|
||||
m_Kind: 3
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 87
|
||||
m_Height: 87
|
||||
m_Kind: 1
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 58
|
||||
m_Height: 58
|
||||
m_Kind: 1
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 29
|
||||
m_Height: 29
|
||||
m_Kind: 1
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 58
|
||||
m_Height: 58
|
||||
m_Kind: 1
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 29
|
||||
m_Height: 29
|
||||
m_Kind: 1
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 60
|
||||
m_Height: 60
|
||||
m_Kind: 2
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 40
|
||||
m_Height: 40
|
||||
m_Kind: 2
|
||||
m_SubKind: iPhone
|
||||
- m_Textures: []
|
||||
m_Width: 40
|
||||
m_Height: 40
|
||||
m_Kind: 2
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 20
|
||||
m_Height: 20
|
||||
m_Kind: 2
|
||||
m_SubKind: iPad
|
||||
- m_Textures: []
|
||||
m_Width: 1024
|
||||
m_Height: 1024
|
||||
m_Kind: 4
|
||||
m_SubKind: App Store
|
||||
- m_BuildTarget: Android
|
||||
m_Icons:
|
||||
- m_Textures: []
|
||||
m_Width: 432
|
||||
m_Height: 432
|
||||
m_Kind: 2
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 324
|
||||
m_Height: 324
|
||||
m_Kind: 2
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 216
|
||||
m_Height: 216
|
||||
m_Kind: 2
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 162
|
||||
m_Height: 162
|
||||
m_Kind: 2
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 108
|
||||
m_Height: 108
|
||||
m_Kind: 2
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 81
|
||||
m_Height: 81
|
||||
m_Kind: 2
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 192
|
||||
m_Height: 192
|
||||
m_Kind: 1
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 144
|
||||
m_Height: 144
|
||||
m_Kind: 1
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 96
|
||||
m_Height: 96
|
||||
m_Kind: 1
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 72
|
||||
m_Height: 72
|
||||
m_Kind: 1
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 48
|
||||
m_Height: 48
|
||||
m_Kind: 1
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 36
|
||||
m_Height: 36
|
||||
m_Kind: 1
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 192
|
||||
m_Height: 192
|
||||
m_Kind: 0
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 144
|
||||
m_Height: 144
|
||||
m_Kind: 0
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 96
|
||||
m_Height: 96
|
||||
m_Kind: 0
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 72
|
||||
m_Height: 72
|
||||
m_Kind: 0
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 48
|
||||
m_Height: 48
|
||||
m_Kind: 0
|
||||
m_SubKind:
|
||||
- m_Textures: []
|
||||
m_Width: 36
|
||||
m_Height: 36
|
||||
m_Kind: 0
|
||||
m_SubKind:
|
||||
m_BuildTargetBatching:
|
||||
- m_BuildTarget: Standalone
|
||||
m_StaticBatching: 1
|
||||
m_DynamicBatching: 0
|
||||
- m_BuildTarget: tvOS
|
||||
m_StaticBatching: 1
|
||||
m_DynamicBatching: 0
|
||||
- m_BuildTarget: Android
|
||||
m_StaticBatching: 1
|
||||
m_DynamicBatching: 0
|
||||
- m_BuildTarget: iPhone
|
||||
m_StaticBatching: 1
|
||||
m_DynamicBatching: 0
|
||||
- m_BuildTarget: WebGL
|
||||
m_StaticBatching: 0
|
||||
m_DynamicBatching: 0
|
||||
m_BuildTargetShaderSettings: []
|
||||
m_BuildTargetGraphicsJobs:
|
||||
- m_BuildTarget: MacStandaloneSupport
|
||||
m_GraphicsJobs: 0
|
||||
- m_BuildTarget: Switch
|
||||
m_GraphicsJobs: 1
|
||||
- m_BuildTarget: MetroSupport
|
||||
m_GraphicsJobs: 1
|
||||
- m_BuildTarget: AppleTVSupport
|
||||
m_GraphicsJobs: 0
|
||||
- m_BuildTarget: BJMSupport
|
||||
m_GraphicsJobs: 1
|
||||
- m_BuildTarget: LinuxStandaloneSupport
|
||||
m_GraphicsJobs: 1
|
||||
- m_BuildTarget: PS4Player
|
||||
m_GraphicsJobs: 1
|
||||
- m_BuildTarget: iOSSupport
|
||||
m_GraphicsJobs: 0
|
||||
- m_BuildTarget: WindowsStandaloneSupport
|
||||
m_GraphicsJobs: 1
|
||||
- m_BuildTarget: XboxOnePlayer
|
||||
m_GraphicsJobs: 1
|
||||
- m_BuildTarget: LuminSupport
|
||||
m_GraphicsJobs: 0
|
||||
- m_BuildTarget: AndroidPlayer
|
||||
m_GraphicsJobs: 0
|
||||
- m_BuildTarget: WebGLSupport
|
||||
m_GraphicsJobs: 0
|
||||
m_BuildTargetGraphicsJobMode:
|
||||
- m_BuildTarget: PS4Player
|
||||
m_GraphicsJobMode: 0
|
||||
- m_BuildTarget: XboxOnePlayer
|
||||
m_GraphicsJobMode: 0
|
||||
m_BuildTargetGraphicsAPIs:
|
||||
- m_BuildTarget: AndroidPlayer
|
||||
m_APIs: 150000000b000000
|
||||
m_Automatic: 1
|
||||
- m_BuildTarget: iOSSupport
|
||||
m_APIs: 10000000
|
||||
m_Automatic: 1
|
||||
- m_BuildTarget: AppleTVSupport
|
||||
m_APIs: 10000000
|
||||
m_Automatic: 1
|
||||
- m_BuildTarget: WebGLSupport
|
||||
m_APIs: 0b000000
|
||||
m_Automatic: 1
|
||||
m_BuildTargetVRSettings:
|
||||
- m_BuildTarget: Standalone
|
||||
m_Enabled: 0
|
||||
m_Devices:
|
||||
- Oculus
|
||||
- OpenVR
|
||||
m_DefaultShaderChunkSizeInMB: 16
|
||||
m_DefaultShaderChunkCount: 0
|
||||
openGLRequireES31: 0
|
||||
openGLRequireES31AEP: 0
|
||||
openGLRequireES32: 0
|
||||
m_TemplateCustomTags: {}
|
||||
mobileMTRendering:
|
||||
Android: 1
|
||||
iPhone: 1
|
||||
tvOS: 1
|
||||
m_BuildTargetGroupLightmapEncodingQuality:
|
||||
- m_BuildTarget: Android
|
||||
m_EncodingQuality: 1
|
||||
- m_BuildTarget: iPhone
|
||||
m_EncodingQuality: 1
|
||||
- m_BuildTarget: tvOS
|
||||
m_EncodingQuality: 1
|
||||
m_BuildTargetGroupHDRCubemapEncodingQuality:
|
||||
- m_BuildTarget: Android
|
||||
m_EncodingQuality: 1
|
||||
- m_BuildTarget: iPhone
|
||||
m_EncodingQuality: 1
|
||||
- m_BuildTarget: tvOS
|
||||
m_EncodingQuality: 1
|
||||
m_BuildTargetGroupLightmapSettings: []
|
||||
m_BuildTargetGroupLoadStoreDebugModeSettings: []
|
||||
m_BuildTargetNormalMapEncoding:
|
||||
- m_BuildTarget: Android
|
||||
m_Encoding: 1
|
||||
- m_BuildTarget: iPhone
|
||||
m_Encoding: 1
|
||||
- m_BuildTarget: tvOS
|
||||
m_Encoding: 1
|
||||
m_BuildTargetDefaultTextureCompressionFormat:
|
||||
- m_BuildTarget: Android
|
||||
m_Format: 3
|
||||
playModeTestRunnerEnabled: 0
|
||||
runPlayModeTestAsEditModeTest: 0
|
||||
actionOnDotNetUnhandledException: 1
|
||||
enableInternalProfiler: 0
|
||||
logObjCUncaughtExceptions: 1
|
||||
enableCrashReportAPI: 0
|
||||
cameraUsageDescription:
|
||||
locationUsageDescription:
|
||||
microphoneUsageDescription:
|
||||
bluetoothUsageDescription:
|
||||
macOSTargetOSVersion: 10.13.0
|
||||
switchNMETAOverride:
|
||||
switchNetLibKey:
|
||||
switchSocketMemoryPoolSize: 6144
|
||||
switchSocketAllocatorPoolSize: 128
|
||||
switchSocketConcurrencyLimit: 14
|
||||
switchScreenResolutionBehavior: 2
|
||||
switchUseCPUProfiler: 0
|
||||
switchEnableFileSystemTrace: 0
|
||||
switchLTOSetting: 0
|
||||
switchApplicationID: 0x01004b9000490000
|
||||
switchNSODependencies:
|
||||
switchCompilerFlags:
|
||||
switchTitleNames_0:
|
||||
switchTitleNames_1:
|
||||
switchTitleNames_2:
|
||||
switchTitleNames_3:
|
||||
switchTitleNames_4:
|
||||
switchTitleNames_5:
|
||||
switchTitleNames_6:
|
||||
switchTitleNames_7:
|
||||
switchTitleNames_8:
|
||||
switchTitleNames_9:
|
||||
switchTitleNames_10:
|
||||
switchTitleNames_11:
|
||||
switchTitleNames_12:
|
||||
switchTitleNames_13:
|
||||
switchTitleNames_14:
|
||||
switchTitleNames_15:
|
||||
switchPublisherNames_0:
|
||||
switchPublisherNames_1:
|
||||
switchPublisherNames_2:
|
||||
switchPublisherNames_3:
|
||||
switchPublisherNames_4:
|
||||
switchPublisherNames_5:
|
||||
switchPublisherNames_6:
|
||||
switchPublisherNames_7:
|
||||
switchPublisherNames_8:
|
||||
switchPublisherNames_9:
|
||||
switchPublisherNames_10:
|
||||
switchPublisherNames_11:
|
||||
switchPublisherNames_12:
|
||||
switchPublisherNames_13:
|
||||
switchPublisherNames_14:
|
||||
switchPublisherNames_15:
|
||||
switchIcons_0: {fileID: 0}
|
||||
switchIcons_1: {fileID: 0}
|
||||
switchIcons_2: {fileID: 0}
|
||||
switchIcons_3: {fileID: 0}
|
||||
switchIcons_4: {fileID: 0}
|
||||
switchIcons_5: {fileID: 0}
|
||||
switchIcons_6: {fileID: 0}
|
||||
switchIcons_7: {fileID: 0}
|
||||
switchIcons_8: {fileID: 0}
|
||||
switchIcons_9: {fileID: 0}
|
||||
switchIcons_10: {fileID: 0}
|
||||
switchIcons_11: {fileID: 0}
|
||||
switchIcons_12: {fileID: 0}
|
||||
switchIcons_13: {fileID: 0}
|
||||
switchIcons_14: {fileID: 0}
|
||||
switchIcons_15: {fileID: 0}
|
||||
switchSmallIcons_0: {fileID: 0}
|
||||
switchSmallIcons_1: {fileID: 0}
|
||||
switchSmallIcons_2: {fileID: 0}
|
||||
switchSmallIcons_3: {fileID: 0}
|
||||
switchSmallIcons_4: {fileID: 0}
|
||||
switchSmallIcons_5: {fileID: 0}
|
||||
switchSmallIcons_6: {fileID: 0}
|
||||
switchSmallIcons_7: {fileID: 0}
|
||||
switchSmallIcons_8: {fileID: 0}
|
||||
switchSmallIcons_9: {fileID: 0}
|
||||
switchSmallIcons_10: {fileID: 0}
|
||||
switchSmallIcons_11: {fileID: 0}
|
||||
switchSmallIcons_12: {fileID: 0}
|
||||
switchSmallIcons_13: {fileID: 0}
|
||||
switchSmallIcons_14: {fileID: 0}
|
||||
switchSmallIcons_15: {fileID: 0}
|
||||
switchManualHTML:
|
||||
switchAccessibleURLs:
|
||||
switchLegalInformation:
|
||||
switchMainThreadStackSize: 1048576
|
||||
switchPresenceGroupId:
|
||||
switchLogoHandling: 0
|
||||
switchReleaseVersion: 0
|
||||
switchDisplayVersion: 1.0.0
|
||||
switchStartupUserAccount: 0
|
||||
switchSupportedLanguagesMask: 0
|
||||
switchLogoType: 0
|
||||
switchApplicationErrorCodeCategory:
|
||||
switchUserAccountSaveDataSize: 0
|
||||
switchUserAccountSaveDataJournalSize: 0
|
||||
switchApplicationAttribute: 0
|
||||
switchCardSpecSize: -1
|
||||
switchCardSpecClock: -1
|
||||
switchRatingsMask: 0
|
||||
switchRatingsInt_0: 0
|
||||
switchRatingsInt_1: 0
|
||||
switchRatingsInt_2: 0
|
||||
switchRatingsInt_3: 0
|
||||
switchRatingsInt_4: 0
|
||||
switchRatingsInt_5: 0
|
||||
switchRatingsInt_6: 0
|
||||
switchRatingsInt_7: 0
|
||||
switchRatingsInt_8: 0
|
||||
switchRatingsInt_9: 0
|
||||
switchRatingsInt_10: 0
|
||||
switchRatingsInt_11: 0
|
||||
switchRatingsInt_12: 0
|
||||
switchLocalCommunicationIds_0:
|
||||
switchLocalCommunicationIds_1:
|
||||
switchLocalCommunicationIds_2:
|
||||
switchLocalCommunicationIds_3:
|
||||
switchLocalCommunicationIds_4:
|
||||
switchLocalCommunicationIds_5:
|
||||
switchLocalCommunicationIds_6:
|
||||
switchLocalCommunicationIds_7:
|
||||
switchParentalControl: 0
|
||||
switchAllowsScreenshot: 1
|
||||
switchAllowsVideoCapturing: 1
|
||||
switchAllowsRuntimeAddOnContentInstall: 0
|
||||
switchDataLossConfirmation: 0
|
||||
switchUserAccountLockEnabled: 0
|
||||
switchSystemResourceMemory: 16777216
|
||||
switchSupportedNpadStyles: 22
|
||||
switchNativeFsCacheSize: 32
|
||||
switchIsHoldTypeHorizontal: 0
|
||||
switchSupportedNpadCount: 8
|
||||
switchEnableTouchScreen: 1
|
||||
switchSocketConfigEnabled: 0
|
||||
switchTcpInitialSendBufferSize: 32
|
||||
switchTcpInitialReceiveBufferSize: 64
|
||||
switchTcpAutoSendBufferSizeMax: 256
|
||||
switchTcpAutoReceiveBufferSizeMax: 256
|
||||
switchUdpSendBufferSize: 9
|
||||
switchUdpReceiveBufferSize: 42
|
||||
switchSocketBufferEfficiency: 4
|
||||
switchSocketInitializeEnabled: 1
|
||||
switchNetworkInterfaceManagerInitializeEnabled: 1
|
||||
switchDisableHTCSPlayerConnection: 0
|
||||
switchUseNewStyleFilepaths: 1
|
||||
switchUseLegacyFmodPriorities: 0
|
||||
switchUseMicroSleepForYield: 1
|
||||
switchEnableRamDiskSupport: 0
|
||||
switchMicroSleepForYieldTime: 25
|
||||
switchRamDiskSpaceSize: 12
|
||||
ps4NPAgeRating: 12
|
||||
ps4NPTitleSecret:
|
||||
ps4NPTrophyPackPath:
|
||||
ps4ParentalLevel: 11
|
||||
ps4ContentID: ED1633-NPXX51362_00-0000000000000000
|
||||
ps4Category: 0
|
||||
ps4MasterVersion: 01.00
|
||||
ps4AppVersion: 01.00
|
||||
ps4AppType: 0
|
||||
ps4ParamSfxPath:
|
||||
ps4VideoOutPixelFormat: 0
|
||||
ps4VideoOutInitialWidth: 1920
|
||||
ps4VideoOutBaseModeInitialWidth: 1920
|
||||
ps4VideoOutReprojectionRate: 60
|
||||
ps4PronunciationXMLPath:
|
||||
ps4PronunciationSIGPath:
|
||||
ps4BackgroundImagePath:
|
||||
ps4StartupImagePath:
|
||||
ps4StartupImagesFolder:
|
||||
ps4IconImagesFolder:
|
||||
ps4SaveDataImagePath:
|
||||
ps4SdkOverride:
|
||||
ps4BGMPath:
|
||||
ps4ShareFilePath:
|
||||
ps4ShareOverlayImagePath:
|
||||
ps4PrivacyGuardImagePath:
|
||||
ps4ExtraSceSysFile:
|
||||
ps4NPtitleDatPath:
|
||||
ps4RemotePlayKeyAssignment: -1
|
||||
ps4RemotePlayKeyMappingDir:
|
||||
ps4PlayTogetherPlayerCount: 0
|
||||
ps4EnterButtonAssignment: 1
|
||||
ps4ApplicationParam1: 0
|
||||
ps4ApplicationParam2: 0
|
||||
ps4ApplicationParam3: 0
|
||||
ps4ApplicationParam4: 0
|
||||
ps4DownloadDataSize: 0
|
||||
ps4GarlicHeapSize: 2048
|
||||
ps4ProGarlicHeapSize: 2560
|
||||
playerPrefsMaxSize: 32768
|
||||
ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
|
||||
ps4pnSessions: 1
|
||||
ps4pnPresence: 1
|
||||
ps4pnFriends: 1
|
||||
ps4pnGameCustomData: 1
|
||||
playerPrefsSupport: 0
|
||||
enableApplicationExit: 0
|
||||
resetTempFolder: 1
|
||||
restrictedAudioUsageRights: 0
|
||||
ps4UseResolutionFallback: 0
|
||||
ps4ReprojectionSupport: 0
|
||||
ps4UseAudio3dBackend: 0
|
||||
ps4UseLowGarlicFragmentationMode: 1
|
||||
ps4SocialScreenEnabled: 0
|
||||
ps4ScriptOptimizationLevel: 0
|
||||
ps4Audio3dVirtualSpeakerCount: 14
|
||||
ps4attribCpuUsage: 0
|
||||
ps4PatchPkgPath:
|
||||
ps4PatchLatestPkgPath:
|
||||
ps4PatchChangeinfoPath:
|
||||
ps4PatchDayOne: 0
|
||||
ps4attribUserManagement: 0
|
||||
ps4attribMoveSupport: 0
|
||||
ps4attrib3DSupport: 0
|
||||
ps4attribShareSupport: 0
|
||||
ps4attribExclusiveVR: 0
|
||||
ps4disableAutoHideSplash: 0
|
||||
ps4videoRecordingFeaturesUsed: 0
|
||||
ps4contentSearchFeaturesUsed: 0
|
||||
ps4CompatibilityPS5: 0
|
||||
ps4AllowPS5Detection: 0
|
||||
ps4GPU800MHz: 1
|
||||
ps4attribEyeToEyeDistanceSettingVR: 0
|
||||
ps4IncludedModules: []
|
||||
ps4attribVROutputEnabled: 0
|
||||
monoEnv:
|
||||
splashScreenBackgroundSourceLandscape: {fileID: 0}
|
||||
splashScreenBackgroundSourcePortrait: {fileID: 0}
|
||||
blurSplashScreenBackground: 1
|
||||
spritePackerPolicy:
|
||||
webGLMemorySize: 16
|
||||
webGLExceptionSupport: 1
|
||||
webGLNameFilesAsHashes: 0
|
||||
webGLShowDiagnostics: 0
|
||||
webGLDataCaching: 1
|
||||
webGLDebugSymbols: 0
|
||||
webGLEmscriptenArgs:
|
||||
webGLModulesDirectory:
|
||||
webGLTemplate: APPLICATION:Default
|
||||
webGLAnalyzeBuildSize: 0
|
||||
webGLUseEmbeddedResources: 0
|
||||
webGLCompressionFormat: 1
|
||||
webGLWasmArithmeticExceptions: 0
|
||||
webGLLinkerTarget: 1
|
||||
webGLThreadsSupport: 0
|
||||
webGLDecompressionFallback: 0
|
||||
webGLInitialMemorySize: 32
|
||||
webGLMaximumMemorySize: 2048
|
||||
webGLMemoryGrowthMode: 2
|
||||
webGLMemoryLinearGrowthStep: 16
|
||||
webGLMemoryGeometricGrowthStep: 0.2
|
||||
webGLMemoryGeometricGrowthCap: 96
|
||||
webGLPowerPreference: 2
|
||||
scriptingDefineSymbols:
|
||||
Standalone: MEOWMENT_DEBUG_TOOL
|
||||
additionalCompilerArguments: {}
|
||||
platformArchitecture: {}
|
||||
scriptingBackend: {}
|
||||
il2cppCompilerConfiguration: {}
|
||||
il2cppCodeGeneration: {}
|
||||
managedStrippingLevel:
|
||||
EmbeddedLinux: 1
|
||||
GameCoreScarlett: 1
|
||||
GameCoreXboxOne: 1
|
||||
Nintendo Switch: 1
|
||||
PS4: 1
|
||||
PS5: 1
|
||||
QNX: 1
|
||||
Stadia: 1
|
||||
VisionOS: 1
|
||||
WebGL: 1
|
||||
Windows Store Apps: 1
|
||||
XboxOne: 1
|
||||
iPhone: 1
|
||||
tvOS: 1
|
||||
incrementalIl2cppBuild: {}
|
||||
suppressCommonWarnings: 1
|
||||
allowUnsafeCode: 0
|
||||
useDeterministicCompilation: 1
|
||||
additionalIl2CppArgs:
|
||||
scriptingRuntimeVersion: 1
|
||||
gcIncremental: 1
|
||||
gcWBarrierValidation: 0
|
||||
apiCompatibilityLevelPerPlatform: {}
|
||||
m_RenderingPath: 1
|
||||
m_MobileRenderingPath: 1
|
||||
metroPackageName: MeowMentDebugTool
|
||||
metroPackageVersion:
|
||||
metroCertificatePath:
|
||||
metroCertificatePassword:
|
||||
metroCertificateSubject:
|
||||
metroCertificateIssuer:
|
||||
metroCertificateNotAfter: 0000000000000000
|
||||
metroApplicationDescription: MeowMentDebugTool
|
||||
wsaImages: {}
|
||||
metroTileShortName:
|
||||
metroTileShowName: 0
|
||||
metroMediumTileShowName: 0
|
||||
metroLargeTileShowName: 0
|
||||
metroWideTileShowName: 0
|
||||
metroSupportStreamingInstall: 0
|
||||
metroLastRequiredScene: 0
|
||||
metroDefaultTileSize: 1
|
||||
metroTileForegroundText: 2
|
||||
metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
|
||||
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1}
|
||||
metroSplashScreenUseBackgroundColor: 0
|
||||
syncCapabilities: 0
|
||||
platformCapabilities: {}
|
||||
metroTargetDeviceFamilies: {}
|
||||
metroFTAName:
|
||||
metroFTAFileTypes: []
|
||||
metroProtocolName:
|
||||
vcxProjDefaultLanguage:
|
||||
XboxOneProductId:
|
||||
XboxOneUpdateKey:
|
||||
XboxOneSandboxId:
|
||||
XboxOneContentId:
|
||||
XboxOneTitleId:
|
||||
XboxOneSCId:
|
||||
XboxOneGameOsOverridePath:
|
||||
XboxOnePackagingOverridePath:
|
||||
XboxOneAppManifestOverridePath:
|
||||
XboxOneVersion: 1.0.0.0
|
||||
XboxOnePackageEncryption: 0
|
||||
XboxOnePackageUpdateGranularity: 2
|
||||
XboxOneDescription:
|
||||
XboxOneLanguage:
|
||||
- enus
|
||||
XboxOneCapability: []
|
||||
XboxOneGameRating: {}
|
||||
XboxOneIsContentPackage: 0
|
||||
XboxOneEnhancedXboxCompatibilityMode: 0
|
||||
XboxOneEnableGPUVariability: 1
|
||||
XboxOneSockets: {}
|
||||
XboxOneSplashScreen: {fileID: 0}
|
||||
XboxOneAllowedProductIds: []
|
||||
XboxOnePersistentLocalStorageSize: 0
|
||||
XboxOneXTitleMemory: 8
|
||||
XboxOneOverrideIdentityName:
|
||||
XboxOneOverrideIdentityPublisher:
|
||||
vrEditorSettings: {}
|
||||
cloudServicesEnabled:
|
||||
UNet: 1
|
||||
luminIcon:
|
||||
m_Name:
|
||||
m_ModelFolderPath:
|
||||
m_PortalFolderPath:
|
||||
luminCert:
|
||||
m_CertPath:
|
||||
m_SignPackage: 1
|
||||
luminIsChannelApp: 0
|
||||
luminVersion:
|
||||
m_VersionCode: 1
|
||||
m_VersionName:
|
||||
hmiPlayerDataPath:
|
||||
hmiForceSRGBBlit: 1
|
||||
embeddedLinuxEnableGamepadInput: 1
|
||||
hmiLogStartupTiming: 0
|
||||
hmiCpuConfiguration:
|
||||
apiCompatibilityLevel: 6
|
||||
activeInputHandler: 0
|
||||
windowsGamepadBackendHint: 0
|
||||
cloudProjectId:
|
||||
framebufferDepthMemorylessMode: 0
|
||||
qualitySettingsNames: []
|
||||
projectName:
|
||||
organizationId:
|
||||
cloudEnabled: 0
|
||||
legacyClampBlendShapeWeights: 0
|
||||
hmiLoadingImage: {fileID: 0}
|
||||
platformRequiresReadableAssets: 0
|
||||
virtualTexturingSupportEnabled: 0
|
||||
insecureHttpOption: 0
|
||||
@ -1,2 +0,0 @@
|
||||
m_EditorVersion: 2022.3.62f3
|
||||
m_EditorVersionWithRevision: 2022.3.62f3 (96770f904ca7)
|
||||
@ -1,234 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!47 &1
|
||||
QualitySettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 5
|
||||
m_CurrentQuality: 5
|
||||
m_QualitySettings:
|
||||
- serializedVersion: 2
|
||||
name: Very Low
|
||||
pixelLightCount: 0
|
||||
shadows: 0
|
||||
shadowResolution: 0
|
||||
shadowProjection: 1
|
||||
shadowCascades: 1
|
||||
shadowDistance: 15
|
||||
shadowNearPlaneOffset: 3
|
||||
shadowCascade2Split: 0.33333334
|
||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||
shadowmaskMode: 0
|
||||
blendWeights: 1
|
||||
textureQuality: 1
|
||||
anisotropicTextures: 0
|
||||
antiAliasing: 0
|
||||
softParticles: 0
|
||||
softVegetation: 0
|
||||
realtimeReflectionProbes: 0
|
||||
billboardsFaceCameraPosition: 0
|
||||
vSyncCount: 0
|
||||
lodBias: 0.3
|
||||
maximumLODLevel: 0
|
||||
streamingMipmapsActive: 0
|
||||
streamingMipmapsAddAllCameras: 1
|
||||
streamingMipmapsMemoryBudget: 512
|
||||
streamingMipmapsRenderersPerFrame: 512
|
||||
streamingMipmapsMaxLevelReduction: 2
|
||||
streamingMipmapsMaxFileIORequests: 1024
|
||||
particleRaycastBudget: 4
|
||||
asyncUploadTimeSlice: 2
|
||||
asyncUploadBufferSize: 16
|
||||
asyncUploadPersistentBuffer: 1
|
||||
resolutionScalingFixedDPIFactor: 1
|
||||
excludedTargetPlatforms: []
|
||||
- serializedVersion: 2
|
||||
name: Low
|
||||
pixelLightCount: 0
|
||||
shadows: 0
|
||||
shadowResolution: 0
|
||||
shadowProjection: 1
|
||||
shadowCascades: 1
|
||||
shadowDistance: 20
|
||||
shadowNearPlaneOffset: 3
|
||||
shadowCascade2Split: 0.33333334
|
||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||
shadowmaskMode: 0
|
||||
blendWeights: 2
|
||||
textureQuality: 0
|
||||
anisotropicTextures: 0
|
||||
antiAliasing: 0
|
||||
softParticles: 0
|
||||
softVegetation: 0
|
||||
realtimeReflectionProbes: 0
|
||||
billboardsFaceCameraPosition: 0
|
||||
vSyncCount: 0
|
||||
lodBias: 0.4
|
||||
maximumLODLevel: 0
|
||||
streamingMipmapsActive: 0
|
||||
streamingMipmapsAddAllCameras: 1
|
||||
streamingMipmapsMemoryBudget: 512
|
||||
streamingMipmapsRenderersPerFrame: 512
|
||||
streamingMipmapsMaxLevelReduction: 2
|
||||
streamingMipmapsMaxFileIORequests: 1024
|
||||
particleRaycastBudget: 16
|
||||
asyncUploadTimeSlice: 2
|
||||
asyncUploadBufferSize: 16
|
||||
asyncUploadPersistentBuffer: 1
|
||||
resolutionScalingFixedDPIFactor: 1
|
||||
excludedTargetPlatforms: []
|
||||
- serializedVersion: 2
|
||||
name: Medium
|
||||
pixelLightCount: 1
|
||||
shadows: 1
|
||||
shadowResolution: 0
|
||||
shadowProjection: 1
|
||||
shadowCascades: 1
|
||||
shadowDistance: 20
|
||||
shadowNearPlaneOffset: 3
|
||||
shadowCascade2Split: 0.33333334
|
||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||
shadowmaskMode: 0
|
||||
blendWeights: 2
|
||||
textureQuality: 0
|
||||
anisotropicTextures: 1
|
||||
antiAliasing: 0
|
||||
softParticles: 0
|
||||
softVegetation: 0
|
||||
realtimeReflectionProbes: 0
|
||||
billboardsFaceCameraPosition: 0
|
||||
vSyncCount: 1
|
||||
lodBias: 0.7
|
||||
maximumLODLevel: 0
|
||||
streamingMipmapsActive: 0
|
||||
streamingMipmapsAddAllCameras: 1
|
||||
streamingMipmapsMemoryBudget: 512
|
||||
streamingMipmapsRenderersPerFrame: 512
|
||||
streamingMipmapsMaxLevelReduction: 2
|
||||
streamingMipmapsMaxFileIORequests: 1024
|
||||
particleRaycastBudget: 64
|
||||
asyncUploadTimeSlice: 2
|
||||
asyncUploadBufferSize: 16
|
||||
asyncUploadPersistentBuffer: 1
|
||||
resolutionScalingFixedDPIFactor: 1
|
||||
excludedTargetPlatforms: []
|
||||
- serializedVersion: 2
|
||||
name: High
|
||||
pixelLightCount: 2
|
||||
shadows: 2
|
||||
shadowResolution: 1
|
||||
shadowProjection: 1
|
||||
shadowCascades: 2
|
||||
shadowDistance: 40
|
||||
shadowNearPlaneOffset: 3
|
||||
shadowCascade2Split: 0.33333334
|
||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||
shadowmaskMode: 1
|
||||
blendWeights: 2
|
||||
textureQuality: 0
|
||||
anisotropicTextures: 1
|
||||
antiAliasing: 0
|
||||
softParticles: 0
|
||||
softVegetation: 1
|
||||
realtimeReflectionProbes: 1
|
||||
billboardsFaceCameraPosition: 1
|
||||
vSyncCount: 1
|
||||
lodBias: 1
|
||||
maximumLODLevel: 0
|
||||
streamingMipmapsActive: 0
|
||||
streamingMipmapsAddAllCameras: 1
|
||||
streamingMipmapsMemoryBudget: 512
|
||||
streamingMipmapsRenderersPerFrame: 512
|
||||
streamingMipmapsMaxLevelReduction: 2
|
||||
streamingMipmapsMaxFileIORequests: 1024
|
||||
particleRaycastBudget: 256
|
||||
asyncUploadTimeSlice: 2
|
||||
asyncUploadBufferSize: 16
|
||||
asyncUploadPersistentBuffer: 1
|
||||
resolutionScalingFixedDPIFactor: 1
|
||||
excludedTargetPlatforms: []
|
||||
- serializedVersion: 2
|
||||
name: Very High
|
||||
pixelLightCount: 3
|
||||
shadows: 2
|
||||
shadowResolution: 2
|
||||
shadowProjection: 1
|
||||
shadowCascades: 2
|
||||
shadowDistance: 70
|
||||
shadowNearPlaneOffset: 3
|
||||
shadowCascade2Split: 0.33333334
|
||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||
shadowmaskMode: 1
|
||||
blendWeights: 4
|
||||
textureQuality: 0
|
||||
anisotropicTextures: 2
|
||||
antiAliasing: 2
|
||||
softParticles: 1
|
||||
softVegetation: 1
|
||||
realtimeReflectionProbes: 1
|
||||
billboardsFaceCameraPosition: 1
|
||||
vSyncCount: 1
|
||||
lodBias: 1.5
|
||||
maximumLODLevel: 0
|
||||
streamingMipmapsActive: 0
|
||||
streamingMipmapsAddAllCameras: 1
|
||||
streamingMipmapsMemoryBudget: 512
|
||||
streamingMipmapsRenderersPerFrame: 512
|
||||
streamingMipmapsMaxLevelReduction: 2
|
||||
streamingMipmapsMaxFileIORequests: 1024
|
||||
particleRaycastBudget: 1024
|
||||
asyncUploadTimeSlice: 2
|
||||
asyncUploadBufferSize: 16
|
||||
asyncUploadPersistentBuffer: 1
|
||||
resolutionScalingFixedDPIFactor: 1
|
||||
excludedTargetPlatforms: []
|
||||
- serializedVersion: 2
|
||||
name: Ultra
|
||||
pixelLightCount: 4
|
||||
shadows: 2
|
||||
shadowResolution: 2
|
||||
shadowProjection: 1
|
||||
shadowCascades: 4
|
||||
shadowDistance: 150
|
||||
shadowNearPlaneOffset: 3
|
||||
shadowCascade2Split: 0.33333334
|
||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||
shadowmaskMode: 1
|
||||
blendWeights: 4
|
||||
textureQuality: 0
|
||||
anisotropicTextures: 2
|
||||
antiAliasing: 2
|
||||
softParticles: 1
|
||||
softVegetation: 1
|
||||
realtimeReflectionProbes: 1
|
||||
billboardsFaceCameraPosition: 1
|
||||
vSyncCount: 1
|
||||
lodBias: 2
|
||||
maximumLODLevel: 0
|
||||
streamingMipmapsActive: 0
|
||||
streamingMipmapsAddAllCameras: 1
|
||||
streamingMipmapsMemoryBudget: 512
|
||||
streamingMipmapsRenderersPerFrame: 512
|
||||
streamingMipmapsMaxLevelReduction: 2
|
||||
streamingMipmapsMaxFileIORequests: 1024
|
||||
particleRaycastBudget: 4096
|
||||
asyncUploadTimeSlice: 2
|
||||
asyncUploadBufferSize: 16
|
||||
asyncUploadPersistentBuffer: 1
|
||||
resolutionScalingFixedDPIFactor: 1
|
||||
excludedTargetPlatforms: []
|
||||
m_PerPlatformDefaultQuality:
|
||||
Android: 2
|
||||
Lumin: 5
|
||||
GameCoreScarlett: 5
|
||||
GameCoreXboxOne: 5
|
||||
Nintendo 3DS: 5
|
||||
Nintendo Switch: 5
|
||||
PS4: 5
|
||||
PS5: 5
|
||||
Stadia: 5
|
||||
Standalone: 5
|
||||
WebGL: 3
|
||||
Windows Store Apps: 5
|
||||
XboxOne: 5
|
||||
iPhone: 2
|
||||
tvOS: 2
|
||||
@ -1,121 +0,0 @@
|
||||
{
|
||||
"templatePinStates": [],
|
||||
"dependencyTypeInfos": [
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.AnimationClip",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEditor.Animations.AnimatorController",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.AnimatorOverrideController",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEditor.Audio.AudioMixerController",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.ComputeShader",
|
||||
"defaultInstantiationMode": 1
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Cubemap",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.GameObject",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEditor.LightingDataAsset",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.LightingSettings",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Material",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEditor.MonoScript",
|
||||
"defaultInstantiationMode": 1
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.PhysicMaterial",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.PhysicsMaterial2D",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Rendering.PostProcessing.PostProcessResources",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Rendering.VolumeProfile",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEditor.SceneAsset",
|
||||
"defaultInstantiationMode": 1
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Shader",
|
||||
"defaultInstantiationMode": 1
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.ShaderVariantCollection",
|
||||
"defaultInstantiationMode": 1
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Texture",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Texture2D",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.Timeline.TimelineAsset",
|
||||
"defaultInstantiationMode": 0
|
||||
}
|
||||
],
|
||||
"defaultDependencyTypeInfo": {
|
||||
"userAdded": false,
|
||||
"type": "<default_scene_template_dependencies>",
|
||||
"defaultInstantiationMode": 1
|
||||
},
|
||||
"newSceneOverride": 0
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!78 &1
|
||||
TagManager:
|
||||
serializedVersion: 2
|
||||
tags: []
|
||||
layers:
|
||||
- Default
|
||||
- TransparentFX
|
||||
- Ignore Raycast
|
||||
-
|
||||
- Water
|
||||
- UI
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
m_SortingLayers:
|
||||
- name: Default
|
||||
uniqueID: 0
|
||||
locked: 0
|
||||
@ -1,9 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!5 &1
|
||||
TimeManager:
|
||||
m_ObjectHideFlags: 0
|
||||
Fixed Timestep: 0.02
|
||||
Maximum Allowed Timestep: 0.33333334
|
||||
m_TimeScale: 1
|
||||
Maximum Particle Timestep: 0.03
|
||||
@ -1,36 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!310 &1
|
||||
UnityConnectSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 1
|
||||
m_Enabled: 0
|
||||
m_TestMode: 0
|
||||
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
|
||||
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
|
||||
m_ConfigUrl: https://config.uca.cloud.unity3d.com
|
||||
m_DashboardUrl: https://dashboard.unity3d.com
|
||||
m_TestInitMode: 0
|
||||
CrashReportingSettings:
|
||||
m_EventUrl: https://perf-events.cloud.unity3d.com
|
||||
m_Enabled: 0
|
||||
m_LogBufferSize: 10
|
||||
m_CaptureEditorExceptions: 1
|
||||
UnityPurchasingSettings:
|
||||
m_Enabled: 0
|
||||
m_TestMode: 0
|
||||
UnityAnalyticsSettings:
|
||||
m_Enabled: 0
|
||||
m_TestMode: 0
|
||||
m_InitializeOnStartup: 1
|
||||
m_PackageRequiringCoreStatsPresent: 0
|
||||
UnityAdsSettings:
|
||||
m_Enabled: 0
|
||||
m_InitializeOnStartup: 1
|
||||
m_TestMode: 0
|
||||
m_IosGameId:
|
||||
m_AndroidGameId:
|
||||
m_GameIds: {}
|
||||
m_GameId:
|
||||
PerformanceReportingSettings:
|
||||
m_Enabled: 0
|
||||
@ -1,12 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!937362698 &1
|
||||
VFXManager:
|
||||
m_ObjectHideFlags: 0
|
||||
m_IndirectShader: {fileID: 0}
|
||||
m_CopyBufferShader: {fileID: 0}
|
||||
m_SortShader: {fileID: 0}
|
||||
m_StripUpdateShader: {fileID: 0}
|
||||
m_RenderPipeSettingsPath:
|
||||
m_FixedTimeStep: 0.016666668
|
||||
m_MaxDeltaTime: 0.05
|
||||
@ -1,8 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!890905787 &1
|
||||
VersionControlSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Mode: Visible Meta Files
|
||||
m_CollabEditorSettings:
|
||||
inProgressEnabled: 1
|
||||
@ -1,10 +0,0 @@
|
||||
{
|
||||
"m_SettingKeys": [
|
||||
"VR Device Disabled",
|
||||
"VR Device User Alert"
|
||||
],
|
||||
"m_SettingValues": [
|
||||
"False",
|
||||
"False"
|
||||
]
|
||||
}
|
||||
156
功能实现总结.md
156
功能实现总结.md
@ -1,156 +0,0 @@
|
||||
# 功能实现完成 - 总结报告
|
||||
|
||||
## 实现的功能
|
||||
|
||||
### ✅ 1. Debugger显示状态查询
|
||||
|
||||
新增方法:`UniversalDebugTool.IsDebuggerVisible()`
|
||||
|
||||
**用途**:
|
||||
- 返回bool值,表示Debugger是否正在显示
|
||||
- 用于判断主窗口或悬浮按钮是否可见
|
||||
|
||||
**代码位置**:
|
||||
- [UniversalDebugTool.cs](Packages/com.bywaystudios.meowmentdebugtool/Runtime/UniversalDebugTool.cs#L719-L732)
|
||||
|
||||
**使用示例**:
|
||||
```csharp
|
||||
bool isVisible = UniversalDebugTool.IsDebuggerVisible();
|
||||
Debug.Log($"Debugger显示状态: {isVisible}");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ✅ 2. 按钮分组功能
|
||||
|
||||
**改动内容**:
|
||||
|
||||
1. **特性修改** - `DebugButtonAttribute`
|
||||
- 新增 `GroupName` 属性
|
||||
- 构造函数第一个参数改为组名
|
||||
- 默认组名为"默认"
|
||||
|
||||
2. **模块重构** - `CustomButtonsModule`
|
||||
- 添加分组数据结构
|
||||
- 自动创建分组切换UI容器
|
||||
- 实现按组加载和显示按钮
|
||||
- 添加组切换视觉反馈
|
||||
|
||||
**使用方式**:
|
||||
```csharp
|
||||
#if MEOWMENT_DEBUG_TOOL
|
||||
[MeowmentDebugTool.UniversalDebugTool.DebugButton("玩家", "加金币")]
|
||||
public static void AddGold()
|
||||
{
|
||||
Debug.Log("加金币");
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
**功能特点**:
|
||||
- ✨ 自动分组:根据特性中的组名自动分类
|
||||
- 🎨 UI优化:顶部显示组切换按钮
|
||||
- 🔄 智能排序:"默认"组排在最前
|
||||
- 🎯 视觉反馈:当前组显示为绿色
|
||||
|
||||
---
|
||||
|
||||
## 文件修改清单
|
||||
|
||||
### 修改的文件
|
||||
1. ✏️ [UniversalDebugTool.cs](Packages/com.bywaystudios.meowmentdebugtool/Runtime/UniversalDebugTool.cs)
|
||||
- 添加 `IsDebuggerVisible()` 方法
|
||||
- 修改 `DebugButtonAttribute` 构造函数
|
||||
|
||||
2. ✏️ [CustomButtonsModule.cs](Packages/com.bywaystudios.meowmentdebugtool/Runtime/CustomButtonsModule.cs)
|
||||
- 完全重构以支持分组功能
|
||||
- 添加分组数据结构和UI逻辑
|
||||
|
||||
3. ✏️ [Test.cs](Assets/Scenes/Scripts/Test.cs)
|
||||
- 添加使用示例代码
|
||||
- 展示如何使用新的分组功能
|
||||
|
||||
### 新增的文件
|
||||
1. 📄 [新功能说明.md](新功能说明.md)
|
||||
- 详细的功能使用文档
|
||||
- 包含示例代码和注意事项
|
||||
|
||||
2. 📄 [功能实现总结.md](功能实现总结.md)
|
||||
- 本文件,快速查看实现内容
|
||||
|
||||
---
|
||||
|
||||
## 重要提示
|
||||
|
||||
### ⚠️ 破坏性更新
|
||||
|
||||
`DebugButton` 特性的参数顺序已改变:
|
||||
|
||||
**旧代码** ❌:
|
||||
```csharp
|
||||
[DebugButton("按钮名")]
|
||||
```
|
||||
|
||||
**新代码** ✅:
|
||||
```csharp
|
||||
[MeowmentDebugTool.UniversalDebugTool.DebugButton("默认", "按钮名")]
|
||||
```
|
||||
|
||||
### 🔧 迁移指南
|
||||
|
||||
如果有旧代码,需要:
|
||||
1. 在所有 `DebugButton` 特性前添加组名参数
|
||||
2. 使用完整的命名空间路径 `MeowmentDebugTool.UniversalDebugTool.DebugButton`
|
||||
3. 建议使用 `#if MEOWMENT_DEBUG_TOOL` 条件编译
|
||||
|
||||
---
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **基础功能测试**:
|
||||
- 调用 `IsDebuggerVisible()` 测试返回值
|
||||
- 尝试 Show/Hide 后检查状态
|
||||
|
||||
2. **分组功能测试**:
|
||||
- 创建多个不同组的按钮
|
||||
- 测试组切换是否正常
|
||||
- 验证按钮是否正确归类
|
||||
|
||||
3. **兼容性测试**:
|
||||
- 测试没有组名的按钮(应归入"默认"组)
|
||||
- 测试只有一个组的情况
|
||||
- 测试大量按钮的性能
|
||||
|
||||
---
|
||||
|
||||
## 已知问题
|
||||
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **可配置性**:
|
||||
- 允许自定义分组按钮颜色
|
||||
- 允许自定义分组容器高度
|
||||
|
||||
2. **功能增强**:
|
||||
- 支持搜索/过滤按钮
|
||||
- 支持收藏常用按钮
|
||||
- 支持按钮排序
|
||||
|
||||
3. **UI改进**:
|
||||
- 更好的分组按钮布局(可滚动)
|
||||
- 添加分组图标支持
|
||||
|
||||
---
|
||||
|
||||
## 联系方式
|
||||
|
||||
如有问题或建议,请联系开发者。
|
||||
|
||||
---
|
||||
|
||||
**完成日期**:2025年12月30日
|
||||
**版本**:v1.1.0
|
||||
148
拖动功能问题修复说明.md
148
拖动功能问题修复说明.md
@ -1,148 +0,0 @@
|
||||
# 拖动功能问题修复说明
|
||||
|
||||
## 问题描述
|
||||
禁用调试工具的拖动功能后(`enableDragging = false`),发现其他UI上的棋子也无法拖动了。
|
||||
|
||||
## 问题原因
|
||||
|
||||
### Unity事件系统机制
|
||||
在Unity的事件系统中,当一个GameObject实现了拖动接口(`IBeginDragHandler`, `IDragHandler`, `IEndDragHandler`)时:
|
||||
|
||||
1. **事件会被该对象"拦截"**:即使在方法内部直接 `return`,Unity也认为该对象已经处理了事件
|
||||
2. **事件不会继续传递**:被拦截的事件不会传递给下层或其他UI元素
|
||||
3. **影响范围广泛**:这会导致场景中所有在该对象下方的可拖动UI元素都无法接收拖动事件
|
||||
|
||||
### 之前的实现问题
|
||||
```csharp
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!enableDragging) return; // ❌ 直接返回,但事件已被拦截
|
||||
// ... 正常的拖动逻辑
|
||||
}
|
||||
```
|
||||
|
||||
这种实现方式会导致:
|
||||
- 调试工具的悬浮按钮拦截了所有拖动事件
|
||||
- 其他UI元素(如棋子)无法接收到拖动事件
|
||||
- 即使 `enableDragging = false`,问题依然存在
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 核心思路
|
||||
当 `enableDragging = false` 时,不应该简单地返回,而是应该将事件**主动传递**给其他可以处理该事件的UI元素。
|
||||
|
||||
### 实现细节
|
||||
|
||||
#### 1. 修改拖动事件处理方法
|
||||
在 `OnBeginDrag`, `OnDrag`, `OnEndDrag` 中添加事件传递逻辑:
|
||||
|
||||
```csharp
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!enableDragging)
|
||||
{
|
||||
// ✅ 将事件传递给父级或下层UI元素
|
||||
PassEventToParent(eventData, ExecuteEvents.beginDragHandler);
|
||||
return;
|
||||
}
|
||||
// ... 正常的拖动逻辑
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 实现事件传递方法
|
||||
添加 `PassEventToParent` 方法,按以下顺序尝试传递事件:
|
||||
|
||||
```csharp
|
||||
private void PassEventToParent<T>(PointerEventData eventData, ExecuteEvents.EventFunction<T> eventFunction)
|
||||
where T : IEventSystemHandler
|
||||
{
|
||||
// 步骤1: 向上传递给父级对象
|
||||
Transform parent = transform.parent;
|
||||
while (parent != null)
|
||||
{
|
||||
if (ExecuteEvents.Execute(parent.gameObject, eventData, eventFunction))
|
||||
{
|
||||
return; // 父级处理了,停止传递
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
// 步骤2: 如果父级都没处理,传递给射线检测到的下一个对象
|
||||
var raycastResults = new List<RaycastResult>();
|
||||
EventSystem.current.RaycastAll(eventData, raycastResults);
|
||||
|
||||
foreach (var result in raycastResults)
|
||||
{
|
||||
if (result.gameObject == gameObject)
|
||||
continue; // 跳过自己
|
||||
|
||||
if (ExecuteEvents.Execute(result.gameObject, eventData, eventFunction))
|
||||
{
|
||||
return; // 下层对象处理了,停止传递
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 工作原理
|
||||
|
||||
1. **事件拦截**:悬浮按钮首先接收到拖动事件
|
||||
2. **条件判断**:检查 `enableDragging` 是否为 `false`
|
||||
3. **向上传递**:尝试将事件传递给父级对象树
|
||||
4. **射线检测**:如果父级未处理,通过射线检测找到下层UI元素
|
||||
5. **事件执行**:让找到的对象执行相应的拖动事件处理
|
||||
|
||||
## 修改文件
|
||||
- `Packages/com.bywaystudios.meowmentdebugtool/Runtime/DraggableFloatingButton.cs`
|
||||
- 修改 `OnBeginDrag` 方法
|
||||
- 修改 `OnDrag` 方法
|
||||
- 修改 `OnEndDrag` 方法
|
||||
- 新增 `PassEventToParent` 方法
|
||||
|
||||
## 测试建议
|
||||
|
||||
### 测试场景1:禁用拖动模式
|
||||
1. 设置 `enableDragging = false`
|
||||
2. 点击悬浮按钮 → 应该正常打开调试窗口
|
||||
3. 尝试拖动其他UI上的棋子 → **应该能够正常拖动**
|
||||
|
||||
### 测试场景2:启用拖动模式
|
||||
1. 设置 `enableDragging = true`
|
||||
2. 拖动悬浮按钮 → 应该能够正常拖动
|
||||
3. 点击悬浮按钮(不拖动)→ 应该打开调试窗口
|
||||
|
||||
### 测试场景3:多层UI叠加
|
||||
1. 创建多个可拖动的UI元素,部分重叠
|
||||
2. 确保悬浮按钮在最上层
|
||||
3. 禁用悬浮按钮拖动后,测试下层UI元素能否正常拖动
|
||||
|
||||
## 技术要点
|
||||
|
||||
### Unity事件传递机制
|
||||
- `ExecuteEvents.Execute()`:手动触发事件处理
|
||||
- `EventSystem.RaycastAll()`:获取所有被射线击中的UI元素
|
||||
- 事件处理器接口:`IEventSystemHandler`
|
||||
|
||||
### 泛型约束
|
||||
使用泛型方法支持不同类型的事件处理:
|
||||
```csharp
|
||||
private void PassEventToParent<T>(...) where T : IEventSystemHandler
|
||||
```
|
||||
|
||||
### 事件类型
|
||||
- `ExecuteEvents.beginDragHandler` - 开始拖动
|
||||
- `ExecuteEvents.dragHandler` - 拖动中
|
||||
- `ExecuteEvents.endDragHandler` - 结束拖动
|
||||
|
||||
## 可能的副作用
|
||||
|
||||
### 性能考虑
|
||||
- `RaycastAll` 会执行完整的射线检测,可能有轻微性能开销
|
||||
- 仅在 `enableDragging = false` 时触发,实际影响很小
|
||||
|
||||
### 兼容性
|
||||
- 需要确保场景中有 `EventSystem`
|
||||
- 依赖 Unity 的 EventSystem 模块
|
||||
|
||||
## 总结
|
||||
通过主动传递事件而不是简单地忽略事件,解决了禁用拖动后影响其他UI元素的问题。这是一个典型的UI事件系统问题,需要理解Unity的事件传递机制才能正确处理。
|
||||
233
新功能说明.md
233
新功能说明.md
@ -1,233 +0,0 @@
|
||||
# MeowmentDebugTool 新功能说明
|
||||
|
||||
## 更新日期
|
||||
2025年12月30日
|
||||
|
||||
## 新增功能
|
||||
|
||||
### 1. 获取Debugger显示状态
|
||||
|
||||
新增了一个公共静态方法 `IsDebuggerVisible()`,用于获取Debugger的当前显示状态。
|
||||
|
||||
#### 使用方法
|
||||
|
||||
```csharp
|
||||
// 获取Debugger是否正在显示
|
||||
bool isVisible = UniversalDebugTool.IsDebuggerVisible();
|
||||
|
||||
if (isVisible)
|
||||
{
|
||||
Debug.Log("Debugger正在显示");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("Debugger已隐藏或未初始化");
|
||||
}
|
||||
```
|
||||
|
||||
#### 方法说明
|
||||
|
||||
- **方法签名**: `public static bool IsDebuggerVisible()`
|
||||
- **返回值**:
|
||||
- `true` - Debugger正在显示(主窗口或悬浮按钮可见)
|
||||
- `false` - Debugger完全隐藏或未初始化
|
||||
- **使用场景**:
|
||||
- 判断是否需要显示/隐藏Debugger
|
||||
- 根据Debugger状态执行不同的逻辑
|
||||
- 在截图或录屏前检查Debugger状态
|
||||
|
||||
---
|
||||
|
||||
### 2. 按钮分组功能
|
||||
|
||||
为调试按钮添加了分组功能,可以将按钮按功能分类显示,提高大量按钮时的使用体验。
|
||||
|
||||
#### 使用方法
|
||||
|
||||
在使用 `DebugButton` 特性时,在第一个参数指定组名:
|
||||
|
||||
```csharp
|
||||
using MeowmentDebugTool;
|
||||
|
||||
#if MEOWMENT_DEBUG_TOOL
|
||||
// 默认组
|
||||
[DebugButton("默认", "我的按钮")]
|
||||
public static void MyButton()
|
||||
{
|
||||
Debug.Log("按钮被点击");
|
||||
}
|
||||
|
||||
// 玩家相关按钮
|
||||
[DebugButton("玩家", "加金币")]
|
||||
public static void AddGold()
|
||||
{
|
||||
Debug.Log("给玩家加了1000金币");
|
||||
}
|
||||
|
||||
[DebugButton("玩家", "升级")]
|
||||
public static void LevelUp()
|
||||
{
|
||||
Debug.Log("玩家升了1级");
|
||||
}
|
||||
|
||||
// 关卡相关按钮
|
||||
[DebugButton("关卡", "跳过当前关卡")]
|
||||
public static void SkipLevel()
|
||||
{
|
||||
Debug.Log("跳过当前关卡");
|
||||
}
|
||||
|
||||
[DebugButton("关卡", "解锁所有关卡", 0.8f, 0.6f, 0.2f)]
|
||||
public static void UnlockAllLevels()
|
||||
{
|
||||
Debug.Log("解锁所有关卡");
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
**注意**:确保在文件顶部添加 `using MeowmentDebugTool;` 以便可以直接使用 `DebugButton` 特性。
|
||||
|
||||
#### 特性参数说明
|
||||
|
||||
`DebugButton` 特性的新参数顺序:
|
||||
|
||||
```csharp
|
||||
DebugButtonAttribute(
|
||||
string groupName = "默认", // 组名(新增)
|
||||
string displayName = "", // 显示名称
|
||||
float r = 0.8f, // 按钮颜色 R
|
||||
float g = 0.8f, // 按钮颜色 G
|
||||
float b = 0.8f // 按钮颜色 B
|
||||
)
|
||||
```
|
||||
|
||||
#### 功能特点
|
||||
|
||||
1. **自动分组**: 系统会自动收集所有带有 `DebugButton` 特性的方法,并按组名分类
|
||||
2. **组标题显示**: 每个组会显示一个标题行,标题格式为:`━━━━━━ 组名 ━━━━━━`
|
||||
3. **默认组**: 如果不指定组名或组名为空,按钮会被归入"默认"组
|
||||
4. **组排序**: "默认"组会排在最前面,其他组按字母顺序排列
|
||||
5. **一次显示所有**: 所有组的按钮会在一个滚动视图中垂直显示,无需切换
|
||||
|
||||
#### 界面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ ━━━━━━ 默认 ━━━━━━ │ ← 组标题
|
||||
│ [测试按钮1] │
|
||||
│ [测试按钮2] │ ← 该组的按钮
|
||||
│ │
|
||||
│ ━━━━━━ 玩家 ━━━━━━ │ ← 组标题
|
||||
│ [加金币] │
|
||||
│ [升级] │
|
||||
│ [满血复活] │ ← 该组的按钮
|
||||
│ │
|
||||
│ ━━━━━━ 关卡 ━━━━━━ │ ← 组标题
|
||||
│ [跳过当前关卡] │
|
||||
│ [重置关卡进度] │
|
||||
│ [解锁所有关卡] │ ← 该组的按钮
|
||||
│ ... │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 注意事项
|
||||
|
||||
1. **兼容性**: 这是一个破坏性更新,旧代码需要调整参数顺序
|
||||
|
||||
**旧代码**:
|
||||
```csharp
|
||||
[DebugButton("按钮名称")]
|
||||
```
|
||||
|
||||
**新代码** (需要添加组名):
|
||||
```csharp
|
||||
[DebugButton("默认", "按钮名称")]
|
||||
```
|
||||
|
||||
2. **组名建议**:
|
||||
- 使用简短明确的组名(如:玩家、关卡、道具、系统等)
|
||||
- 相关功能的按钮放在同一组
|
||||
- 常用功能建议放在"默认"组
|
||||
|
||||
3. **性能**: 分组功能不会影响性能,因为:
|
||||
- 只在初始化和手动重载时扫描方法
|
||||
- 所有按钮一次性创建,无需动态切换
|
||||
|
||||
---
|
||||
|
||||
## 示例代码
|
||||
|
||||
完整的使用示例请参考 `Assets/Scenes/Scripts/Test.cs` 文件。
|
||||
|
||||
## 向后兼容性说明
|
||||
|
||||
⚠️ **重要**: `DebugButton` 特性的参数顺序已更改,旧代码需要手动调整。
|
||||
|
||||
如果你之前这样使用:
|
||||
```csharp
|
||||
[DebugButton("我的按钮", 0.5f, 0.5f, 0.5f)]
|
||||
```
|
||||
|
||||
现在需要改为:
|
||||
```csharp
|
||||
[DebugButton("默认", "我的按钮", 0.5f, 0.5f, 0.5f)]
|
||||
```
|
||||
|
||||
或者如果不需要自定义颜色:
|
||||
```csharp
|
||||
[DebugButton("默认", "我的按钮")]
|
||||
```
|
||||
|
||||
**注意**:请确保在文件顶部添加 `using MeowmentDebugTool;`
|
||||
|
||||
---
|
||||
|
||||
## 技术细节
|
||||
|
||||
### CustomButtonsModule 的改动
|
||||
|
||||
1. 添加了分组数据结构 `Dictionary<string, List<ButtonInfo>>`
|
||||
2. 添加了分组UI容器的自动创建逻辑
|
||||
3. 修改了按钮加载流程,先分组再显示
|
||||
4. 添加了组切换功能和视觉反馈
|
||||
|
||||
### UniversalDebugTool 的改动
|
||||
|
||||
1. 添加了 `IsDebuggerVisible()` 方法
|
||||
2. 修改了 `DebugButtonAttribute` 的构造函数,添加了 `groupName` 参数
|
||||
3. 更新了文档注释
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 如何知道当前有哪些组?
|
||||
A: 在初始化时,控制台会输出所有找到的组及其按钮数量:
|
||||
```
|
||||
[CustomButtonsModule] 共找到 3 个按钮组
|
||||
- 默认: 2 个按钮
|
||||
- 玩家: 3 个按钮
|
||||
- 关卡: 3 个按钮
|
||||
```
|
||||
|
||||
### Q: 能否动态添加组?
|
||||
A: 可以,调用 `ReloadCustomButtons()` 方法即可重新扫描所有按钮并更新分组。
|
||||
|
||||
### Q: 分组按钮的样式可以自定义吗?
|
||||
A: 可以,分组按钮使用与普通按钮相同的预制件,可以通过修改预制件来自定义样式。
|
||||
|
||||
### Q: IsDebuggerVisible() 什么情况下返回 false?
|
||||
A: 以下情况会返回 false:
|
||||
- Debugger 未初始化(未调用 `Init()`)
|
||||
- 主窗口和悬浮按钮都被隐藏
|
||||
- Debugger GameObject 被销毁
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.1.0 (2025-12-30)
|
||||
- ✨ 新增 `IsDebuggerVisible()` 方法用于获取显示状态
|
||||
- ✨ 新增按钮分组功能
|
||||
- 🔧 修改 `DebugButtonAttribute` 构造函数参数顺序(破坏性更新)
|
||||
- 📝 更新文档和示例代码
|
||||
Loading…
Reference in New Issue
Block a user