更新框架
This commit is contained in:
parent
db745820e8
commit
435ccea285
15
Client/Assets/Art/Atlas/Atlas_Common_bb.spriteatlasv2
Normal file
15
Client/Assets/Art/Atlas/Atlas_Common_bb.spriteatlasv2
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!612988286 &1
|
||||||
|
SpriteAtlasAsset:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_MasterAtlas: {fileID: 0}
|
||||||
|
m_ImporterData:
|
||||||
|
packables:
|
||||||
|
- {fileID: 21300000, guid: 5fe20064a619ceb4aacf49802ee4f70e, type: 3}
|
||||||
|
m_IsVariant: 0
|
||||||
69
Client/Assets/Art/Atlas/Atlas_Common_bb.spriteatlasv2.meta
Normal file
69
Client/Assets/Art/Atlas/Atlas_Common_bb.spriteatlasv2.meta
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dc412ce8a0c03474dbc19475ebe3791a
|
||||||
|
SpriteAtlasImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
anisoLevel: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureCompression: 0
|
||||||
|
filterMode: 1
|
||||||
|
generateMipMaps: 0
|
||||||
|
readable: 0
|
||||||
|
crunchedCompression: 0
|
||||||
|
sRGB: 1
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: Android
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: 50
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 1
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: iPhone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: 49
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 1
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: WebGL
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: 50
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 1
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
packingSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
padding: 4
|
||||||
|
blockOffset: 1
|
||||||
|
allowAlphaSplitting: 0
|
||||||
|
enableRotation: 0
|
||||||
|
enableTightPacking: 1
|
||||||
|
enableAlphaDilation: 1
|
||||||
|
secondaryTextureSettings: {}
|
||||||
|
variantMultiplier: 1
|
||||||
|
bindAsDefault: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
120
Client/Assets/AudioGroupConfigs.asset
Normal file
120
Client/Assets/AudioGroupConfigs.asset
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
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: 11500000, guid: 35a9ab9e2f42f744ca3801948d9b8c2e, type: 3}
|
||||||
|
m_Name: AudioGroupConfigs
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_GroupConfigs:
|
||||||
|
- m_Name: "\u97F3\u6548"
|
||||||
|
m_Mute: 0
|
||||||
|
m_Volume: 1
|
||||||
|
m_AgentHelperCount: 4
|
||||||
|
m_ExposedVolumeParameter: SoundVolume
|
||||||
|
m_SpatialBlend: 1
|
||||||
|
m_DopplerLevel: 1
|
||||||
|
m_Spread: 0
|
||||||
|
m_SourcePriority: 128
|
||||||
|
m_ReverbZoneMix: 1
|
||||||
|
m_OcclusionEnabled: 0
|
||||||
|
m_OcclusionMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_OcclusionCheckInterval: 0.12
|
||||||
|
m_OcclusionLowPassCutoff: 1200
|
||||||
|
m_OcclusionVolumeMultiplier: 0.55
|
||||||
|
AudioType: 0
|
||||||
|
audioRolloffMode: 0
|
||||||
|
minDistance: 2
|
||||||
|
maxDistance: 80
|
||||||
|
- m_Name: "\u754C\u9762\u97F3\u6548"
|
||||||
|
m_Mute: 0
|
||||||
|
m_Volume: 1
|
||||||
|
m_AgentHelperCount: 12
|
||||||
|
m_ExposedVolumeParameter: UISoundVolume
|
||||||
|
m_SpatialBlend: 0
|
||||||
|
m_DopplerLevel: 1
|
||||||
|
m_Spread: 0
|
||||||
|
m_SourcePriority: 128
|
||||||
|
m_ReverbZoneMix: 1
|
||||||
|
m_OcclusionEnabled: 0
|
||||||
|
m_OcclusionMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_OcclusionCheckInterval: 0.12
|
||||||
|
m_OcclusionLowPassCutoff: 1200
|
||||||
|
m_OcclusionVolumeMultiplier: 0.55
|
||||||
|
AudioType: 1
|
||||||
|
audioRolloffMode: 0
|
||||||
|
minDistance: 1
|
||||||
|
maxDistance: 25
|
||||||
|
- m_Name: "\u97F3\u4E50"
|
||||||
|
m_Mute: 0
|
||||||
|
m_Volume: 1
|
||||||
|
m_AgentHelperCount: 1
|
||||||
|
m_ExposedVolumeParameter: MusicVolume
|
||||||
|
m_SpatialBlend: 0
|
||||||
|
m_DopplerLevel: 1
|
||||||
|
m_Spread: 0
|
||||||
|
m_SourcePriority: 32
|
||||||
|
m_ReverbZoneMix: 1
|
||||||
|
m_OcclusionEnabled: 0
|
||||||
|
m_OcclusionMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_OcclusionCheckInterval: 0.12
|
||||||
|
m_OcclusionLowPassCutoff: 1200
|
||||||
|
m_OcclusionVolumeMultiplier: 0.55
|
||||||
|
AudioType: 2
|
||||||
|
audioRolloffMode: 0
|
||||||
|
minDistance: 1
|
||||||
|
maxDistance: 25
|
||||||
|
- m_Name: "\u8BED\u97F3"
|
||||||
|
m_Mute: 0
|
||||||
|
m_Volume: 1
|
||||||
|
m_AgentHelperCount: 6
|
||||||
|
m_ExposedVolumeParameter: VoiceVolume
|
||||||
|
m_SpatialBlend: 1
|
||||||
|
m_DopplerLevel: 1
|
||||||
|
m_Spread: 0
|
||||||
|
m_SourcePriority: 128
|
||||||
|
m_ReverbZoneMix: 1
|
||||||
|
m_OcclusionEnabled: 1
|
||||||
|
m_OcclusionMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_OcclusionCheckInterval: 0.12
|
||||||
|
m_OcclusionLowPassCutoff: 1200
|
||||||
|
m_OcclusionVolumeMultiplier: 0.55
|
||||||
|
AudioType: 3
|
||||||
|
audioRolloffMode: 0
|
||||||
|
minDistance: 2
|
||||||
|
maxDistance: 80
|
||||||
|
- m_Name: "\u73AF\u5883\u97F3"
|
||||||
|
m_Mute: 0
|
||||||
|
m_Volume: 1
|
||||||
|
m_AgentHelperCount: 6
|
||||||
|
m_ExposedVolumeParameter: AmbientVolume
|
||||||
|
m_SpatialBlend: 1
|
||||||
|
m_DopplerLevel: 1
|
||||||
|
m_Spread: 0
|
||||||
|
m_SourcePriority: 128
|
||||||
|
m_ReverbZoneMix: 1
|
||||||
|
m_OcclusionEnabled: 1
|
||||||
|
m_OcclusionMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_OcclusionCheckInterval: 0.12
|
||||||
|
m_OcclusionLowPassCutoff: 1200
|
||||||
|
m_OcclusionVolumeMultiplier: 0.55
|
||||||
|
AudioType: 4
|
||||||
|
audioRolloffMode: 0
|
||||||
|
minDistance: 2
|
||||||
|
maxDistance: 80
|
||||||
@ -1,7 +1,8 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3cd21cd1bc02c44449bf7b999ae7bdd4
|
guid: 7ae4699f0778d2441907aeccaf6c9b29
|
||||||
TextScriptImporter:
|
NativeFormatImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
@ -1,83 +0,0 @@
|
|||||||
# EditorExtension Atlas 自动图集模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
该模块位于 `Editor/Postprocessor/Atlas`,用于维护图集配置、响应 Sprite 导入/删除、标记脏图集并执行全量生成。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 以目录为单位自动生成 UI 图集。
|
|
||||||
- 不同平台使用不同压缩格式。
|
|
||||||
- 导入资源时自动更新图集状态。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
### 打开配置窗口
|
|
||||||
- 菜单:`Tools/Extension/图集工具/Configuration Panel`
|
|
||||||
|
|
||||||
### 全量生成
|
|
||||||
```csharp
|
|
||||||
EditorSpriteSaveInfo.ForceGenerateAll();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 模块组成
|
|
||||||
- `AtlasConfiguration`:图集配置单例。
|
|
||||||
- `AtlasConfigWindow`:配置窗口。
|
|
||||||
- `EditorSpriteSaveInfo`:缓存、脏标记、全量生成。
|
|
||||||
- `SpritePostprocessor`:接入 Unity 导入流程。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`AtlasConfiguration`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/Postprocessor/Atlas/AtlasConfiguration.cs`
|
|
||||||
|
|
||||||
#### 公开配置字段
|
|
||||||
- `outputAtlasDir`
|
|
||||||
- `sourceAtlasRoot`
|
|
||||||
- `androidFormat`
|
|
||||||
- `iosFormat`
|
|
||||||
- `webglFormat`
|
|
||||||
- `padding`
|
|
||||||
- `enableRotation`
|
|
||||||
- `blockOffset`
|
|
||||||
- `tightPacking`
|
|
||||||
- `compressionQuality`
|
|
||||||
- `autoGenerate`
|
|
||||||
- `enableLogging`
|
|
||||||
- `enableV2`
|
|
||||||
- `excludeKeywords`
|
|
||||||
- `excludeFolders`
|
|
||||||
|
|
||||||
示例:
|
|
||||||
```csharp
|
|
||||||
AtlasConfiguration.Instance.autoGenerate = true;
|
|
||||||
AtlasConfiguration.Save(true);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 类型:`AtlasConfigWindow`
|
|
||||||
#### `public static void ShowWindow()`
|
|
||||||
- 作用:打开图集配置窗口。
|
|
||||||
|
|
||||||
### 类型:`EditorSpriteSaveInfo`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/Postprocessor/Atlas/EditorSpriteSaveInfo.cs`
|
|
||||||
|
|
||||||
#### `public static void ConvertToSprite(string assetPath)`
|
|
||||||
- 作用:把资源路径转换或校正为 Sprite 导入设置。
|
|
||||||
|
|
||||||
#### `public static void OnImportSprite(string assetPath)`
|
|
||||||
- 作用:处理 Sprite 导入。
|
|
||||||
|
|
||||||
#### `public static void OnDeleteSprite(string assetPath)`
|
|
||||||
- 作用:处理 Sprite 删除。
|
|
||||||
|
|
||||||
#### `public static void ForceGenerateAll()`
|
|
||||||
- 作用:全量生成图集。
|
|
||||||
|
|
||||||
#### `public static void ClearCache()`
|
|
||||||
- 作用:清理模块缓存。
|
|
||||||
|
|
||||||
#### `public static void MarkParentAtlasesDirty(string assetPath)`
|
|
||||||
- 作用:标记资源所在父图集为脏。
|
|
||||||
|
|
||||||
### 类型:`SpritePostprocessor`
|
|
||||||
- 说明:继承 `AssetPostprocessor`,作为导入事件入口,本身无额外公开调用接口。
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
- 建议原图目录与输出目录严格分离。
|
|
||||||
- 开启自动生成时,排除目录和关键字要统一维护。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: edc716e06a048f240a9f9bda8ff156ce
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
# EditorExtension 基础工具模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
基础工具模块由 `EditorIcons` 和 `EditorToolFunctionAttribute` 两部分组成:
|
|
||||||
- `EditorIcons`:浏览、检索、预览并导出 Unity 内置编辑器图标。
|
|
||||||
- `EditorToolFunctionAttribute`:把静态方法声明为“编辑器快捷工具”,供 `EditorQuickToolBar` 自动收集。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 快速查找 Unity 内置图标。
|
|
||||||
- 将团队常用编辑器方法集中到工具栏菜单。
|
|
||||||
- 避免为每个工具重复创建顶级菜单。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
### 打开图标浏览器
|
|
||||||
- 菜单:`Tools/Extension/Editor Icons`
|
|
||||||
|
|
||||||
### 声明工具函数
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.Editor.Extension;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public static class DemoEditorTools
|
|
||||||
{
|
|
||||||
[EditorToolFunction("Demo/打印当前场景", 10)]
|
|
||||||
public static void PrintScene()
|
|
||||||
{
|
|
||||||
Debug.Log(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 详细使用说明
|
|
||||||
### `EditorIcons`
|
|
||||||
- 支持关键字搜索。
|
|
||||||
- 支持大小图标切换。
|
|
||||||
- 支持单个导出 PNG。
|
|
||||||
- 支持批量导出全部图标到目录。
|
|
||||||
|
|
||||||
### `EditorToolFunctionAttribute`
|
|
||||||
- 仅扫描静态方法。
|
|
||||||
- 扫描时机为编辑器加载阶段。
|
|
||||||
- 扫描结果按 `MenuOrder` 升序排列。
|
|
||||||
- 建议被标记的方法不要带参数。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`EditorIcons`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/EditorIcons.cs`
|
|
||||||
|
|
||||||
#### `public static void EditorIconsOpen()`
|
|
||||||
- 作用:打开图标浏览窗口。
|
|
||||||
- 参数:无。
|
|
||||||
- 返回值:`void`。
|
|
||||||
|
|
||||||
#### `public static string[] ico_list`
|
|
||||||
- 作用:内置图标名称列表。
|
|
||||||
- 示例:
|
|
||||||
```csharp
|
|
||||||
foreach (var iconName in EditorIcons.ico_list)
|
|
||||||
{
|
|
||||||
Debug.Log(iconName);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 类型:`AlicizaX.Editor.Extension.EditorToolFunctionAttribute`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/EditorToolFunctionAttribute.cs`
|
|
||||||
|
|
||||||
#### `public EditorToolFunctionAttribute(string menu, int menuOrder = 0)`
|
|
||||||
- 作用:声明工具菜单路径与排序值。
|
|
||||||
- 参数:
|
|
||||||
- `menu`:菜单路径。
|
|
||||||
- `menuOrder`:排序值。
|
|
||||||
|
|
||||||
#### `public string ToolMenuPath { get; }`
|
|
||||||
- 作用:获取菜单路径。
|
|
||||||
|
|
||||||
#### `public int MenuOrder { get; }`
|
|
||||||
- 作用:获取排序值。
|
|
||||||
|
|
||||||
#### `public MethodInfo MethodInfo { get; }`
|
|
||||||
- 作用:获取实际绑定的方法信息。
|
|
||||||
|
|
||||||
#### `public void SetMethodInfo(MethodInfo methodInfo)`
|
|
||||||
- 作用:由收集器在扫描时写入目标方法。
|
|
||||||
|
|
||||||
## 集成建议
|
|
||||||
- 推荐把所有项目编辑器命令统一声明为 `EditorToolFunctionAttribute`。
|
|
||||||
- 图标挑选可先通过 `EditorIcons` 查名,再用于按钮和菜单项。
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
# EditorExtension 自定义工具栏项目模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`ToolBarExtension` 目录在 `Toolbar` 框架之上实现了一组项目级工具栏元素:
|
|
||||||
- `EditorQuickToolBar`
|
|
||||||
- `LocalizationDropdownField`
|
|
||||||
- `ResourceModeDropdownField`
|
|
||||||
- `SwitchSceneToolBar`
|
|
||||||
- `BuildSettingWindow`(当前源码为注释模板)
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 快速切换语言、资源模式与场景。
|
|
||||||
- 把项目工具统一收口到主工具栏。
|
|
||||||
- 自动调度 `EditorToolFunctionAttribute` 标记的方法。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
这些类型均通过 `MainToolbarElementAttribute` 自动挂载,无需手动注册。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`AlicizaX.Editor.Extension.EditorQuickToolBar`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/ToolBarExtension/EditorQuickToolBar.cs`
|
|
||||||
- `InitializeElement()`:初始化工具下拉按钮。
|
|
||||||
|
|
||||||
### 类型:`LocalizationDropdownField`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/ToolBarExtension/LocalizationDropdownField.cs`
|
|
||||||
- `InitializeElement()`:初始化语言切换下拉框。
|
|
||||||
- `InvokeOnValidateInScene()`:强制刷新场景中所有 `UXTextMeshPro` 的编辑器预览。
|
|
||||||
|
|
||||||
### 类型:`AlicizaX.Editor.Extension.ResourceModeDropdownField`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/ToolBarExtension/ResourceModeDropdownField.cs`
|
|
||||||
- `InitializeElement()`:初始化资源模式下拉框。
|
|
||||||
|
|
||||||
### 类型:`SwitchSceneToolBar`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/ToolBarExtension/SwitchSceneToolBar.cs`
|
|
||||||
- `InitializeElement()`:初始化场景切换按钮并监听场景切换。
|
|
||||||
|
|
||||||
### 类型:`BuildSettingWindow`
|
|
||||||
- 说明:当前源码整体注释,无生效公开 API,可作为未来扩展模板。
|
|
||||||
|
|
||||||
## 详细使用说明
|
|
||||||
### `EditorQuickToolBar`
|
|
||||||
- 从 `EditorToolFunctionAttributeCollector.Attributes` 读取菜单项。
|
|
||||||
- 点击菜单后通过反射执行静态方法。
|
|
||||||
|
|
||||||
### `LocalizationDropdownField`
|
|
||||||
- 读取语言列表并写入 `EditorPrefs`。
|
|
||||||
- 切换后会刷新场景里的 `UXTextMeshPro` 文本预览。
|
|
||||||
|
|
||||||
### `ResourceModeDropdownField`
|
|
||||||
- 提供 `Editor / Offline / Host / Webgl` 四种模式。
|
|
||||||
- 模式结果通过 `EditorPrefs` 持久化。
|
|
||||||
|
|
||||||
### `SwitchSceneToolBar`
|
|
||||||
- 默认扫描 `Assets/Bundles/` 与 `Assets/Scenes/` 下的场景。
|
|
||||||
- 切换前会检查当前场景未保存状态。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 19d768fd857ab3d42887f3cddd38bf37
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
# EditorExtension HybridCLR 模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`HybridCLR` 模块封装热更新 DLL 构建、AOT 补充 DLL 复制、热更 DLL 复制与宏开关。核心入口为 `BuildDLLCommand`。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 一键编译并拷贝热更新 DLL。
|
|
||||||
- 启用/关闭 `ENABLE_HYBRIDCLR`。
|
|
||||||
- 输出 `.dll.bytes` 供运行时加载。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
### 菜单
|
|
||||||
- `HybridCLR/Tools/Define Symbols/Disable HybridCLR`
|
|
||||||
- `HybridCLR/Tools/Define Symbols/Enable HybridCLR`
|
|
||||||
- `HybridCLR/Tools/BuildAssets And CopyTo AssemblyTextAssetPath`
|
|
||||||
|
|
||||||
### 代码
|
|
||||||
```csharp
|
|
||||||
using UnityEditor;
|
|
||||||
|
|
||||||
BuildDLLCommand.Enable();
|
|
||||||
BuildDLLCommand.BuildAndCopyDlls(EditorUserBuildSettings.activeBuildTarget);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 工作流程
|
|
||||||
1. 通过 `Enable()` / `Disable()` 控制宏与 HybridCLR 设置。
|
|
||||||
2. `BuildAndCopyDlls()` 编译热更程序集。
|
|
||||||
3. `CopyAOTHotUpdateDlls()` 复制 AOT 与 HotUpdate DLL。
|
|
||||||
4. `AssetDatabase.Refresh()` 刷新资源库。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/HybridCLR/BuildDLLCommand.cs`
|
|
||||||
|
|
||||||
### 类型:`BuildDLLCommand`
|
|
||||||
#### `public static string AssemblyTextAssetPath`
|
|
||||||
- 作用:目标输出目录。
|
|
||||||
|
|
||||||
#### `public static void Disable()`
|
|
||||||
- 作用:关闭 HybridCLR 宏与设置。
|
|
||||||
|
|
||||||
#### `public static void Enable()`
|
|
||||||
- 作用:启用 HybridCLR 宏与设置。
|
|
||||||
|
|
||||||
#### `public static void BuildAndCopyDlls()`
|
|
||||||
- 作用:按当前激活平台编译并复制 DLL。
|
|
||||||
|
|
||||||
#### `public static void GenerateAll()`
|
|
||||||
- 作用:执行 `PrebuildCommand.GenerateAll()`。
|
|
||||||
|
|
||||||
#### `public static void BuildAndCopyDlls(BuildTarget target)`
|
|
||||||
- 作用:按指定平台编译并复制 DLL。
|
|
||||||
|
|
||||||
#### `public static void CopyAOTHotUpdateDlls(BuildTarget target)`
|
|
||||||
- 作用:统一复制 AOT 与 HotUpdate DLL。
|
|
||||||
|
|
||||||
#### `public static void CopyAOTAssembliesToAssetPath()`
|
|
||||||
- 作用:复制 AOT 补充程序集到输出目录。
|
|
||||||
|
|
||||||
#### `public static void CopyHotUpdateAssembliesToAssetPath()`
|
|
||||||
- 作用:复制 HotUpdate 程序集到输出目录。
|
|
||||||
|
|
||||||
## 示例
|
|
||||||
```csharp
|
|
||||||
[UnityEditor.MenuItem("Tools/HybridCLR/全部生成")]
|
|
||||||
public static void BuildAll()
|
|
||||||
{
|
|
||||||
BuildDLLCommand.GenerateAll();
|
|
||||||
BuildDLLCommand.BuildAndCopyDlls(UnityEditor.EditorUserBuildSettings.activeBuildTarget);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
- 依赖 HybridCLR 包和相关生成脚本完整可用。
|
|
||||||
- AOT 源目录通常需要先执行生成或构建流程后才存在。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: efaf24517e127234183a8852e2de38db
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
# EditorExtension ReferenceFinder 引用分析模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`ReferenceFinder` 用于分析项目资源的依赖与反向引用关系,支持缓存、树状展示和排序。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 查询资源被谁引用。
|
|
||||||
- 清理无用资源前做依赖确认。
|
|
||||||
- 排查深层依赖链和循环引用风险。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
using TEngine.Editor;
|
|
||||||
|
|
||||||
ResourceReferenceInfo.FindRef();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 模块结构
|
|
||||||
- `ResourceReferenceInfo`:入口与界面层。
|
|
||||||
- `ReferenceFinderData`:采集、缓存、状态管理。
|
|
||||||
- `AssetTreeView`:树状显示。
|
|
||||||
- `SortHelper`:排序逻辑。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`TEngine.Editor.ReferenceFinderData`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/ReferenceFinder/ReferenceFinderData.cs`
|
|
||||||
|
|
||||||
#### 公开成员
|
|
||||||
- `AssetState`
|
|
||||||
- `MinThreadCount`
|
|
||||||
- `allAssets`
|
|
||||||
- `assetDict`
|
|
||||||
- `CollectDependenciesInfo()`
|
|
||||||
- `ReadAssetInfo()`
|
|
||||||
- `GetAsset(string dataPath, string assetPath)`
|
|
||||||
- `ReadFromCache()`
|
|
||||||
- `UpdateAssetState(string guid)`
|
|
||||||
- `GetInfoByState(AssetState state)`
|
|
||||||
- `ClearCache()`
|
|
||||||
- `GetRefCount(AssetDescription desc, AssetDescription parentDesc)`
|
|
||||||
|
|
||||||
#### `AssetDescription` 字段
|
|
||||||
- `assetDependencyHashString`
|
|
||||||
- `dependencies`
|
|
||||||
- `name`
|
|
||||||
- `path`
|
|
||||||
- `references`
|
|
||||||
- `state`
|
|
||||||
|
|
||||||
### 类型:`TEngine.Editor.ResourceReferenceInfo`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/ReferenceFinder/ResourceReferenceInfo.cs`
|
|
||||||
|
|
||||||
#### 公开成员
|
|
||||||
- `Data`
|
|
||||||
- `needUpdateAssetTree`
|
|
||||||
- `needUpdateState`
|
|
||||||
- `selectedAssetGuid`
|
|
||||||
- `mAssetTreeView`
|
|
||||||
- `FindRef()`
|
|
||||||
- `DrawOptionBar()`
|
|
||||||
|
|
||||||
### 类型:`AssetTreeView`
|
|
||||||
- `AssetTreeView(TreeViewState state, MultiColumnHeader multicolumnHeader)`
|
|
||||||
- `SortExpandItem()`
|
|
||||||
- `CreateDefaultMultiColumnHeaderState(float treeViewWidth, bool isDepend)`
|
|
||||||
|
|
||||||
### 类型:`ClickColumn`
|
|
||||||
- `SortInColumn`
|
|
||||||
- `SortWithIndex`
|
|
||||||
- `ClickColumn(MultiColumnHeaderState state)`
|
|
||||||
- `SortByName()`
|
|
||||||
- `SortByPath()`
|
|
||||||
|
|
||||||
### 类型:`DragAreaGetObject`
|
|
||||||
- `GetObjects(string meg = null)`
|
|
||||||
|
|
||||||
### 类型:`SortHelper`
|
|
||||||
- `Init()`
|
|
||||||
- `ChangeSortType(...)`
|
|
||||||
- `SortByName()`
|
|
||||||
- `SortByPath()`
|
|
||||||
- `SortChild(...)`
|
|
||||||
- `NormalSort(...)`
|
|
||||||
- `FastSort(...)`
|
|
||||||
- `CompareWithName(...)`
|
|
||||||
- `CompareWithNameDesc(...)`
|
|
||||||
- `CompareWithPath(...)`
|
|
||||||
- `CompareWithPathDesc(...)`
|
|
||||||
|
|
||||||
### 其他公开类型
|
|
||||||
- `ListInfo`
|
|
||||||
- `SortType`
|
|
||||||
- `SortConfig`
|
|
||||||
|
|
||||||
## 示例
|
|
||||||
```csharp
|
|
||||||
var data = new TEngine.Editor.ReferenceFinderData();
|
|
||||||
data.CollectDependenciesInfo();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
- 大项目建议优先使用缓存。
|
|
||||||
- 资源大规模变更后建议先清缓存再重新采集。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6e2acda8e9c7959409e0c16d83cc852f
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
# EditorExtension TexturePacker 模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`TexturePacker` 提供一个轻量级编辑器窗口 `UnityTexturePackerEditor`,用于把多张纹理打包为一张大图并记录子图布局信息。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 临时合并散图。
|
|
||||||
- 验证贴图布局。
|
|
||||||
- 做非正式生产链路的编辑器打包。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
UnityTexturePackerEditor.ShowWindow();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/TexturePacker/UnityTexturePackEditor.cs`
|
|
||||||
|
|
||||||
### 类型:`UnityTexturePackerEditor`
|
|
||||||
#### `public static void ShowWindow()`
|
|
||||||
- 作用:打开 TexturePacker 窗口。
|
|
||||||
|
|
||||||
### 公开布局信息字段
|
|
||||||
- `name`
|
|
||||||
- `sourcePath`
|
|
||||||
- `x`
|
|
||||||
- `y`
|
|
||||||
- `w`
|
|
||||||
- `h`
|
|
||||||
- `sourceW`
|
|
||||||
- `sourceH`
|
|
||||||
|
|
||||||
### 公开导入备份字段
|
|
||||||
- `path`
|
|
||||||
- `isReadable`
|
|
||||||
- `type`
|
|
||||||
- `compression`
|
|
||||||
- `maxSize`
|
|
||||||
|
|
||||||
## 使用建议
|
|
||||||
- 如果项目已有正式 SpriteAtlas 流程,该工具更适合临时处理和验证。
|
|
||||||
- 执行前后应注意纹理导入配置恢复。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: fd5b62c9141e9654ba29b499d0888dde
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
# EditorExtension Toolbar 扩展框架手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`Toolbar` 模块用于向 Unity 主工具栏动态注入自定义 `VisualElement` / `IMGUIContainer`,支持自动发现、排序、对齐、推荐样式、分组与用户覆盖配置。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 给 Unity 顶部工具栏挂项目级入口。
|
|
||||||
- 统一管理开发、调试、资源、场景、构建工具。
|
|
||||||
- 让工具栏元素支持分组、显隐与个性化排序。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
using Paps.UnityToolbarExtenderUIToolkit;
|
|
||||||
using UnityEngine.UIElements;
|
|
||||||
|
|
||||||
[MainToolbarElement("DemoToolbar", ToolbarAlign.Right, 100)]
|
|
||||||
public class DemoToolbarElement : IMGUIContainer
|
|
||||||
{
|
|
||||||
public void InitializeElement()
|
|
||||||
{
|
|
||||||
onGUIHandler = () => UnityEngine.GUILayout.Label("Demo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 工作机制
|
|
||||||
1. `MainToolbar` 定位 Unity 原生 Toolbar 容器。
|
|
||||||
2. `MainToolbarAutomaticExtender` 负责刷新与注入。
|
|
||||||
3. 特性仓储扫描带 `MainToolbarElementAttribute` 的类型。
|
|
||||||
4. 元素实例化后包装为 `MainToolbarElement`。
|
|
||||||
5. 控制面板和覆盖配置负责用户态管理。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`MainToolbarElementAttribute`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/Toolbar/MainToolbarElementAttribute.cs`
|
|
||||||
|
|
||||||
- `MainToolbarElementAttribute(string id, ToolbarAlign alignment = ToolbarAlign.Left, int order = 0, bool useRecommendedStyles = true)`
|
|
||||||
- `Id`
|
|
||||||
- `Alignment`
|
|
||||||
- `Order`
|
|
||||||
- `UseRecommendedStyles`
|
|
||||||
|
|
||||||
### 类型:`MainToolbarElement`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/Toolbar/MainToolbarElement.cs`
|
|
||||||
|
|
||||||
- `Id`
|
|
||||||
- `VisualElement`
|
|
||||||
- `Alignment`
|
|
||||||
- `Order`
|
|
||||||
- `UseRecommendedStyles`
|
|
||||||
- 构造函数 `MainToolbarElement(...)`
|
|
||||||
|
|
||||||
### 类型:`MainToolbar`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/Toolbar/MainToolbar.cs`
|
|
||||||
|
|
||||||
- `OnInitialized`
|
|
||||||
- `OnRefresh`
|
|
||||||
- `UnityToolbarRoot`
|
|
||||||
- `LeftContainer`
|
|
||||||
- `CenterContainer`
|
|
||||||
- `RightContainer`
|
|
||||||
- `PlayModeButtonsContainer`
|
|
||||||
- `IsAvailable`
|
|
||||||
|
|
||||||
### 类型:`MainToolbarAutomaticExtender`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/Toolbar/MainToolbarAutomaticExtender.cs`
|
|
||||||
|
|
||||||
- `OnRefresh`
|
|
||||||
- `OnAddedCustomContainersToToolbar`
|
|
||||||
|
|
||||||
### 类型:`MainToolbarControlPanelWindow`
|
|
||||||
源码:`Packages/com.alicizax.unity.editor.extension/Editor/Toolbar/ControlPanelWindow/MainToolbarControlPanelWindow.cs`
|
|
||||||
|
|
||||||
- `OpenWindow()`
|
|
||||||
|
|
||||||
### 类型:`MainToolbarElementController`
|
|
||||||
- `Id`
|
|
||||||
- `ControlledVisualElement`
|
|
||||||
- `HoldsAGroup`
|
|
||||||
- `HoldsANativeElement`
|
|
||||||
|
|
||||||
### 其他重要公开类型
|
|
||||||
- `ToolbarAlign`
|
|
||||||
- `GroupDefinition`
|
|
||||||
- `GroupElement`
|
|
||||||
- `ScriptableGroupDefinition`
|
|
||||||
- `MainToolbarElementDropdownAttribute`
|
|
||||||
- `MainToolbarElementOverride`
|
|
||||||
- `RecommendedStyle` 及派生类
|
|
||||||
- `Variable` / `SerializableVariable` 等变量序列化类型
|
|
||||||
|
|
||||||
## 打开控制面板
|
|
||||||
- 菜单:`Tools/Extension/Toolbar/Main Toolbar Control Panel`
|
|
||||||
- 代码:`MainToolbarControlPanelWindow.OpenWindow();`
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
- `Id` 应稳定且全局唯一。
|
|
||||||
- 自定义元素建议在 `InitializeElement()` 中做依赖判空。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7f5ebb19e8045f24c8f0de3a2218fabb
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: cbb4b30bf931b134094b7d4d196ce68f
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
# Event
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Event 模块提供轻量级、低分配的结构体事件系统,适合模块解耦、状态广播、UI/玩法/流程间通知,以及编辑器内订阅行为监控。
|
|
||||||
|
|
||||||
设计重点:
|
|
||||||
|
|
||||||
- 使用 `struct` 事件降低 GC 压力
|
|
||||||
- 通过泛型容器按事件类型隔离订阅列表
|
|
||||||
- 使用调试注册表记录订阅、发布、扩容等行为
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 定义 `struct` 事件并实现 `IEventArgs`
|
|
||||||
2. 调用 `EventBus.Subscribe<T>()` 订阅
|
|
||||||
3. 调用 `EventBus.Publish(in evt)` 发布
|
|
||||||
4. 在对象失活或销毁时释放订阅句柄
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
|
|
||||||
public struct PlayerLevelUpEvent : IEventArgs
|
|
||||||
{
|
|
||||||
public int NewLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class EventQuickStart
|
|
||||||
{
|
|
||||||
private EventRuntimeHandle _handle;
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
_handle = EventBus.Subscribe<PlayerLevelUpEvent>(OnLevelUp);
|
|
||||||
EventBus.Publish(new PlayerLevelUpEvent { NewLevel = 10 });
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLevelUp(PlayerLevelUpEvent evt)
|
|
||||||
{
|
|
||||||
Log.Info($"Level => {evt.NewLevel}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
业务代码
|
|
||||||
├─ EventBus.Subscribe<T>()
|
|
||||||
├─ EventBus.Publish<T>()
|
|
||||||
└─ EventBus.Clear<T>()
|
|
||||||
↓
|
|
||||||
EventContainer<T>
|
|
||||||
↓
|
|
||||||
EventRuntimeHandle / 订阅槽
|
|
||||||
↓
|
|
||||||
EventDebugRegistry
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心类型说明
|
|
||||||
|
|
||||||
### `IEventArgs`
|
|
||||||
|
|
||||||
- 所有事件载体的标记接口
|
|
||||||
- 事件类型必须是 `struct`
|
|
||||||
|
|
||||||
### `EventBus`
|
|
||||||
|
|
||||||
公开能力:
|
|
||||||
|
|
||||||
- `Subscribe<T>(Action<T> handler)`
|
|
||||||
- `Publish<T>(in T evt)`
|
|
||||||
- `GetSubscriberCount<T>()`
|
|
||||||
- `EnsureCapacity<T>(int capacity)`
|
|
||||||
- `Clear<T>()`
|
|
||||||
|
|
||||||
### `EventRuntimeHandle`
|
|
||||||
|
|
||||||
- 表示一次已建立的订阅
|
|
||||||
- 用于解绑或自动管理订阅生命周期
|
|
||||||
|
|
||||||
### `EventInitialSize<T>`
|
|
||||||
|
|
||||||
- 用于为某类事件声明初始订阅容量
|
|
||||||
- 高频事件建议预热容量
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `EventBus.Subscribe<T>(Action<T> handler) where T : struct, IEventArgs`
|
|
||||||
|
|
||||||
- 必填参数:`handler`
|
|
||||||
- 返回值:`EventRuntimeHandle`
|
|
||||||
- 泛型约束:`T : struct, IEventArgs`
|
|
||||||
- 说明:订阅某种事件
|
|
||||||
- 注意:建议保存返回句柄,便于后续解绑
|
|
||||||
|
|
||||||
### `EventBus.Publish<T>(in T evt) where T : struct, IEventArgs`
|
|
||||||
|
|
||||||
- 必填参数:`evt`
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:同步发布事件
|
|
||||||
- 注意:回调会立即执行,发布链路中不要写过重逻辑
|
|
||||||
|
|
||||||
### `EventBus.GetSubscriberCount<T>()`
|
|
||||||
|
|
||||||
- 返回值:`int`
|
|
||||||
- 说明:返回当前事件订阅数量
|
|
||||||
|
|
||||||
### `EventBus.EnsureCapacity<T>(int capacity)`
|
|
||||||
|
|
||||||
- 必填参数:`capacity`
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:预热内部容器容量
|
|
||||||
|
|
||||||
### `EventBus.Clear<T>()`
|
|
||||||
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:清空某类事件订阅
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public struct CoinChangedEvent : IEventArgs
|
|
||||||
{
|
|
||||||
public int CurrentValue;
|
|
||||||
public int Delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class EventExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private EventRuntimeHandle _handle;
|
|
||||||
private int _coin;
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
EventBus.EnsureCapacity<CoinChangedEvent>(8);
|
|
||||||
_handle = EventBus.Subscribe<CoinChangedEvent>(OnCoinChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (Input.GetKeyDown(KeyCode.C))
|
|
||||||
{
|
|
||||||
_coin += 100;
|
|
||||||
EventBus.Publish(new CoinChangedEvent
|
|
||||||
{
|
|
||||||
CurrentValue = _coin,
|
|
||||||
Delta = 100
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDisable()
|
|
||||||
{
|
|
||||||
_handle.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCoinChanged(CoinChangedEvent evt)
|
|
||||||
{
|
|
||||||
Debug.Log($"Coin changed: {evt.CurrentValue} (+{evt.Delta})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 事件体尽量小,避免塞入大对象
|
|
||||||
- 高频事件预热容量
|
|
||||||
- 订阅与释放时机成对出现
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
- 事件类型定义成 `class`
|
|
||||||
- 只订阅不解绑
|
|
||||||
|
|
||||||
## 性能注意事项
|
|
||||||
|
|
||||||
- `Publish` 为同步执行,避免重逻辑
|
|
||||||
- 结合编辑器事件监视器检查扩容次数和订阅抖动
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c7741236daa2b2949b67f42a855ae3e3
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,186 +0,0 @@
|
|||||||
# Foundation
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Foundation 是整个框架的运行时基础层,负责:
|
|
||||||
|
|
||||||
- 应用根节点初始化
|
|
||||||
- 服务容器与作用域管理
|
|
||||||
- 公共异常、内存池、数据结构
|
|
||||||
- 全局访问入口与运行时基础配置
|
|
||||||
- 模块动态绑定与启动时配置注入
|
|
||||||
|
|
||||||
如果把整个包看成一棵树,Foundation 就是树根;其他模块都建立在它提供的服务世界之上。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 最少步骤
|
|
||||||
|
|
||||||
1. 在启动场景挂载 `RootModule`
|
|
||||||
2. 让各功能模块组件与 `RootModule` 位于同一生命周期体系内
|
|
||||||
3. 使用 `GameApp` 或 `AppServices` 获取模块服务
|
|
||||||
|
|
||||||
### 最小示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class FoundationQuickStart : MonoBehaviour
|
|
||||||
{
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
RootModule root = GameApp.Base;
|
|
||||||
root.FrameRate = 120;
|
|
||||||
root.GameSpeed = 1f;
|
|
||||||
|
|
||||||
Debug.Log($"Has world: {AppServices.HasWorld}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
RootModule
|
|
||||||
└─ AppServiceRoot
|
|
||||||
└─ ServiceWorld
|
|
||||||
├─ App Scope
|
|
||||||
├─ Scene Scope
|
|
||||||
└─ Gameplay Scope
|
|
||||||
```
|
|
||||||
|
|
||||||
### 各部分职责
|
|
||||||
|
|
||||||
- `RootModule`:全局根节点,负责运行参数和全局清理
|
|
||||||
- `AppServiceRoot`:创建 `ServiceWorld` 并驱动 Tick
|
|
||||||
- `ServiceWorld`:持有多个 `ServiceScope`
|
|
||||||
- `ServiceScope`:某个作用域下的服务容器
|
|
||||||
- `AppServices`:统一静态访问门面
|
|
||||||
- `GameApp`:高频模块快捷入口
|
|
||||||
|
|
||||||
## 核心类型说明
|
|
||||||
|
|
||||||
### `RootModule`
|
|
||||||
|
|
||||||
关键属性:
|
|
||||||
|
|
||||||
- `FrameRate`:目标帧率
|
|
||||||
- `GameSpeed`:时间缩放
|
|
||||||
- `IsGamePaused`:是否暂停
|
|
||||||
- `RunInBackground`:后台运行
|
|
||||||
- `NeverSleep`:禁止休眠
|
|
||||||
|
|
||||||
关键方法:
|
|
||||||
|
|
||||||
- `PauseGame()`
|
|
||||||
- `ResumeGame()`
|
|
||||||
- `ResetNormalGameSpeed()`
|
|
||||||
|
|
||||||
### `AppServices`
|
|
||||||
|
|
||||||
常用成员:
|
|
||||||
|
|
||||||
- `HasWorld` / `HasScene` / `HasGameplay`
|
|
||||||
- `App` / `Scene` / `Gameplay`
|
|
||||||
- `EnsureWorld()` / `EnsureScene()` / `EnsureGameplay()`
|
|
||||||
- `Require<T>()`
|
|
||||||
- `TryGet<T>(out T service)`
|
|
||||||
- `Shutdown()`
|
|
||||||
|
|
||||||
### `GameApp`
|
|
||||||
|
|
||||||
公开入口:
|
|
||||||
|
|
||||||
- `Base`
|
|
||||||
- `Audio`
|
|
||||||
- `Localization`
|
|
||||||
- `ObjectPool`
|
|
||||||
- `Procedure`
|
|
||||||
- `Resource`
|
|
||||||
- `Scene`
|
|
||||||
- `Timer`
|
|
||||||
- `UI`
|
|
||||||
|
|
||||||
### `ModuleDynamicBind`
|
|
||||||
|
|
||||||
作用:
|
|
||||||
|
|
||||||
- 在非 Editor 环境中读取 `ModuleDynamicBindInfo`
|
|
||||||
- 对 `ResourceComponent`、`DebuggerComponent`、`LocalizationComponent` 注入启动配置
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `AppServices.Require<T>() where T : class, IService`
|
|
||||||
|
|
||||||
- 参数:无
|
|
||||||
- 返回值:`T`
|
|
||||||
- 泛型约束:`class, IService`
|
|
||||||
- 说明:强制获取已注册服务
|
|
||||||
- 异常:服务世界未创建或服务未注册时失败
|
|
||||||
|
|
||||||
### `AppServices.TryGet<T>(out T service) where T : class, IService`
|
|
||||||
|
|
||||||
- 输出参数:`service`
|
|
||||||
- 返回值:`bool`
|
|
||||||
- 说明:安全查询服务
|
|
||||||
|
|
||||||
### `AppServices.EnsureWorld(int appScopeOrder = ServiceDomainOrder.App)`
|
|
||||||
|
|
||||||
- 可选参数:`appScopeOrder`
|
|
||||||
- 返回值:`ServiceWorld`
|
|
||||||
|
|
||||||
### `RootModule.PauseGame()`
|
|
||||||
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:保存当前速度并暂停
|
|
||||||
|
|
||||||
### `RootModule.ResumeGame()`
|
|
||||||
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:恢复暂停前速度
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class FoundationExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
RootModule root = GameApp.Base;
|
|
||||||
root.FrameRate = 120;
|
|
||||||
root.RunInBackground = true;
|
|
||||||
root.NeverSleep = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (Input.GetKeyDown(KeyCode.P))
|
|
||||||
{
|
|
||||||
if (GameApp.Base.IsGamePaused)
|
|
||||||
GameApp.Base.ResumeGame();
|
|
||||||
else
|
|
||||||
GameApp.Base.PauseGame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 只保留一个 `RootModule`
|
|
||||||
- 首场景统一挂载框架组件
|
|
||||||
- 常用服务走 `GameApp`,扩展服务走 `AppServices`
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
- 服务未注册就访问
|
|
||||||
- 多个 `RootModule` 并存
|
|
||||||
|
|
||||||
## 性能注意事项
|
|
||||||
|
|
||||||
- 不要频繁重建服务世界
|
|
||||||
- 高频访问模块时优先使用 `GameApp` 的缓存入口
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 91578f5be03b1de4dbac802cab59cb24
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
# GameObjectPool
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
GameObjectPool 面向场景对象与预制体实例复用。它基于 `PoolConfig` 决定某个资源是否入池、如何匹配、如何预热,并可通过 `Resources` 或 AssetBundle/YooAsset 进行加载。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 场景挂载 `GameObjectPoolManager`
|
|
||||||
2. 准备 `PoolConfigScriptableObject`
|
|
||||||
3. 确保 `ResourceComponent` 已注册
|
|
||||||
4. 使用 `PreloadAsync` / `GetGameObjectAsync` / `Release`
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
GameObjectPoolManager
|
|
||||||
├─ PoolConfigScriptableObject
|
|
||||||
├─ PoolConfig
|
|
||||||
├─ RuntimePrefabPool
|
|
||||||
└─ IResourceLoader
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `GameObjectPoolManager`
|
|
||||||
|
|
||||||
主要能力:
|
|
||||||
|
|
||||||
- `GetGameObject(...)`
|
|
||||||
- `GetGameObjectAsync(...)`
|
|
||||||
- `Preload(...)`
|
|
||||||
- `PreloadAsync(...)`
|
|
||||||
- `Release(GameObject gameObject)`
|
|
||||||
- `ClearAllPools()`
|
|
||||||
- `ForceCleanup()`
|
|
||||||
|
|
||||||
### `PoolConfig`
|
|
||||||
|
|
||||||
决定:
|
|
||||||
|
|
||||||
- 资源匹配方式
|
|
||||||
- 预热数量
|
|
||||||
- 清理与过期策略
|
|
||||||
- 使用哪种资源加载器
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `GetGameObject(string assetPath, Transform parent = null)`
|
|
||||||
|
|
||||||
- 必填参数:`assetPath`
|
|
||||||
- 可选参数:`parent`
|
|
||||||
- 返回值:`GameObject`
|
|
||||||
- 异常:初始化未完成时会抛异常
|
|
||||||
|
|
||||||
### `GetGameObjectAsync(string assetPath, Transform parent = null, CancellationToken cancellationToken = default)`
|
|
||||||
|
|
||||||
- 必填参数:`assetPath`
|
|
||||||
- 可选参数:`parent`
|
|
||||||
- 可选参数:`cancellationToken`
|
|
||||||
- 返回值:`UniTask<GameObject>`
|
|
||||||
|
|
||||||
### `Release(GameObject gameObject)`
|
|
||||||
|
|
||||||
- 必填参数:`gameObject`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using Cysharp.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class GameObjectPoolExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeField] private GameObjectPoolManager poolManager;
|
|
||||||
|
|
||||||
private async UniTaskVoid Start()
|
|
||||||
{
|
|
||||||
await poolManager.PreloadAsync("Assets/Bundles/Effects/Fx_Hit.prefab", 3);
|
|
||||||
|
|
||||||
GameObject fx = await poolManager.GetGameObjectAsync("Assets/Bundles/Effects/Fx_Hit.prefab", transform);
|
|
||||||
await UniTask.Delay(1000);
|
|
||||||
poolManager.Release(fx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 特效、子弹、临时场景装饰物优先走该模块
|
|
||||||
- 常见资源在初始化阶段预热
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
- 在初始化完成前调用同步接口
|
|
||||||
- 对池对象手动 `Destroy`
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: fb63f330ed43037448a8c927045727c5
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,204 +0,0 @@
|
|||||||
# ObjectPool
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
ObjectPool 是面向纯 C# 对象的通用对象池模块,适合缓存临时数据对象、资源包装对象、UI/资源扩展辅助对象和调试器内部缓存对象。
|
|
||||||
|
|
||||||
它与 `MemoryPool` 的区别:
|
|
||||||
|
|
||||||
- `MemoryPool` 更偏向单个对象快速申请/释放
|
|
||||||
- `ObjectPool` 更偏向带策略的池管理,支持容量、过期、优先级、锁定等行为
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 场景挂载 `ObjectPoolComponent`
|
|
||||||
2. 定义继承 `ObjectBase` 的对象类型
|
|
||||||
3. 使用 `GameApp.ObjectPool.CreatePool<T>()`
|
|
||||||
4. `Register` / `Spawn` / `Unspawn`
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using AlicizaX.ObjectPool;
|
|
||||||
|
|
||||||
public sealed class CacheItem : ObjectBase
|
|
||||||
{
|
|
||||||
public string Key;
|
|
||||||
|
|
||||||
public override void Clear()
|
|
||||||
{
|
|
||||||
Key = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ObjectPoolQuickStart
|
|
||||||
{
|
|
||||||
public void Run()
|
|
||||||
{
|
|
||||||
var pool = GameApp.ObjectPool.CreatePool<CacheItem>(ObjectPoolCreateOptions.Single("Cache"));
|
|
||||||
CacheItem item = MemoryPool.Acquire<CacheItem>();
|
|
||||||
item.Key = "A";
|
|
||||||
pool.Register(item, false);
|
|
||||||
|
|
||||||
CacheItem spawned = pool.Spawn();
|
|
||||||
pool.Unspawn(spawned);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
ObjectPoolComponent
|
|
||||||
└─ ObjectPoolService
|
|
||||||
├─ IObjectPool<T>
|
|
||||||
├─ ObjectPoolBase
|
|
||||||
└─ ObjectBase
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心类型说明
|
|
||||||
|
|
||||||
### `IObjectPoolService`
|
|
||||||
|
|
||||||
负责:
|
|
||||||
|
|
||||||
- 创建对象池
|
|
||||||
- 查询对象池
|
|
||||||
- 销毁对象池
|
|
||||||
- 统一释放未使用对象
|
|
||||||
|
|
||||||
### `IObjectPool<T>`
|
|
||||||
|
|
||||||
常用公开方法:
|
|
||||||
|
|
||||||
- `Register`
|
|
||||||
- `Spawn`
|
|
||||||
- `Unspawn`
|
|
||||||
- `SetLocked`
|
|
||||||
- `SetPriority`
|
|
||||||
- `Release`
|
|
||||||
- `ReleaseAllUnused`
|
|
||||||
|
|
||||||
### `ObjectBase`
|
|
||||||
|
|
||||||
- 池内对象基类
|
|
||||||
- 需要正确实现 `Clear()`
|
|
||||||
|
|
||||||
### `ObjectPoolCreateOptions`
|
|
||||||
|
|
||||||
主要参数:
|
|
||||||
|
|
||||||
- `name`
|
|
||||||
- `allowMultiSpawn`
|
|
||||||
- `autoReleaseInterval`
|
|
||||||
- `capacity`
|
|
||||||
- `expireTime`
|
|
||||||
- `priority`
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `IObjectPoolService.CreatePool<T>(ObjectPoolCreateOptions options = default) where T : ObjectBase`
|
|
||||||
|
|
||||||
- 可选参数:`options`
|
|
||||||
- 返回值:`IObjectPool<T>`
|
|
||||||
- 泛型约束:`T : ObjectBase`
|
|
||||||
|
|
||||||
### `IObjectPool<T>.Register(T obj, bool spawned)`
|
|
||||||
|
|
||||||
- 必填参数:`obj`
|
|
||||||
- 必填参数:`spawned`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
### `IObjectPool<T>.Spawn()`
|
|
||||||
|
|
||||||
- 返回值:`T`
|
|
||||||
- 说明:取出一个可用对象;无可用对象时通常返回 `null`
|
|
||||||
|
|
||||||
### `IObjectPool<T>.Unspawn(T obj)`
|
|
||||||
|
|
||||||
- 必填参数:`obj`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
### `IObjectPool<T>.ReleaseAllUnused()`
|
|
||||||
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:释放当前池中未使用对象
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using AlicizaX.ObjectPool;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class DamageTextData : ObjectBase
|
|
||||||
{
|
|
||||||
public int Value;
|
|
||||||
public Color Color;
|
|
||||||
|
|
||||||
public void Init(int value, Color color)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
Color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Clear()
|
|
||||||
{
|
|
||||||
Value = 0;
|
|
||||||
Color = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ObjectPoolExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private IObjectPool<DamageTextData> _pool;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_pool = GameApp.ObjectPool.CreatePool<DamageTextData>(
|
|
||||||
new ObjectPoolCreateOptions(
|
|
||||||
name: "DamageText",
|
|
||||||
allowMultiSpawn: false,
|
|
||||||
autoReleaseInterval: 30f,
|
|
||||||
capacity: 64,
|
|
||||||
expireTime: 120f,
|
|
||||||
priority: 0));
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
DamageTextData data = MemoryPool.Acquire<DamageTextData>();
|
|
||||||
data.Init(i, Color.red);
|
|
||||||
_pool.Register(data, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowDamage(int damage)
|
|
||||||
{
|
|
||||||
DamageTextData data = _pool.Spawn();
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
data = MemoryPool.Acquire<DamageTextData>();
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Init(damage, Color.yellow);
|
|
||||||
Debug.Log($"Damage => {data.Value}");
|
|
||||||
_pool.Unspawn(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 对象应保持“可完全重置”
|
|
||||||
- 通过 `ObjectPoolCreateOptions` 明确池策略
|
|
||||||
- 大量短生命周期对象优先考虑对象池
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
- 把 `GameObject` 放入该池
|
|
||||||
- `Clear()` 未重置字段
|
|
||||||
- 未区分 `Register(..., true/false)`
|
|
||||||
|
|
||||||
## 性能注意事项
|
|
||||||
|
|
||||||
- 大对象池请配置 `capacity` 和 `expireTime`
|
|
||||||
- 过多小池会增加管理成本
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: eaf9c0f1f6ac7e241b6b95a9c1a5b6a4
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: dabe76bff0e82ac49acbce538ac31bc2
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,157 +0,0 @@
|
|||||||
# EditorTools
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
EditorTools 是框架的编辑器侧配套,覆盖 Inspector、自定义窗口、配置工具与代码生成流程,目的是降低模块接入与排查成本。
|
|
||||||
|
|
||||||
与 UI 最相关的部分是:
|
|
||||||
|
|
||||||
- `UISettingEditorWindow`
|
|
||||||
- `UIGenerateQuick`
|
|
||||||
- `UIScriptGeneratorHelper`
|
|
||||||
- `UIGenerateConfiguration`
|
|
||||||
|
|
||||||
它们共同组成了 **UIHolder 自动生成工作流**。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### UI 绑定工具的基本使用流程
|
|
||||||
|
|
||||||
1. 打开 UI 生成配置窗口,配置 UI 规则
|
|
||||||
2. 把 UI 预制体放在配置的 `UIPrefabRootPath` 目录下
|
|
||||||
3. 按命名规范布置需要绑定的节点
|
|
||||||
4. 选中 UI 预制体根节点
|
|
||||||
5. 执行菜单 `GameObject/UI生成绑定`
|
|
||||||
6. 等待脚本编译完成
|
|
||||||
7. 生成器自动把 `XXXHolder` 挂回预制体,并回填控件字段
|
|
||||||
|
|
||||||
## UIHolder 自动生成说明
|
|
||||||
|
|
||||||
### 1. `UIHolder` 的定位
|
|
||||||
|
|
||||||
在本框架中:
|
|
||||||
|
|
||||||
- `UIHolder` 指的是继承自 `UIHolderObjectBase` 的绑定类
|
|
||||||
- 它主要用于保存控件引用和资源标签
|
|
||||||
- 它不是主要的业务逻辑承载类
|
|
||||||
|
|
||||||
推荐方式:
|
|
||||||
|
|
||||||
- **手写 Window / Widget 逻辑**
|
|
||||||
- **自动生成 Holder 绑定类**
|
|
||||||
|
|
||||||
### 2. 使用哪个工具生成
|
|
||||||
|
|
||||||
核心入口:
|
|
||||||
|
|
||||||
- 菜单:`GameObject/UI生成绑定`
|
|
||||||
|
|
||||||
对应代码入口位于:
|
|
||||||
|
|
||||||
- `Packages/com.alicizax.unity.framework/Editor/UI/GenerateWindow/UIGenerateQuick.cs:1`
|
|
||||||
|
|
||||||
当你执行该菜单时,生成器会:
|
|
||||||
|
|
||||||
- 检查当前选中的对象是否是 prefab
|
|
||||||
- 读取 `UIGenerateConfiguration`
|
|
||||||
- 校验 prefab 是否位于允许的 UI 根路径下
|
|
||||||
- 分析节点名并推断组件类型
|
|
||||||
- 输出 `UIHolder` 脚本
|
|
||||||
- 在脚本编译后自动挂到 prefab 上
|
|
||||||
- 自动把字段与节点/组件引用绑定完成
|
|
||||||
|
|
||||||
### 3. 命名规则如何影响生成
|
|
||||||
|
|
||||||
生成器会结合:
|
|
||||||
|
|
||||||
- `UIElementRegexConfigs`
|
|
||||||
- `ComCheckSplitName`
|
|
||||||
- `ComCheckEndName`
|
|
||||||
- `ArrayComSplitName`
|
|
||||||
|
|
||||||
来识别节点绑定信息。
|
|
||||||
|
|
||||||
例如默认配置会把:
|
|
||||||
|
|
||||||
- `Btn#Close@` 识别为按钮字段
|
|
||||||
- `Text#Title@` 识别为文本字段
|
|
||||||
- `Img#Icon@` 识别为图片字段
|
|
||||||
|
|
||||||
### 4. 生成结果是什么
|
|
||||||
|
|
||||||
生成出的 Holder 类通常:
|
|
||||||
|
|
||||||
- 继承 `UIHolderObjectBase`
|
|
||||||
- 自动带有 `UIResAttribute`
|
|
||||||
- 自动写入资源路径常量
|
|
||||||
- 自动生成字段与公开访问器
|
|
||||||
|
|
||||||
这使得 UI 逻辑层可以直接通过泛型 Holder 访问控件,而无需再手动查找。
|
|
||||||
|
|
||||||
## 相关工具与职责
|
|
||||||
|
|
||||||
### `UISettingEditorWindow`
|
|
||||||
|
|
||||||
作用:
|
|
||||||
|
|
||||||
- 维护 UI 生成配置
|
|
||||||
- 配置输出目录、命名空间、Prefab 根路径、资源加载方式
|
|
||||||
|
|
||||||
### `UIGenerateQuick`
|
|
||||||
|
|
||||||
作用:
|
|
||||||
|
|
||||||
- 提供快速菜单入口
|
|
||||||
- 校验当前对象是否可生成
|
|
||||||
|
|
||||||
### `UIScriptGeneratorHelper`
|
|
||||||
|
|
||||||
作用:
|
|
||||||
|
|
||||||
- 扫描节点
|
|
||||||
- 推断字段名和组件类型
|
|
||||||
- 生成代码
|
|
||||||
- 在脚本重载后自动挂载脚本并绑定字段
|
|
||||||
|
|
||||||
### `UIGenerateConfiguration`
|
|
||||||
|
|
||||||
作用:
|
|
||||||
|
|
||||||
- 保存生成规则与路径设置
|
|
||||||
- 支持不同项目或不同目录使用不同配置
|
|
||||||
|
|
||||||
## 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 推荐流程:
|
|
||||||
// 1. 设计 InventoryItem.prefab
|
|
||||||
// 2. 选中 prefab 根节点
|
|
||||||
// 3. 执行 “GameObject/UI生成绑定”
|
|
||||||
// 4. 得到 InventoryItemHolder : UIHolderObjectBase
|
|
||||||
// 5. 在业务代码中编写:
|
|
||||||
// public sealed class InventoryItemWidget : UIWidget<InventoryItemHolder> { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 把 UI 生成规则纳入项目模板,避免每个模块自行定义一套命名方式
|
|
||||||
- Holder 文件视为“生成产物”,不要手工长期维护
|
|
||||||
- 如果修改了 prefab 绑定节点,重新执行一次生成工具
|
|
||||||
- 逻辑类和生成类分离,减少合并冲突
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
### 预制体不在配置的 UI 根路径下
|
|
||||||
|
|
||||||
- 现象:执行生成工具无结果
|
|
||||||
- 原因:`UIGenerateQuick.CheckCanGenerate` 校验失败
|
|
||||||
|
|
||||||
### 修改了预制体但没重新生成 Holder
|
|
||||||
|
|
||||||
- 现象:字段缺失或控件引用错误
|
|
||||||
- 处理:重新执行 `GameObject/UI生成绑定`
|
|
||||||
|
|
||||||
### 手动改了生成类名称或命名空间
|
|
||||||
|
|
||||||
- 现象:逻辑类泛型类型失配
|
|
||||||
- 处理:尽量不要手改生成文件,必要时同步更新生成配置与逻辑类引用
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0c080bcc065201840afe739351071504
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 4faf052fe9676814a83fd3638d12e801
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
# Plugins
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
`Plugins` 目录保存框架依赖的第三方程序集与源码生成插件,它们补充了框架运行时能力、兼容层与自动注册逻辑。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
通常不需要业务层主动初始化本模块。开发者需要做的是:
|
|
||||||
|
|
||||||
1. 确认 Unity 正常导入 DLL
|
|
||||||
2. 不随意删除或移动 `Plugins` 目录文件
|
|
||||||
3. 在 UI / Event 自动注册异常时优先检查生成器 DLL 是否生效
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
Plugins
|
|
||||||
├─ XLog.dll
|
|
||||||
├─ SharpZipLib
|
|
||||||
├─ System.Memory / Buffers / Unsafe
|
|
||||||
├─ EventSourceGenerator.dll
|
|
||||||
└─ UISourceGenerator.dll
|
|
||||||
```
|
|
||||||
|
|
||||||
## 主要内容
|
|
||||||
|
|
||||||
- `XLog.dll`:日志能力支持
|
|
||||||
- `ICSharpCode.SharpZipLib.dll`:压缩/解压相关能力
|
|
||||||
- `System.Buffers.dll`、`System.Memory.dll`、`System.Runtime.CompilerServices.Unsafe.dll`:底层兼容依赖
|
|
||||||
- `EventSourceGenerator.dll`:事件源码生成插件
|
|
||||||
- `UISourceGenerator.dll`:UI 源码生成插件
|
|
||||||
|
|
||||||
## API / 作用说明
|
|
||||||
|
|
||||||
### `EventSourceGenerator.dll`
|
|
||||||
|
|
||||||
- 作用:辅助事件相关代码生成
|
|
||||||
|
|
||||||
### `UISourceGenerator.dll`
|
|
||||||
|
|
||||||
- 作用:辅助 UI 元数据与资源绑定注册
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 本模块通常不直接由业务代码调用。
|
|
||||||
// 若出现 UI/Event 自动注册异常,请先检查对应 DLL 在 Unity 中是否正常导入。
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 锁定插件版本
|
|
||||||
- 升级 Unity 后优先验证生成器与 IL2CPP 打包链路
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 2052075fd72f78349bc745789185c70d
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
# Aliciza X Framework 快速入口
|
|
||||||
|
|
||||||
## 1. 框架简介
|
|
||||||
|
|
||||||
`com.alicizax.unity.framework` 是一套面向 Unity 项目的模块化基础框架,围绕 **根节点统一启动、服务容器统一获取、运行时模块按需组合** 的设计思想构建。
|
|
||||||
框架通过 `RootModule` 建立全局运行时入口,通过 `AppServices` / `GameApp` 暴露常用服务访问点,再由 UI、资源、音频、本地化、场景、流程、池化、定时器等模块分别承载具体业务能力。
|
|
||||||
|
|
||||||
### 核心设计理念
|
|
||||||
|
|
||||||
- **组合优先**:各模块以组件或服务形式注册,按项目需要启用。
|
|
||||||
- **职责分层**:区分 `Core / Runtime / Editor / Plugins`,运行时与编辑器逻辑边界清晰。
|
|
||||||
- **统一入口**:通过 `GameApp`、服务定位与根模块生命周期减少业务侧样板代码。
|
|
||||||
- **面向工程化**:覆盖资源加载、UI 绑定、流程切换、调试监视、池化复用等常见项目基础设施。
|
|
||||||
|
|
||||||
## 2. 推荐阅读顺序
|
|
||||||
|
|
||||||
1. [Foundation](./Core/Foundation.md)
|
|
||||||
2. [Resource](./Runtime/Resource.md)
|
|
||||||
3. [Timer](./Runtime/Timer.md)
|
|
||||||
4. [UI](./Runtime/UI.md)
|
|
||||||
5. 其余业务模块
|
|
||||||
|
|
||||||
## 3. 模块目录
|
|
||||||
|
|
||||||
### Core
|
|
||||||
|
|
||||||
- [Foundation](./Core/Foundation.md):根模块、服务容器、通用基础设施与核心抽象。
|
|
||||||
- [Event](./Core/Event.md):结构体事件总线、事件订阅与调试监视。
|
|
||||||
- [ObjectPool](./Core/ObjectPool.md):通用对象池与可复用实例管理。
|
|
||||||
- [GameObjectPool](./Core/GameObjectPool.md):面向预制体/场景对象的 GameObject 级池化系统。
|
|
||||||
|
|
||||||
### Runtime
|
|
||||||
|
|
||||||
- [Audio](./Runtime/Audio.md):音频播放、分组音量、播放句柄与运行时控制。
|
|
||||||
- [Debugger](./Runtime/Debugger.md):运行时调试面板、监控入口与调试扩展。
|
|
||||||
- [Localization](./Runtime/Localization.md):本地化表、语言切换与文本刷新机制。
|
|
||||||
- [Procedure](./Runtime/Procedure.md):流程/状态节点切换与启动流程组织。
|
|
||||||
- [Resource](./Runtime/Resource.md):资源系统封装、包初始化、资源加载与实例化。
|
|
||||||
- [Scene](./Runtime/Scene.md):场景加载、场景域切换与场景生命周期协作。
|
|
||||||
- [Timer](./Runtime/Timer.md):统一定时器服务、延时/循环/取消与时间驱动逻辑。
|
|
||||||
- [UI](./Runtime/UI.md):UI 窗口、Widget、Holder 绑定、层级管理与动画过渡。
|
|
||||||
|
|
||||||
### Editor
|
|
||||||
|
|
||||||
- [EditorTools](./Editor/EditorTools.md):Inspector、事件监视器、UI 绑定生成器与本地化编辑工具。
|
|
||||||
|
|
||||||
### Plugins
|
|
||||||
|
|
||||||
- [Plugins](./Plugins/Plugins.md):第三方程序集、代码生成器与插件职责说明。
|
|
||||||
|
|
||||||
## 4. 整体协作关系
|
|
||||||
|
|
||||||
```text
|
|
||||||
RootModule
|
|
||||||
└── AppServiceRoot
|
|
||||||
└── AppServices / GameApp
|
|
||||||
├── Resource
|
|
||||||
├── Timer
|
|
||||||
├── UI
|
|
||||||
├── Audio
|
|
||||||
├── Localization
|
|
||||||
├── Procedure
|
|
||||||
├── ObjectPool / GameObjectPool
|
|
||||||
└── Scene
|
|
||||||
```
|
|
||||||
|
|
||||||
### 常见依赖关系
|
|
||||||
|
|
||||||
- `UI` 通常依赖 `Resource` 加载界面资源,并依赖 `Timer` 驱动过渡或延迟行为。
|
|
||||||
- `Scene` 常与 `Resource` 协作处理场景包加载,与 `Procedure` 协作组织关卡切换。
|
|
||||||
- `Localization` 常与 `UI` 或 `UX` 文本组件协作,负责语言刷新。
|
|
||||||
- `GameObjectPool` 常与 `Resource` 协作完成预制体异步加载与回收复用。
|
|
||||||
|
|
||||||
## 5. 最小接入步骤
|
|
||||||
|
|
||||||
### 场景基础组件
|
|
||||||
|
|
||||||
推荐在启动场景中至少挂载:
|
|
||||||
|
|
||||||
- `RootModule`
|
|
||||||
- `ResourceComponent`
|
|
||||||
- `TimerComponent`
|
|
||||||
- `UIComponent`
|
|
||||||
|
|
||||||
### 启动顺序建议
|
|
||||||
|
|
||||||
```text
|
|
||||||
RootModule -> ResourceComponent -> TimerComponent -> UIComponent -> 其他业务模块
|
|
||||||
```
|
|
||||||
|
|
||||||
### 最小示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using AlicizaX.Resource.Runtime;
|
|
||||||
using Cysharp.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class BootstrapExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
IResourceService resourceService = GameApp.Resource;
|
|
||||||
await resourceService.InitPackageAsync();
|
|
||||||
await GameApp.UI.ShowUI<MainMenuWindow>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 6. 常见问题
|
|
||||||
|
|
||||||
### `GameApp.xxx` 为空
|
|
||||||
|
|
||||||
- 对应模块组件尚未挂载或未完成初始化。
|
|
||||||
- `RootModule` 尚未建立根服务容器。
|
|
||||||
- 获取时机早于模块注册阶段。
|
|
||||||
|
|
||||||
### UI 无法打开
|
|
||||||
|
|
||||||
- `UIComponent` 未配置 `UIRoot`。
|
|
||||||
- UI 资源路径或 `UIResAttribute` 配置错误。
|
|
||||||
- UI 绑定代码未生成,或 `UIWidget<T>` 泛型未引用正确的 Holder 类型。
|
|
||||||
|
|
||||||
### 资源加载失败
|
|
||||||
|
|
||||||
- 资源包尚未初始化。
|
|
||||||
- 资源路径与包内地址不一致。
|
|
||||||
- 运行环境缺少对应包或依赖资源。
|
|
||||||
|
|
||||||
## 7. 下一步
|
|
||||||
|
|
||||||
- 从 [Foundation](./Core/Foundation.md) 理解根模块与服务注册方式。
|
|
||||||
- 从 [Resource](./Runtime/Resource.md) 理解资源系统初始化与加载链路。
|
|
||||||
- 从 [UI](./Runtime/UI.md) 理解 UIHolder 自动生成、`UIWidget<T>` 绑定与窗口生命周期。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: edb42bd58f70a29419fef9babc8b6152
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6296361d31a52a045948fe1d9a074f6e
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
# Audio
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Audio 模块负责统一音频分类、音量控制、音频池与播放行为。它把音频拆分为音乐、音效、UI 音效、语音等类别,并支持使用 `AudioMixer` 做混音控制。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 场景挂载 `AudioComponent`
|
|
||||||
2. 配置 `AudioMixer`、实例根节点与 `AudioGroupConfig`
|
|
||||||
3. 通过 `GameApp.Audio` 播放音频
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using AlicizaX.Audio.Runtime;
|
|
||||||
|
|
||||||
public sealed class AudioQuickStart
|
|
||||||
{
|
|
||||||
public void PlayClick()
|
|
||||||
{
|
|
||||||
GameApp.Audio.Play(AudioType.UISound, "Audio/UI/Click");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
AudioComponent
|
|
||||||
└─ AudioService
|
|
||||||
├─ AudioCategory
|
|
||||||
├─ AudioAgent
|
|
||||||
├─ AudioGroupConfig
|
|
||||||
└─ AudioClipPool
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `IAudioService`
|
|
||||||
|
|
||||||
主要属性:
|
|
||||||
|
|
||||||
- `Volume`
|
|
||||||
- `Enable`
|
|
||||||
- `MusicVolume` / `SoundVolume` / `UISoundVolume` / `VoiceVolume`
|
|
||||||
- `MusicEnable` / `SoundEnable` / `UISoundEnable` / `VoiceEnable`
|
|
||||||
- `AudioMixer`
|
|
||||||
- `InstanceRoot`
|
|
||||||
|
|
||||||
主要方法:
|
|
||||||
|
|
||||||
- `Initialize(...)`
|
|
||||||
- `Play(...)`
|
|
||||||
- `Stop(...)`
|
|
||||||
- `StopAll(...)`
|
|
||||||
- `PutInAudioPool(...)`
|
|
||||||
- `CleanSoundPool()`
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `Initialize(AudioGroupConfig[] audioGroupConfigs, Transform instanceRoot = null, AudioMixer audioMixer = null)`
|
|
||||||
|
|
||||||
- 必填参数:`audioGroupConfigs`
|
|
||||||
- 可选参数:`instanceRoot`
|
|
||||||
- 可选参数:`audioMixer`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
### `Play(AudioType type, string path, bool bLoop = false, float volume = 1.0f, bool bAsync = false, bool bInPool = false)`
|
|
||||||
|
|
||||||
- 必填参数:`type`
|
|
||||||
- 必填参数:`path`
|
|
||||||
- 其余均为可选参数
|
|
||||||
- 返回值:`AudioAgent`
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using AlicizaX.Audio.Runtime;
|
|
||||||
|
|
||||||
public sealed class AudioExample
|
|
||||||
{
|
|
||||||
public void PlayBgm()
|
|
||||||
{
|
|
||||||
GameApp.Audio.MusicVolume = 0.8f;
|
|
||||||
GameApp.Audio.Play(AudioType.Music, "Audio/Bgm/MainTheme", true, 1f, true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 常用短音效建议预热
|
|
||||||
- 背景音乐和 UI 音效分混音组管理
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: bb1c0a7757fb6764392d1e5256e350ed
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,68 +0,0 @@
|
|||||||
# Debugger
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Debugger 模块提供运行时调试面板,可查看日志、FPS、系统信息、场景信息、对象池、运行时内存等。调试窗口采用树状注册方式,支持扩展自定义页面。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 场景挂载 `DebuggerComponent`
|
|
||||||
2. 选择激活策略 `DebuggerActiveWindowType`
|
|
||||||
3. 通过 `RegisterDebuggerWindow` 扩展自定义页面
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
DebuggerComponent
|
|
||||||
└─ DebuggerService
|
|
||||||
├─ IDebuggerWindowGroup
|
|
||||||
└─ IDebuggerWindow
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `IDebuggerService`
|
|
||||||
|
|
||||||
公开能力:
|
|
||||||
|
|
||||||
- `ActiveWindow`
|
|
||||||
- `DebuggerWindowRoot`
|
|
||||||
- `RegisterDebuggerWindow(...)`
|
|
||||||
- `UnregisterDebuggerWindow(...)`
|
|
||||||
- `GetDebuggerWindow(...)`
|
|
||||||
- `SelectDebuggerWindow(...)`
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args)`
|
|
||||||
|
|
||||||
- 必填参数:`path`
|
|
||||||
- 必填参数:`debuggerWindow`
|
|
||||||
- 可选参数:`args`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
### `UnregisterDebuggerWindow(string path)`
|
|
||||||
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.Debugger.Runtime;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class SimpleDebuggerWindow : IDebuggerWindow
|
|
||||||
{
|
|
||||||
public void Initialize(params object[] args) { }
|
|
||||||
public void Shutdown() { }
|
|
||||||
public void OnEnter() { }
|
|
||||||
public void OnLeave() { }
|
|
||||||
public void OnUpdate(float elapseSeconds, float realElapseSeconds) { }
|
|
||||||
public void OnDraw() => GUILayout.Label("Custom debug page");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 自定义窗口只放诊断信息
|
|
||||||
- 发布环境建议仅开发版开启
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 622e9f4d6de5d6f4d90bec501dcc2592
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
# Localization
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Localization 模块负责语言管理、本地化表装载、键值查询与格式化输出。它支持启动时加载内置表与资源表,也支持运行时异步切换语言。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 挂载 `LocalizationComponent`
|
|
||||||
2. 设置默认语言
|
|
||||||
3. 配置启动表或资源路径
|
|
||||||
4. 使用 `GameApp.Localization.GetString()`
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
|
|
||||||
public sealed class LocalizationQuickStart
|
|
||||||
{
|
|
||||||
public string GetTitle()
|
|
||||||
{
|
|
||||||
return GameApp.Localization.GetString("UI_Title");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
LocalizationComponent
|
|
||||||
└─ LocalizationService
|
|
||||||
├─ GameLocaizationTable
|
|
||||||
├─ LocalizationLanguage
|
|
||||||
└─ LocalizationChangeEvent
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `ILocalizationService`
|
|
||||||
|
|
||||||
公开能力:
|
|
||||||
|
|
||||||
- `Language`
|
|
||||||
- `Initialize(string language)`
|
|
||||||
- `ChangedLanguage(string language)`
|
|
||||||
- `SwitchLanguageAsync(string language, CancellationToken cancellationToken = default)`
|
|
||||||
- `GetString(...)`
|
|
||||||
- `TryGetRawString(...)`
|
|
||||||
- `CoverAddLocalizationConfig(...)`
|
|
||||||
- `IncreAddLocalizationConfig(...)`
|
|
||||||
- `ReloadLocalizationConfig(...)`
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `Initialize(string language)`
|
|
||||||
|
|
||||||
- 必填参数:`language`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
### `SwitchLanguageAsync(string language, CancellationToken cancellationToken = default)`
|
|
||||||
|
|
||||||
- 必填参数:`language`
|
|
||||||
- 可选参数:`cancellationToken`
|
|
||||||
- 返回值:`UniTask`
|
|
||||||
|
|
||||||
### `GetString(string key, params object[] args)`
|
|
||||||
|
|
||||||
- 必填参数:`key`
|
|
||||||
- 可选参数:`args`
|
|
||||||
- 返回值:`string`
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using Cysharp.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class LocalizationExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
Debug.Log(GameApp.Localization.GetString("UI_Start"));
|
|
||||||
await GameApp.Localization.SwitchLanguageAsync("English");
|
|
||||||
Debug.Log(GameApp.Localization.GetString("UI_Start"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 统一 Key 命名规则
|
|
||||||
- 语言切换事件中只做刷新,不做重资源初始化
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
- Key 不存在却未做兜底
|
|
||||||
- 资源服务未注册时依赖资源路径表
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5e7853f21507379449bb237975fb20ae
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
# Procedure
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Procedure 模块用于组织游戏主流程,如启动、登录、主城、战斗、结算等状态切换。它以 `ProcedureBase` 为模板方法基类,把生命周期拆成初始化、进入、离开、更新、销毁。
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 挂载 `ProcedureComponent`
|
|
||||||
2. 定义多个继承 `ProcedureBase` 的流程
|
|
||||||
3. 调用 `InitializeProcedure`
|
|
||||||
4. 通过 `SwitchProcedure<T>()` 切换
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
ProcedureComponent
|
|
||||||
└─ ProcedureService
|
|
||||||
├─ IProcedure
|
|
||||||
└─ ProcedureBase
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `IProcedureService`
|
|
||||||
|
|
||||||
公开能力:
|
|
||||||
|
|
||||||
- `CurrentProcedureType`
|
|
||||||
- `InitializeProcedure(...)`
|
|
||||||
- `ClearAllProcedures()`
|
|
||||||
- `ContainsProcedure(Type procedureType)`
|
|
||||||
- `TrySwitchProcedure(Type procedureType)`
|
|
||||||
|
|
||||||
### `ProcedureBase`
|
|
||||||
|
|
||||||
生命周期模板:
|
|
||||||
|
|
||||||
- `OnInit()`
|
|
||||||
- `OnEnter()`
|
|
||||||
- `OnLeave()`
|
|
||||||
- `OnUpdate()`
|
|
||||||
- `OnDestroy()`
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `InitializeProcedure(IEnumerable<IProcedure> availableProcedures, Type defaultProcedureType)`
|
|
||||||
|
|
||||||
- 必填参数:`availableProcedures`
|
|
||||||
- 必填参数:`defaultProcedureType`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
### `TrySwitchProcedure(Type procedureType)`
|
|
||||||
|
|
||||||
- 必填参数:`procedureType`
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
### `CurrentProcedureType`
|
|
||||||
|
|
||||||
- 返回值:`Type`
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using System;
|
|
||||||
using AlicizaX;
|
|
||||||
|
|
||||||
public sealed class BootProcedure : ProcedureBase
|
|
||||||
{
|
|
||||||
protected override void OnEnter()
|
|
||||||
{
|
|
||||||
SwitchProcedure<LoginProcedure>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class LoginProcedure : ProcedureBase
|
|
||||||
{
|
|
||||||
protected override void OnEnter()
|
|
||||||
{
|
|
||||||
Log.Info("Enter LoginProcedure");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ProcedureExample
|
|
||||||
{
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
GameApp.Procedure.InitializeProcedure(
|
|
||||||
new IProcedure[] { new BootProcedure(), new LoginProcedure() },
|
|
||||||
typeof(BootProcedure));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 一个流程只负责一个清晰状态
|
|
||||||
- 初始化逻辑放 `OnInit`,进入/退出逻辑放 `OnEnter` / `OnLeave`
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
- 未初始化就切换流程
|
|
||||||
- 把长时间并行任务塞入流程本身
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8e26efa856cdeb8458b10c02c655dad6
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,673 +0,0 @@
|
|||||||
# Resource
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Resource 模块基于 YooAsset 封装了资源包初始化、版本管理、资源查询、同步/异步加载、实例化、缓存回收与低内存处理能力。
|
|
||||||
|
|
||||||
它是多个模块的底层依赖:
|
|
||||||
|
|
||||||
- `UI`:加载窗口和 Widget 预制体
|
|
||||||
- `Audio`:加载音频资源
|
|
||||||
- `Localization`:加载语言表
|
|
||||||
- `GameObjectPool`:加载池对象原始 prefab
|
|
||||||
- `Scene`:主场景与附加场景的资源加载链路
|
|
||||||
|
|
||||||
从当前实现来看,`ResourceService` 还额外提供了:
|
|
||||||
|
|
||||||
- 多包管理
|
|
||||||
- 同一路径并发加载合并
|
|
||||||
- 资源对象池缓存
|
|
||||||
- 低内存时统一回收入口
|
|
||||||
- 下载、版本、清单更新能力
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 最少步骤
|
|
||||||
|
|
||||||
1. 在场景中挂载 `ResourceComponent`
|
|
||||||
2. 配置 `PlayMode`、默认包名和解密服务名
|
|
||||||
3. 游戏启动时调用 `InitPackageAsync`
|
|
||||||
4. 通过 `GameApp.Resource` 或 `AppServices.Require<IResourceService>()` 加载资源
|
|
||||||
|
|
||||||
### 最小示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class ResourceQuickStart : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
await GameApp.Resource.InitPackageAsync();
|
|
||||||
|
|
||||||
Texture2D icon = await GameApp.Resource.LoadAssetAsync<Texture2D>("UI/Common/Icon");
|
|
||||||
Debug.Log(icon != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
ResourceComponent
|
|
||||||
└─ ResourceService
|
|
||||||
├─ YooAsset PackageMap
|
|
||||||
├─ AssetInfo Cache
|
|
||||||
├─ AssetObject Pool
|
|
||||||
├─ Loading Operation Map
|
|
||||||
├─ Download / Version / Manifest
|
|
||||||
└─ ResourceExtComponent / AssetsReference
|
|
||||||
```
|
|
||||||
|
|
||||||
### 关键协作关系
|
|
||||||
|
|
||||||
- `ResourceComponent`:负责注册服务、配置运行模式并接管低内存回收节奏
|
|
||||||
- `ResourceService`:负责包初始化、加载、缓存和释放
|
|
||||||
- `AssetsReference`:负责把实例对象与源资源句柄关联起来,在对象销毁时自动释放源资源引用
|
|
||||||
- `ResourceExtComponent`:负责追踪资源绑定目标并分帧回收无引用资源
|
|
||||||
|
|
||||||
### 运行模式
|
|
||||||
|
|
||||||
当前实现支持以下 `PlayMode`:
|
|
||||||
|
|
||||||
- `EditorSimulateMode`
|
|
||||||
- `OfflinePlayMode`
|
|
||||||
- `HostPlayMode`
|
|
||||||
- `WebPlayMode`
|
|
||||||
|
|
||||||
不同模式决定初始化参数:
|
|
||||||
|
|
||||||
- **EditorSimulateMode**:编辑器模拟构建目录
|
|
||||||
- **OfflinePlayMode**:本地内置资源
|
|
||||||
- **HostPlayMode**:内置资源 + 缓存 + 远端下载
|
|
||||||
- **WebPlayMode**:Web 环境资源拉取方式
|
|
||||||
|
|
||||||
### 并发加载合并机制
|
|
||||||
|
|
||||||
`ResourceService` 内部使用 `_assetLoadingOperations` 合并同一路径的并发加载请求。
|
|
||||||
|
|
||||||
这意味着:
|
|
||||||
|
|
||||||
- 多个系统同时加载同一个资源时,不会重复发起多次底层加载
|
|
||||||
- 后来的请求会等待第一条加载链路完成,再复用结果
|
|
||||||
|
|
||||||
这对 UI 和公共图集资源特别有价值。
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `IResourceService`
|
|
||||||
|
|
||||||
该接口同时覆盖:
|
|
||||||
|
|
||||||
- 包初始化
|
|
||||||
- 包版本与清单管理
|
|
||||||
- 资源存在性检查
|
|
||||||
- 同步/异步加载
|
|
||||||
- 场景对象实例化
|
|
||||||
- 缓存清理
|
|
||||||
- 低内存回收
|
|
||||||
|
|
||||||
### `ResourceComponent`
|
|
||||||
|
|
||||||
它是 Resource 模块在场景中的入口组件,主要职责:
|
|
||||||
|
|
||||||
- 注册 `ResourceService`
|
|
||||||
- 配置默认包名 `PackageName`
|
|
||||||
- 设置运行模式 `PlayMode`
|
|
||||||
- 设置解密服务名 `decryptionServices`
|
|
||||||
- 设置资源对象池参数
|
|
||||||
- 接管 `Application.lowMemory` 事件
|
|
||||||
|
|
||||||
### `ResourceService`
|
|
||||||
|
|
||||||
从当前实现看,`ResourceService` 维护以下关键状态:
|
|
||||||
|
|
||||||
- `DefaultPackageName`
|
|
||||||
- `PlayMode`
|
|
||||||
- `PackageMap`
|
|
||||||
- `_assetInfoMap`
|
|
||||||
- `_assetLoadingOperations`
|
|
||||||
- `_assetPool`
|
|
||||||
|
|
||||||
### `AssetsReference`
|
|
||||||
|
|
||||||
这是实例对象与源资源句柄的桥接组件。
|
|
||||||
|
|
||||||
作用:
|
|
||||||
|
|
||||||
- 当你通过 `LoadGameObject` / `LoadGameObjectAsync` 实例化资源时
|
|
||||||
- 框架会在实例对象上自动挂一个 `AssetsReference`
|
|
||||||
- 当该实例对象销毁时,对应源资源引用会自动 `UnloadAsset`
|
|
||||||
|
|
||||||
这就是为什么:
|
|
||||||
|
|
||||||
- `LoadGameObject` 返回的实例对象通常不需要你手动 `UnloadAsset`
|
|
||||||
|
|
||||||
### `ResourceExtComponent`
|
|
||||||
|
|
||||||
主要用于:
|
|
||||||
|
|
||||||
- 追踪已绑定给 UI、Sprite 或其他目标对象的资源
|
|
||||||
- 自动清理已经失去引用的资源包装对象
|
|
||||||
- 以分帧方式做回收,降低一次性遍历成本
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
以下内容按使用频率分组说明。
|
|
||||||
|
|
||||||
### 一、初始化与运行配置
|
|
||||||
|
|
||||||
#### `void Initialize()`
|
|
||||||
|
|
||||||
- 参数:无
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:初始化 YooAsset、默认包与资产池
|
|
||||||
- 备注:通常由 `ResourceComponent.Start()` 自动调用
|
|
||||||
|
|
||||||
#### `UniTask<bool> InitPackageAsync(string packageName = "", string hostServerURL = "", string fallbackHostServerURL = "")`
|
|
||||||
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 可选参数:`hostServerURL`
|
|
||||||
- 可选参数:`fallbackHostServerURL`
|
|
||||||
- 返回值:`UniTask<bool>`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 初始化指定资源包
|
|
||||||
- 如果 `packageName` 为空,则使用 `DefaultPackageName`
|
|
||||||
- 在 Host/Web 模式下通常需要传入远端地址
|
|
||||||
|
|
||||||
异常与边界:
|
|
||||||
|
|
||||||
- 如果同一个包正在初始化或已成功初始化,会记录错误并直接返回失败结果
|
|
||||||
- 初始化失败时任务会抛出异常
|
|
||||||
|
|
||||||
#### `string DefaultPackageName { get; set; }`
|
|
||||||
|
|
||||||
- 说明:默认资源包名
|
|
||||||
- 推荐:整个项目统一默认包名约定
|
|
||||||
|
|
||||||
#### `EPlayMode PlayMode { get; set; }`
|
|
||||||
|
|
||||||
- 说明:资源系统运行模式
|
|
||||||
- 注意:Editor 与真机配置往往不同
|
|
||||||
|
|
||||||
#### `string DecryptionServices { get; set; }`
|
|
||||||
|
|
||||||
- 说明:解密服务类型名
|
|
||||||
- 注意:该值应是可被反射创建的类型全名
|
|
||||||
|
|
||||||
#### `bool AutoUnloadBundleWhenUnused { get; set; }`
|
|
||||||
|
|
||||||
- 说明:初始化参数中的自动卸载选项
|
|
||||||
|
|
||||||
### 二、版本与下载管理
|
|
||||||
|
|
||||||
#### `string GetPackageVersion(string customPackageName = "")`
|
|
||||||
|
|
||||||
- 可选参数:`customPackageName`
|
|
||||||
- 返回值:包版本字符串
|
|
||||||
|
|
||||||
#### `RequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks = false, int timeout = 60, string customPackageName = "")`
|
|
||||||
|
|
||||||
- 可选参数:`appendTimeTicks`
|
|
||||||
- 可选参数:`timeout`
|
|
||||||
- 可选参数:`customPackageName`
|
|
||||||
- 返回值:`RequestPackageVersionOperation`
|
|
||||||
|
|
||||||
#### `UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout = 60, string customPackageName = "")`
|
|
||||||
|
|
||||||
- 必填参数:`packageVersion`
|
|
||||||
- 可选参数:`timeout`
|
|
||||||
- 可选参数:`customPackageName`
|
|
||||||
- 返回值:`UpdatePackageManifestOperation`
|
|
||||||
|
|
||||||
#### `ResourceDownloaderOperation CreateResourceDownloader(string customPackageName = "")`
|
|
||||||
|
|
||||||
- 可选参数:`customPackageName`
|
|
||||||
- 返回值:`ResourceDownloaderOperation`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 会使用当前 `DownloadingMaxNum` 和 `FailedTryAgain`
|
|
||||||
|
|
||||||
### 三、资源查询
|
|
||||||
|
|
||||||
#### `HasAssetResult HasAsset(string location, string packageName = "")`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 返回值:`HasAssetResult`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 用于判断资源是否存在、是否在本地、是否需要远端下载
|
|
||||||
|
|
||||||
注意:
|
|
||||||
|
|
||||||
- 如果 `location` 为空会抛异常
|
|
||||||
|
|
||||||
#### `bool CheckLocationValid(string location, string packageName = "")`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
#### `AssetInfo GetAssetInfo(string location, string packageName = "")`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 返回值:`AssetInfo`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 内部带有 `_assetInfoMap` 缓存
|
|
||||||
- 同一路径重复获取成本较低
|
|
||||||
|
|
||||||
### 四、同步加载
|
|
||||||
|
|
||||||
#### `T LoadAsset<T>(string location, string packageName = "") where T : UnityEngine.Object`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 返回值:`T`
|
|
||||||
- 泛型约束:`T : UnityEngine.Object`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 同步加载资源
|
|
||||||
- 首次加载会进入资源池缓存
|
|
||||||
- 重复获取相同资源时会优先从 `_assetPool` 中复用
|
|
||||||
|
|
||||||
#### `GameObject LoadGameObject(string location, Transform parent = null, string packageName = "")`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`parent`
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 返回值:`GameObject`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 同步加载 prefab 并实例化
|
|
||||||
- 实例对象会自动挂 `AssetsReference`
|
|
||||||
- 销毁实例时会自动释放源资源引用
|
|
||||||
|
|
||||||
### 五、异步加载
|
|
||||||
|
|
||||||
#### `UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default, string packageName = "") where T : UnityEngine.Object`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`cancellationToken`
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 返回值:`UniTask<T>`
|
|
||||||
|
|
||||||
#### `UniTask<GameObject> LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default, string packageName = "")`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`parent`
|
|
||||||
- 可选参数:`cancellationToken`
|
|
||||||
- 可选参数:`packageName`
|
|
||||||
- 返回值:`UniTask<GameObject>`
|
|
||||||
|
|
||||||
### 六、回调式加载
|
|
||||||
|
|
||||||
#### `UniTask LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")`
|
|
||||||
|
|
||||||
#### `UniTask LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")`
|
|
||||||
|
|
||||||
`LoadAssetCallbacks` 中的回调签名:
|
|
||||||
|
|
||||||
- 成功:`(string assetName, object asset, float duration, object userData)`
|
|
||||||
- 失败:`(string assetName, LoadResourceStatus status, string errorMessage, object userData)`
|
|
||||||
- 进度:`(string assetName, float progress, object userData)`
|
|
||||||
|
|
||||||
适合:
|
|
||||||
|
|
||||||
- 旧式回调链
|
|
||||||
- 想同时观察进度与错误
|
|
||||||
- 不方便直接 `await` 的场景
|
|
||||||
|
|
||||||
### 七、句柄接口
|
|
||||||
|
|
||||||
#### `AssetHandle LoadAssetSyncHandle<T>(string location, string packageName = "") where T : UnityEngine.Object`
|
|
||||||
|
|
||||||
#### `AssetHandle LoadAssetAsyncHandle<T>(string location, string packageName = "") where T : UnityEngine.Object`
|
|
||||||
|
|
||||||
适合:
|
|
||||||
|
|
||||||
- 需要直接管理底层句柄
|
|
||||||
- 需要和 YooAsset 句柄 API 配合
|
|
||||||
|
|
||||||
### 八、释放与回收
|
|
||||||
|
|
||||||
#### `void UnloadAsset(object asset)`
|
|
||||||
|
|
||||||
- 必填参数:`asset`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 本质上是把资源对象从 `_assetPool` 中 `Unspawn`
|
|
||||||
|
|
||||||
#### `void UnloadUnusedAssets()`
|
|
||||||
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 释放资源对象池中未使用的对象
|
|
||||||
- 并对所有已成功初始化的包执行 `UnloadUnusedAssetsAsync`
|
|
||||||
|
|
||||||
#### `void ForceUnloadAllAssets()`
|
|
||||||
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 强制卸载所有资源
|
|
||||||
- WebGL 下会直接警告并退出
|
|
||||||
|
|
||||||
#### `void ForceUnloadUnusedAssets(bool performGCCollect)`
|
|
||||||
|
|
||||||
- 必填参数:`performGCCollect`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 委托给 `ResourceComponent` 控制实际的系统资源回收时机
|
|
||||||
|
|
||||||
## 常见用法
|
|
||||||
|
|
||||||
### 1. 初始化默认包
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using AlicizaX.Resource.Runtime;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class ResourceInitExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
bool ok = await GameApp.Resource.InitPackageAsync();
|
|
||||||
Debug.Log($"Init default package success: {ok}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 初始化远端包
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class HostModeInitExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
await GameApp.Resource.InitPackageAsync(
|
|
||||||
packageName: "DefaultPackage",
|
|
||||||
hostServerURL: "https://cdn.example.com/game",
|
|
||||||
fallbackHostServerURL: "https://backup.example.com/game");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 同步加载配置资源
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class SyncLoadExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
TextAsset config = GameApp.Resource.LoadAsset<TextAsset>("Config/GameBalance");
|
|
||||||
Debug.Log(config != null ? config.text : "Config missing");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 异步加载图片资源
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class AsyncLoadExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
Sprite sprite = await GameApp.Resource.LoadAssetAsync<Sprite>("UI/Common/Atlas/Icon_Star");
|
|
||||||
Debug.Log(sprite != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 加载并实例化 GameObject
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class InstantiateExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private GameObject _hero;
|
|
||||||
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
_hero = await GameApp.Resource.LoadGameObjectAsync("Character/Hero.prefab", transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
if (_hero != null)
|
|
||||||
{
|
|
||||||
Destroy(_hero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 这里不需要对 `_hero` 再调用 `UnloadAsset`
|
|
||||||
- 销毁实例时 `AssetsReference` 会自动释放源资源引用
|
|
||||||
|
|
||||||
### 6. 使用回调式加载并监听进度
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using AlicizaX.Resource.Runtime;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class CallbackLoadExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
var callbacks = new LoadAssetCallbacks(
|
|
||||||
(assetName, asset, duration, userData) =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Load success: {assetName}, duration: {duration:F3}s");
|
|
||||||
},
|
|
||||||
(assetName, status, errorMessage, userData) =>
|
|
||||||
{
|
|
||||||
Debug.LogError($"Load failed: {assetName}, {status}, {errorMessage}");
|
|
||||||
},
|
|
||||||
(assetName, progress, userData) =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Progress {assetName}: {progress:P0}");
|
|
||||||
});
|
|
||||||
|
|
||||||
await GameApp.Resource.LoadAssetAsync(
|
|
||||||
"UI/Common/Icon",
|
|
||||||
priority: 0,
|
|
||||||
loadAssetCallbacks: callbacks,
|
|
||||||
userData: null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. 下载资源版本并更新清单
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class UpdateManifestExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
var versionOp = GameApp.Resource.RequestPackageVersionAsync();
|
|
||||||
await versionOp.ToUniTask();
|
|
||||||
|
|
||||||
if (versionOp.Status == YooAsset.EOperationStatus.Succeed)
|
|
||||||
{
|
|
||||||
string version = versionOp.PackageVersion;
|
|
||||||
var manifestOp = GameApp.Resource.UpdatePackageManifestAsync(version);
|
|
||||||
await manifestOp.ToUniTask();
|
|
||||||
Debug.Log($"Manifest updated to: {version}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8. 创建下载器
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class DownloaderExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
var downloader = GameApp.Resource.CreateResourceDownloader();
|
|
||||||
downloader.BeginDownload();
|
|
||||||
await downloader.ToUniTask();
|
|
||||||
Debug.Log($"Download status: {downloader.Status}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 运行行为细节
|
|
||||||
|
|
||||||
### 1. 重复加载同一路径会优先复用缓存
|
|
||||||
|
|
||||||
当前实现通过 `_assetPool` 保存 `AssetObject`,同一路径的资源会复用池内对象。
|
|
||||||
|
|
||||||
好处:
|
|
||||||
|
|
||||||
- 减少重复加载
|
|
||||||
- 降低频繁生成/销毁底层句柄的开销
|
|
||||||
|
|
||||||
### 2. 并发同路径加载会合并请求
|
|
||||||
|
|
||||||
如果同一路径资源正在加载中:
|
|
||||||
|
|
||||||
- 后续请求不会重复发起底层加载
|
|
||||||
- 会等待首个请求完成后再复用结果
|
|
||||||
|
|
||||||
### 3. `LoadGameObject` 与 `LoadAsset<T>` 的释放语义不同
|
|
||||||
|
|
||||||
#### `LoadAsset<T>`
|
|
||||||
|
|
||||||
- 返回的是资源对象本身
|
|
||||||
- 如有需要可以显式 `UnloadAsset(asset)`
|
|
||||||
|
|
||||||
#### `LoadGameObject`
|
|
||||||
|
|
||||||
- 返回的是实例化后的场景对象
|
|
||||||
- 源 prefab 资源句柄通过 `AssetsReference` 绑定到实例对象
|
|
||||||
- 通常直接 `Destroy(instance)` 即可
|
|
||||||
|
|
||||||
### 4. 低内存行为
|
|
||||||
|
|
||||||
触发 `OnLowMemory()` 时:
|
|
||||||
|
|
||||||
- 会调用 `_forceUnloadUnusedAssetsAction`
|
|
||||||
- 实际清理由 `ResourceComponent` 驱动
|
|
||||||
|
|
||||||
### 5. `AssetInfo` 有内部缓存
|
|
||||||
|
|
||||||
多次 `GetAssetInfo` 会命中 `_assetInfoMap`
|
|
||||||
|
|
||||||
适合:
|
|
||||||
|
|
||||||
- 频繁查询资源合法性
|
|
||||||
- UI 打开前做路径校验
|
|
||||||
|
|
||||||
### 6. 失败行为
|
|
||||||
|
|
||||||
以下情况通常会导致异常或错误日志:
|
|
||||||
|
|
||||||
- 资源路径为空
|
|
||||||
- 包不存在
|
|
||||||
- 资源定位无效
|
|
||||||
- 初始化失败
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 统一资源路径规范,避免大小写和目录命名混乱
|
|
||||||
- 默认优先异步加载
|
|
||||||
- 把“包初始化 / 版本更新 / 资源下载 / 资源使用”分成不同阶段处理
|
|
||||||
- UI、音频、图集等高复用资源尽量走缓存复用
|
|
||||||
- 对需要长期驻留的资源,业务层要明确生命周期,不要频繁反复加载
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
### 1. 包未初始化就加载资源
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 资源查找失败
|
|
||||||
- 返回空对象或直接异常
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- 确保启动流程中先执行 `InitPackageAsync`
|
|
||||||
|
|
||||||
### 2. 默认包名与实际包名不一致
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 路径正确但查不到资源
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- 统一 `DefaultPackageName`
|
|
||||||
- 多包场景显式传入 `packageName`
|
|
||||||
|
|
||||||
### 3. 手动 `UnloadAsset` 已实例化场景对象
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 语义不清晰
|
|
||||||
- 可能导致资源生命周期混乱
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- `LoadGameObject` 返回的实例优先 `Destroy`
|
|
||||||
|
|
||||||
### 4. 解密服务类型名错误
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 初始化时反射失败
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- `DecryptionServices` 必须是可反射创建的完整类型名
|
|
||||||
|
|
||||||
## 性能注意事项
|
|
||||||
|
|
||||||
- 避免在主线程大量同步加载
|
|
||||||
- 常用资源优先缓存复用
|
|
||||||
- 合理设置:
|
|
||||||
- `AssetAutoReleaseInterval`
|
|
||||||
- `AssetCapacity`
|
|
||||||
- `AssetExpireTime`
|
|
||||||
- `AssetPriority`
|
|
||||||
- 高并发异步加载时,优先复用路径和包配置,发挥内部合并机制优势
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: df8519e09d84ea34b8ffd2c4b93c21f9
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,477 +0,0 @@
|
|||||||
# Scene
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Scene 模块负责:
|
|
||||||
|
|
||||||
- 主场景加载
|
|
||||||
- Additive 子场景加载
|
|
||||||
- 延迟激活与解除挂起
|
|
||||||
- 子场景卸载
|
|
||||||
- 主场景状态追踪
|
|
||||||
- 场景作用域(Scene Scope)建立与重置
|
|
||||||
|
|
||||||
它不是 Unity 默认 `SceneManager` 的简单封装,而是把场景切换与框架服务作用域绑定在一起。
|
|
||||||
|
|
||||||
这意味着:
|
|
||||||
|
|
||||||
- **加载主场景时,会重置 Scene Scope**
|
|
||||||
- **加载 Additive 子场景时,不会重置主场景状态**
|
|
||||||
- **主场景和子场景在框架内是两套不同语义**
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 最少步骤
|
|
||||||
|
|
||||||
1. 在场景中挂载 `SceneComponent`
|
|
||||||
2. 确保 `ResourceComponent` 已可用
|
|
||||||
3. 通过 `GameApp.Scene.LoadSceneAsync(...)` 加载场景
|
|
||||||
4. 如需卸载 Additive 场景,调用 `UnloadAsync(...)`
|
|
||||||
|
|
||||||
### 最小示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
public sealed class SceneQuickStart
|
|
||||||
{
|
|
||||||
public async void Load()
|
|
||||||
{
|
|
||||||
await GameApp.Scene.LoadSceneAsync("Scene/Battle", LoadSceneMode.Single);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
SceneComponent
|
|
||||||
└─ SceneService
|
|
||||||
└─ SceneDomainStateService
|
|
||||||
├─ CurrentMainSceneName
|
|
||||||
├─ CurrentMainSceneHandle
|
|
||||||
├─ SubScene Map
|
|
||||||
└─ Handling Scene Set
|
|
||||||
```
|
|
||||||
|
|
||||||
### 关键协作关系
|
|
||||||
|
|
||||||
- `SceneComponent`:注册 `SceneService` 并确保 Scene Scope 存在
|
|
||||||
- `SceneService`:处理加载、激活、卸载与状态切换
|
|
||||||
- `SceneDomainStateService`:记录当前主场景、子场景和处理中场景
|
|
||||||
- `IResourceService`:主场景切换完成后触发资源回收
|
|
||||||
|
|
||||||
### 主场景与子场景的区别
|
|
||||||
|
|
||||||
#### 主场景(Main Scene)
|
|
||||||
|
|
||||||
- 通过 `LoadSceneMode.Single` 加载
|
|
||||||
- 加载前会重置 Scene Scope
|
|
||||||
- 加载完成后更新 `CurrentMainSceneName`
|
|
||||||
- 切换完成后会触发一次资源回收
|
|
||||||
|
|
||||||
#### 子场景(Sub Scene / Additive)
|
|
||||||
|
|
||||||
- 通过 `LoadSceneMode.Additive` 加载
|
|
||||||
- 记录在 `_subScenes` 字典中
|
|
||||||
- 可通过 `UnloadAsync(location)` 卸载
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `ISceneService`
|
|
||||||
|
|
||||||
公开能力:
|
|
||||||
|
|
||||||
- `CurrentMainSceneName`
|
|
||||||
- `LoadSceneAsync(...)`
|
|
||||||
- `LoadScene(...)`
|
|
||||||
- `ActivateScene(string location)`
|
|
||||||
- `UnSuspend(string location)`
|
|
||||||
- `IsMainScene(string location)`
|
|
||||||
- `UnloadAsync(string location, Action<float> progressCallBack = null)`
|
|
||||||
- `Unload(string location, Action callBack = null, Action<float> progressCallBack = null)`
|
|
||||||
- `IsContainScene(string location)`
|
|
||||||
|
|
||||||
### `ISceneStateService`
|
|
||||||
|
|
||||||
偏状态查询接口,主要用于:
|
|
||||||
|
|
||||||
- 查询当前主场景
|
|
||||||
- 查询某个场景是否已记录在当前 Scene Scope 中
|
|
||||||
|
|
||||||
### `SceneDomainStateService`
|
|
||||||
|
|
||||||
当前实现中负责维护:
|
|
||||||
|
|
||||||
- `CurrentMainSceneName`
|
|
||||||
- `CurrentMainSceneHandle`
|
|
||||||
- `_subScenes`
|
|
||||||
- `_handlingScenes`
|
|
||||||
|
|
||||||
用途:
|
|
||||||
|
|
||||||
- 避免同一场景重复并发加载/卸载
|
|
||||||
- 为 `IsContainScene` / `IsMainScene` 提供判断基础
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### 一、场景加载
|
|
||||||
|
|
||||||
#### `UniTask<Scene> LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, uint priority = 100, bool gcCollect = true, Action<float> progressCallBack = null)`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`sceneMode`
|
|
||||||
- 可选参数:`suspendLoad`
|
|
||||||
- 可选参数:`priority`
|
|
||||||
- 可选参数:`gcCollect`
|
|
||||||
- 可选参数:`progressCallBack`
|
|
||||||
- 返回值:`UniTask<UnityEngine.SceneManagement.Scene>`
|
|
||||||
|
|
||||||
参数说明:
|
|
||||||
|
|
||||||
- `location`:场景资源定位地址
|
|
||||||
- `sceneMode`:`Single` 或 `Additive`
|
|
||||||
- `suspendLoad`:是否挂起加载后的激活
|
|
||||||
- `priority`:加载优先级
|
|
||||||
- `gcCollect`:主场景切换后是否执行资源回收
|
|
||||||
- `progressCallBack`:加载进度回调
|
|
||||||
|
|
||||||
行为说明:
|
|
||||||
|
|
||||||
- `Single`:会重置当前 Scene Scope
|
|
||||||
- `Additive`:会作为子场景注册
|
|
||||||
- 如果同一场景正在处理,当前实现会记录错误并返回默认值
|
|
||||||
|
|
||||||
#### `void LoadScene(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, uint priority = 100, Action<Scene> callBack = null, bool gcCollect = true, Action<float> progressCallBack = null)`
|
|
||||||
|
|
||||||
- 注意:这个方法**不是同步加载**
|
|
||||||
- 本质上仍是异步加载,只是使用回调而不是 `await`
|
|
||||||
|
|
||||||
推荐:
|
|
||||||
|
|
||||||
- 新代码优先使用 `LoadSceneAsync`
|
|
||||||
|
|
||||||
### 二、场景激活与挂起
|
|
||||||
|
|
||||||
#### `bool ActivateScene(string location)`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 对应场景已被挂起时,尝试激活它
|
|
||||||
- 可用于 `suspendLoad = true` 的场景
|
|
||||||
|
|
||||||
#### `bool UnSuspend(string location)`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 解除场景挂起
|
|
||||||
- 语义接近 `ActivateScene`
|
|
||||||
|
|
||||||
### 三、场景查询
|
|
||||||
|
|
||||||
#### `bool IsMainScene(string location)`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 判断给定场景是否为当前主场景
|
|
||||||
- 内部结合 `SceneDomainStateService` 与 `SceneManager.GetActiveScene()` 做判断
|
|
||||||
|
|
||||||
#### `bool IsContainScene(string location)`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 判断当前主场景或子场景列表中是否包含该场景
|
|
||||||
|
|
||||||
#### `string CurrentMainSceneName`
|
|
||||||
|
|
||||||
- 返回值:主场景名
|
|
||||||
|
|
||||||
### 四、场景卸载
|
|
||||||
|
|
||||||
#### `UniTask<bool> UnloadAsync(string location, Action<float> progressCallBack = null)`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`progressCallBack`
|
|
||||||
- 返回值:`UniTask<bool>`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 用于卸载 Additive 子场景
|
|
||||||
- 当前实现**不用于直接卸载主场景**
|
|
||||||
|
|
||||||
#### `void Unload(string location, Action callBack = null, Action<float> progressCallBack = null)`
|
|
||||||
|
|
||||||
- 必填参数:`location`
|
|
||||||
- 可选参数:`callBack`
|
|
||||||
- 可选参数:`progressCallBack`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 回调式异步卸载
|
|
||||||
|
|
||||||
## 常见用法
|
|
||||||
|
|
||||||
### 1. 加载主场景
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
public sealed class LoadMainSceneExample
|
|
||||||
{
|
|
||||||
public async void GoBattle()
|
|
||||||
{
|
|
||||||
await GameApp.Scene.LoadSceneAsync("Scene/Battle", LoadSceneMode.Single);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Additive 加载子场景
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
public sealed class AdditiveSceneExample
|
|
||||||
{
|
|
||||||
public async void OpenSubScene()
|
|
||||||
{
|
|
||||||
await GameApp.Scene.LoadSceneAsync("Scene/PhotoRoom", LoadSceneMode.Additive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 卸载 Additive 子场景
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
|
|
||||||
public sealed class UnloadSubSceneExample
|
|
||||||
{
|
|
||||||
public async void CloseSubScene()
|
|
||||||
{
|
|
||||||
if (GameApp.Scene.IsContainScene("Scene/PhotoRoom"))
|
|
||||||
{
|
|
||||||
bool ok = await GameApp.Scene.UnloadAsync("Scene/PhotoRoom");
|
|
||||||
UnityEngine.Debug.Log($"Unload result: {ok}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 带进度的场景加载
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
public sealed class SceneProgressExample
|
|
||||||
{
|
|
||||||
public async void LoadWithProgress()
|
|
||||||
{
|
|
||||||
await GameApp.Scene.LoadSceneAsync(
|
|
||||||
"Scene/Battle",
|
|
||||||
LoadSceneMode.Single,
|
|
||||||
suspendLoad: false,
|
|
||||||
priority: 100,
|
|
||||||
gcCollect: true,
|
|
||||||
progressCallBack: progress =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Scene progress: {progress:P0}");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 挂起加载后手动激活
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
public sealed class SuspendLoadExample
|
|
||||||
{
|
|
||||||
public async void LoadThenActivate()
|
|
||||||
{
|
|
||||||
await GameApp.Scene.LoadSceneAsync(
|
|
||||||
"Scene/Battle",
|
|
||||||
LoadSceneMode.Single,
|
|
||||||
suspendLoad: true);
|
|
||||||
|
|
||||||
GameApp.Scene.ActivateScene("Scene/Battle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 使用回调式加载
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
public sealed class SceneCallbackExample
|
|
||||||
{
|
|
||||||
public void LoadLobby()
|
|
||||||
{
|
|
||||||
GameApp.Scene.LoadScene(
|
|
||||||
"Scene/Lobby",
|
|
||||||
LoadSceneMode.Single,
|
|
||||||
suspendLoad: false,
|
|
||||||
priority: 100,
|
|
||||||
callBack: scene =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Loaded scene: {scene.name}");
|
|
||||||
},
|
|
||||||
gcCollect: true,
|
|
||||||
progressCallBack: progress =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Loading: {progress:P0}");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. 查询当前主场景
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class SceneStateExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
Debug.Log($"Main Scene: {GameApp.Scene.CurrentMainSceneName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 运行行为细节
|
|
||||||
|
|
||||||
### 1. 主场景加载会重置 Scene Scope
|
|
||||||
|
|
||||||
这是本模块最重要的设计点之一。
|
|
||||||
|
|
||||||
当调用:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
GameApp.Scene.LoadSceneAsync("Scene/Battle", LoadSceneMode.Single)
|
|
||||||
```
|
|
||||||
|
|
||||||
内部会:
|
|
||||||
|
|
||||||
1. `Context.ResetScene()`
|
|
||||||
2. 重新注册 `SceneDomainStateService`
|
|
||||||
3. 标记新主场景进入加载中
|
|
||||||
|
|
||||||
这意味着:
|
|
||||||
|
|
||||||
- 旧的 Scene Scope 服务会被重建
|
|
||||||
- 与旧主场景强绑定的场景级服务也应重新初始化
|
|
||||||
|
|
||||||
### 2. Additive 场景不会重置主场景作用域
|
|
||||||
|
|
||||||
使用 `LoadSceneMode.Additive` 时:
|
|
||||||
|
|
||||||
- 场景会被加入 `_subScenes`
|
|
||||||
- 主场景状态保留
|
|
||||||
- 适合加载摄影间、剧情副场景、临时房间等
|
|
||||||
|
|
||||||
### 3. `UnloadAsync` 只对 Additive 子场景有效
|
|
||||||
|
|
||||||
当前实现中:
|
|
||||||
|
|
||||||
- 只有 `_subScenes` 中登记的场景才会走卸载逻辑
|
|
||||||
- 主场景切换依赖新的 `LoadScene(Single)`,而不是单独 `Unload` 主场景
|
|
||||||
|
|
||||||
### 4. 同一场景并发处理会被拦截
|
|
||||||
|
|
||||||
`SceneDomainStateService` 会使用 `_handlingScenes` 记录“正在加载/卸载”的场景。
|
|
||||||
|
|
||||||
效果:
|
|
||||||
|
|
||||||
- 避免同一路径重复加载或重复卸载
|
|
||||||
- 减少状态错乱
|
|
||||||
|
|
||||||
### 5. 主场景加载完成后会触发资源回收
|
|
||||||
|
|
||||||
当主场景切换完成后,会调用:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
Context.Require<IResourceService>().ForceUnloadUnusedAssets(gcCollect);
|
|
||||||
```
|
|
||||||
|
|
||||||
因此:
|
|
||||||
|
|
||||||
- 场景切换是资源回收的重要时间点
|
|
||||||
- `gcCollect` 参数会影响切场景后的回收强度
|
|
||||||
|
|
||||||
### 6. `LoadScene` 方法名容易误导
|
|
||||||
|
|
||||||
虽然名字像“同步加载”,但当前实现中:
|
|
||||||
|
|
||||||
- `LoadScene(...)` 仍然是异步加载
|
|
||||||
- 区别只是它通过回调返回结果,而不是 `await`
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- 主场景切换统一交给流程层管理
|
|
||||||
- Additive 场景只用于临时叠加内容,不要滥用为主流程状态切换
|
|
||||||
- 若需要加载转场动画,可用 `suspendLoad = true` + 手动激活
|
|
||||||
- 场景切换后如有场景级服务初始化,放在新的 Scene Scope 生命周期里完成
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
### 1. 试图用 `UnloadAsync` 卸载主场景
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 返回 `false` 或警告
|
|
||||||
|
|
||||||
正确方式:
|
|
||||||
|
|
||||||
- 通过加载新的 `Single` 主场景来替换
|
|
||||||
|
|
||||||
### 2. 把 `LoadScene(...)` 当同步函数使用
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 加载还没完成就执行后续依赖逻辑
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- 优先使用 `LoadSceneAsync(...)`
|
|
||||||
- 或把后续逻辑写入回调中
|
|
||||||
|
|
||||||
### 3. 重复 Additive 加载同一场景
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 异步版可能直接抛异常
|
|
||||||
- 回调版会记录警告
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- 在加载前先用 `IsContainScene(location)` 做检查
|
|
||||||
|
|
||||||
## 性能注意事项
|
|
||||||
|
|
||||||
- 场景切换本身是重量级操作,不要把短生命周期面板式内容做成 Additive 场景
|
|
||||||
- 进度回调每帧执行,UI 刷新时应尽量轻量
|
|
||||||
- 主场景切换后伴随资源回收,切场景阶段要预估回收开销和 GC 波动
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 13866105ba2b78a4688dbb55ad947045
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,672 +0,0 @@
|
|||||||
# Timer
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
Timer 模块提供统一定时器服务,适合处理:
|
|
||||||
|
|
||||||
- 延时执行
|
|
||||||
- 循环轮询
|
|
||||||
- UI 倒计时
|
|
||||||
- 技能延时结算
|
|
||||||
- 超时控制
|
|
||||||
- 轻量轮询逻辑
|
|
||||||
|
|
||||||
它由 `TimerComponent` 注册 `TimerService`,并通过 `GameApp.Timer` 或 `AppServices.Require<ITimerService>()` 暴露给业务层。
|
|
||||||
|
|
||||||
从实现上看,`TimerService` 使用时间轮来管理定时器,重点优化的是:
|
|
||||||
|
|
||||||
- 大量定时器的调度效率
|
|
||||||
- 低 GC 的回调执行
|
|
||||||
- 支持缩放时间和非缩放时间两套时间基准
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 最少步骤
|
|
||||||
|
|
||||||
1. 在场景中挂载 `TimerComponent`
|
|
||||||
2. 调用 `GameApp.Timer.AddTimer(...)`
|
|
||||||
3. 保存返回的 `timerId`
|
|
||||||
4. 在对象销毁或逻辑结束时调用 `RemoveTimer(timerId)`
|
|
||||||
|
|
||||||
### 最小示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class TimerQuickStart : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _timerId;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_timerId = GameApp.Timer.AddTimer(OnTick, 1f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTick()
|
|
||||||
{
|
|
||||||
Debug.Log("Tick");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
TimerComponent
|
|
||||||
└─ TimerService
|
|
||||||
├─ TimerHandler
|
|
||||||
├─ TimerHandlerNoArgs
|
|
||||||
├─ TimerGenericInvokerCache<T>
|
|
||||||
└─ HierarchicalTimeWheel
|
|
||||||
```
|
|
||||||
|
|
||||||
### 关键协作关系
|
|
||||||
|
|
||||||
- `TimerComponent`:负责在场景中注册 `TimerService`
|
|
||||||
- `TimerService`:真正执行定时调度
|
|
||||||
- `ITimerService`:业务层使用的统一接口
|
|
||||||
- `GameApp.Timer`:高频调用入口
|
|
||||||
|
|
||||||
### 时间基准
|
|
||||||
|
|
||||||
Timer 模块支持两种时间基准:
|
|
||||||
|
|
||||||
- **缩放时间**:使用 `Time.time`
|
|
||||||
- **非缩放时间**:使用 `Time.unscaledTime`
|
|
||||||
|
|
||||||
这由 `isUnscaled` 参数控制:
|
|
||||||
|
|
||||||
- `false`:受 `Time.timeScale` 影响
|
|
||||||
- `true`:不受 `Time.timeScale` 影响
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `ITimerService`
|
|
||||||
|
|
||||||
公开能力:
|
|
||||||
|
|
||||||
- `AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args)`
|
|
||||||
- `AddTimer(TimerHandlerNoArgs callback, float time, bool isLoop = false, bool isUnscaled = false)`
|
|
||||||
- `AddTimer<T>(Action<T> callback, T arg, float time, bool isLoop = false, bool isUnscaled = false)`
|
|
||||||
- `Stop(int timerId)`
|
|
||||||
- `Resume(int timerId)`
|
|
||||||
- `IsRunning(int timerId)`
|
|
||||||
- `GetLeftTime(int timerId)`
|
|
||||||
- `Restart(int timerId)`
|
|
||||||
- `RemoveTimer(int timerId)`
|
|
||||||
- `RemoveAllTimer()`
|
|
||||||
|
|
||||||
### `TimerHandler`
|
|
||||||
|
|
||||||
定义:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public delegate void TimerHandler(params object[] args);
|
|
||||||
```
|
|
||||||
|
|
||||||
适合:
|
|
||||||
|
|
||||||
- 参数数量不固定
|
|
||||||
- 通用回调
|
|
||||||
- 快速搭建原型
|
|
||||||
|
|
||||||
### `TimerHandlerNoArgs`
|
|
||||||
|
|
||||||
定义:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public delegate void TimerHandlerNoArgs();
|
|
||||||
```
|
|
||||||
|
|
||||||
适合:
|
|
||||||
|
|
||||||
- 无参延时执行
|
|
||||||
- 最常见的循环 tick
|
|
||||||
|
|
||||||
### 泛型 `AddTimer<T>`
|
|
||||||
|
|
||||||
适合:
|
|
||||||
|
|
||||||
- 单参数且类型明确的回调
|
|
||||||
- 希望避免 `object[]` 拆装箱和手动转换
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args)`
|
|
||||||
|
|
||||||
- 必填参数:`callback`
|
|
||||||
- 必填参数:`time`
|
|
||||||
- 可选参数:`isLoop`
|
|
||||||
- 可选参数:`isUnscaled`
|
|
||||||
- 可选参数:`args`
|
|
||||||
- 返回值:`timerId`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 注册一个支持参数数组的定时器
|
|
||||||
- `time` 为延迟秒数
|
|
||||||
- `isLoop = true` 时会按相同间隔循环触发
|
|
||||||
|
|
||||||
适合:
|
|
||||||
|
|
||||||
- 参数个数可变
|
|
||||||
- 临时逻辑
|
|
||||||
- 不想额外声明泛型回调的场景
|
|
||||||
|
|
||||||
### `int AddTimer(TimerHandlerNoArgs callback, float time, bool isLoop = false, bool isUnscaled = false)`
|
|
||||||
|
|
||||||
- 必填参数:`callback`
|
|
||||||
- 必填参数:`time`
|
|
||||||
- 可选参数:`isLoop`
|
|
||||||
- 可选参数:`isUnscaled`
|
|
||||||
- 返回值:`timerId`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 注册无参定时器
|
|
||||||
- 是最常用、最简洁的用法
|
|
||||||
|
|
||||||
### `int AddTimer<T>(Action<T> callback, T arg, float time, bool isLoop = false, bool isUnscaled = false)`
|
|
||||||
|
|
||||||
- 必填参数:`callback`
|
|
||||||
- 必填参数:`arg`
|
|
||||||
- 必填参数:`time`
|
|
||||||
- 可选参数:`isLoop`
|
|
||||||
- 可选参数:`isUnscaled`
|
|
||||||
- 返回值:`timerId`
|
|
||||||
- 泛型约束:无额外约束
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 注册单参数强类型定时器
|
|
||||||
- 比 `object[] args` 更清晰、更安全
|
|
||||||
|
|
||||||
### `void Stop(int timerId)`
|
|
||||||
|
|
||||||
- 必填参数:`timerId`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 把指定定时器标记为停止运行
|
|
||||||
- 对无效 `timerId` 为安全无操作
|
|
||||||
|
|
||||||
### `void Resume(int timerId)`
|
|
||||||
|
|
||||||
- 必填参数:`timerId`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 恢复一个已停止的定时器
|
|
||||||
- 对无效 `timerId` 为安全无操作
|
|
||||||
|
|
||||||
### `bool IsRunning(int timerId)`
|
|
||||||
|
|
||||||
- 必填参数:`timerId`
|
|
||||||
- 返回值:`bool`
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 返回该定时器当前是否处于运行状态
|
|
||||||
- 对无效 `timerId` 返回 `false`
|
|
||||||
|
|
||||||
### `float GetLeftTime(int timerId)`
|
|
||||||
|
|
||||||
- 必填参数:`timerId`
|
|
||||||
- 返回值:剩余秒数
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 返回定时器剩余触发时间
|
|
||||||
- 对无效 `timerId` 返回 `0`
|
|
||||||
|
|
||||||
### `void Restart(int timerId)`
|
|
||||||
|
|
||||||
- 必填参数:`timerId`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 重新调度该定时器
|
|
||||||
- 对无效 `timerId` 为安全无操作
|
|
||||||
|
|
||||||
### `void RemoveTimer(int timerId)`
|
|
||||||
|
|
||||||
- 必填参数:`timerId`
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 从系统中移除指定定时器
|
|
||||||
- 是最推荐的结束方式
|
|
||||||
|
|
||||||
### `void RemoveAllTimer()`
|
|
||||||
|
|
||||||
- 返回值:无
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- 清空当前全部定时器
|
|
||||||
- 通常只建议在服务销毁、场景彻底重置或特殊测试环境下使用
|
|
||||||
|
|
||||||
## 常见用法
|
|
||||||
|
|
||||||
### 1. 一次性延时执行
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class DelayExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _delayTimer;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_delayTimer = GameApp.Timer.AddTimer(OnDelayFinish, 2f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_delayTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDelayFinish()
|
|
||||||
{
|
|
||||||
Debug.Log("2 seconds later");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 循环计时器
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class LoopTimerExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _loopTimer;
|
|
||||||
private int _counter;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_loopTimer = GameApp.Timer.AddTimer(OnLoop, 0.5f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_loopTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLoop()
|
|
||||||
{
|
|
||||||
_counter++;
|
|
||||||
Debug.Log($"Loop count: {_counter}");
|
|
||||||
|
|
||||||
if (_counter >= 5)
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_loopTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 带参数的定时器
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class TimerArgsExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _timerId;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_timerId = GameApp.Timer.AddTimer(OnRewardDelay, 3f, false, false, "Gold", 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRewardDelay(params object[] args)
|
|
||||||
{
|
|
||||||
string rewardType = (string)args[0];
|
|
||||||
int amount = (int)args[1];
|
|
||||||
Debug.Log($"Reward => {rewardType}, amount => {amount}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 泛型参数定时器
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class GenericTimerExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _timerId;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_timerId = GameApp.Timer.AddTimer<int>(OnDamageDelay, 200, 1.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDamageDelay(int damage)
|
|
||||||
{
|
|
||||||
Debug.Log($"Delayed damage: {damage}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 不受暂停影响的 UI 倒计时
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class UnscaledCountdownExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _timerId;
|
|
||||||
private float _left = 5f;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_timerId = GameApp.Timer.AddTimer(OnTick, 1f, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTick()
|
|
||||||
{
|
|
||||||
_left -= 1f;
|
|
||||||
Debug.Log($"Countdown: {_left}");
|
|
||||||
|
|
||||||
if (_left <= 0f)
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 查询剩余时间
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class LeftTimeExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _timerId;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_timerId = GameApp.Timer.AddTimer(OnFinish, 10f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
float left = GameApp.Timer.GetLeftTime(_timerId);
|
|
||||||
Debug.Log($"Left: {left:F2}s");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFinish()
|
|
||||||
{
|
|
||||||
Debug.Log("Finished");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. 暂停、恢复与重启
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class PauseResumeTimerExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _timerId;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_timerId = GameApp.Timer.AddTimer(OnTick, 1f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (Input.GetKeyDown(KeyCode.S))
|
|
||||||
{
|
|
||||||
GameApp.Timer.Stop(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Input.GetKeyDown(KeyCode.R))
|
|
||||||
{
|
|
||||||
GameApp.Timer.Resume(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Input.GetKeyDown(KeyCode.T))
|
|
||||||
{
|
|
||||||
GameApp.Timer.Restart(_timerId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTick()
|
|
||||||
{
|
|
||||||
Debug.Log("Running timer");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8. 组件生命周期绑定
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class SafeTimerOwner : MonoBehaviour
|
|
||||||
{
|
|
||||||
private int _timerId = -1;
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
_timerId = GameApp.Timer.AddTimer(OnHeartbeat, 2f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDisable()
|
|
||||||
{
|
|
||||||
if (_timerId > 0)
|
|
||||||
{
|
|
||||||
GameApp.Timer.RemoveTimer(_timerId);
|
|
||||||
_timerId = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHeartbeat()
|
|
||||||
{
|
|
||||||
Debug.Log("Heartbeat");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 运行行为细节
|
|
||||||
|
|
||||||
这一部分基于当前 `TimerService` 实现整理,适合开发时理解边界行为。
|
|
||||||
|
|
||||||
### 1. 无效 `timerId` 的行为
|
|
||||||
|
|
||||||
以下方法对无效 `timerId` 都是安全的:
|
|
||||||
|
|
||||||
- `Stop`
|
|
||||||
- `Resume`
|
|
||||||
- `Restart`
|
|
||||||
- `RemoveTimer`
|
|
||||||
|
|
||||||
对应返回值行为:
|
|
||||||
|
|
||||||
- `IsRunning` 返回 `false`
|
|
||||||
- `GetLeftTime` 返回 `0`
|
|
||||||
|
|
||||||
### 2. 非循环定时器会在触发后自动移除
|
|
||||||
|
|
||||||
一次性定时器执行回调后,不需要手动调用 `RemoveTimer`
|
|
||||||
|
|
||||||
但如果组件生命周期不确定,仍建议在 `OnDestroy` / `OnDisable` 中做防守式移除。
|
|
||||||
|
|
||||||
### 3. 回调异常会被捕获
|
|
||||||
|
|
||||||
`TimerService` 内部会捕获回调异常并记录日志,不会因为单个定时器异常直接打断整个调度链。
|
|
||||||
|
|
||||||
### 4. `Stop` / `Resume` 的语义更像“运行标记”
|
|
||||||
|
|
||||||
源码层面:
|
|
||||||
|
|
||||||
- `Stop(timerId)` 只是把定时器标记为 `IsRunning = false`
|
|
||||||
- `Resume(timerId)` 只是把它重新标记为 `true`
|
|
||||||
|
|
||||||
注意点:
|
|
||||||
|
|
||||||
- 如果定时器已经到达触发时刻,但当时处于 `Stop` 状态,那么该次调度不会执行
|
|
||||||
- 对循环定时器来说,如果它在应触发的那一刻是停止状态,也不会自动重新挂回时间轮
|
|
||||||
|
|
||||||
因此更稳妥的经验是:
|
|
||||||
|
|
||||||
- **短暂停顿并在触发前恢复**:可以用 `Stop` / `Resume`
|
|
||||||
- **需要明确重新开始计时**:优先用 `Restart`
|
|
||||||
|
|
||||||
### 5. `Restart` 对循环定时器更直观
|
|
||||||
|
|
||||||
当前实现里:
|
|
||||||
|
|
||||||
- 循环定时器的 `Interval = time`
|
|
||||||
- 非循环定时器的 `Interval = 0`
|
|
||||||
|
|
||||||
这意味着:
|
|
||||||
|
|
||||||
- 对循环定时器调用 `Restart`,会从当前时刻重新按原间隔开始计时
|
|
||||||
- 对非循环定时器调用 `Restart`,会因为内部间隔是 `0`,变成“下一次 Tick 几乎立刻触发”
|
|
||||||
|
|
||||||
所以建议:
|
|
||||||
|
|
||||||
- **循环定时器**:可以使用 `Restart`
|
|
||||||
- **一次性定时器**:如果要重新延时,直接重新创建一个新的 timer 更清晰
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
### 推荐做法
|
|
||||||
|
|
||||||
- 把 `timerId` 与对象生命周期绑定
|
|
||||||
- UI 倒计时优先用 `isUnscaled = true`
|
|
||||||
- 对单参数回调优先使用泛型重载
|
|
||||||
- 对复杂业务优先在回调中触发业务方法,而不是把整段逻辑都堆进匿名函数
|
|
||||||
|
|
||||||
### 推荐封装方式
|
|
||||||
|
|
||||||
如果你的项目里大量使用定时器,建议封装一层:
|
|
||||||
|
|
||||||
- `StartOnce(float delay, Action action)`
|
|
||||||
- `StartLoop(float interval, Action action)`
|
|
||||||
- `StopAndClear(ref int timerId)`
|
|
||||||
|
|
||||||
这样可以减少重复样板代码和漏删问题。
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
### 1. 循环定时器不移除
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 组件销毁后仍继续运行
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- 在 `OnDisable` 或 `OnDestroy` 中移除
|
|
||||||
|
|
||||||
### 2. 暂停界面仍使用缩放时间
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 游戏暂停后倒计时也停住
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- UI 倒计时使用 `isUnscaled = true`
|
|
||||||
|
|
||||||
### 3. 在非循环定时器上依赖 `Restart`
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 行为不像“重新开始原延时”,而是几乎立即触发
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- 直接重新创建一次性定时器
|
|
||||||
|
|
||||||
### 4. `object[] args` 中频繁装箱拆箱
|
|
||||||
|
|
||||||
现象:
|
|
||||||
|
|
||||||
- 代码可读性差
|
|
||||||
- 更容易写错类型转换
|
|
||||||
|
|
||||||
规避:
|
|
||||||
|
|
||||||
- 单参数时优先用 `AddTimer<T>`
|
|
||||||
|
|
||||||
## 性能注意事项
|
|
||||||
|
|
||||||
- 少量长生命周期定时器成本很低
|
|
||||||
- 大量高频定时器建议业务上合并
|
|
||||||
- 能用泛型单参数回调时,优先别用 `object[]`
|
|
||||||
- 大量短周期循环定时器应谨慎使用,优先考虑合并成统一更新器
|
|
||||||
|
|
||||||
## 适用场景建议
|
|
||||||
|
|
||||||
### 适合使用 Timer 模块
|
|
||||||
|
|
||||||
- 秒级倒计时
|
|
||||||
- UI 展示延迟
|
|
||||||
- 技能或状态延后执行
|
|
||||||
- 轻量循环任务
|
|
||||||
|
|
||||||
### 不适合使用 Timer 模块
|
|
||||||
|
|
||||||
- 每帧复杂逻辑
|
|
||||||
- 高频实时物理计算
|
|
||||||
- 长链路异步流程编排
|
|
||||||
|
|
||||||
这些场景更适合:
|
|
||||||
|
|
||||||
- `Update`
|
|
||||||
- `Coroutine`
|
|
||||||
- `UniTask`
|
|
||||||
- 专门的状态机/调度器
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6a5da693652014446867c2397a69fd27
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,552 +0,0 @@
|
|||||||
# UI
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
|
|
||||||
UI 模块负责窗口创建、资源定位、层级管理、显示/关闭、缓存、过渡动画与界面绑定代码协作。
|
|
||||||
|
|
||||||
本模块里最容易误解的一点是:
|
|
||||||
|
|
||||||
- `UIHolderObjectBase`(通常简称 **UIHolder**)不是推荐手写的业务类
|
|
||||||
- 项目中的大多数 `UIHolder` 都应通过 **UI 绑定工具自动生成**
|
|
||||||
- 业务代码通常只编写 `UIWindow<T>`、`UIWidget<T>`、`UITabWindow<T>` 这类逻辑类
|
|
||||||
|
|
||||||
换句话说:
|
|
||||||
|
|
||||||
- **UIHolder 负责“控件引用和预制体桥接”**
|
|
||||||
- **UI 逻辑类负责“界面行为和生命周期”**
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
1. 在场景中挂载 `UIComponent`
|
|
||||||
2. 为 `UIComponent.uiRoot` 指定 UI 根预制体
|
|
||||||
3. 在 `UISettingEditorWindow` 中配置 UI 生成规则
|
|
||||||
4. 选中 UI 预制体根节点,执行 `GameObject/UI生成绑定`
|
|
||||||
5. 让生成器自动生成 `UIHolder` 类并挂回预制体
|
|
||||||
6. 在逻辑类中使用 `UIWindow<T>` 或 `UIWidget<T>`,其中 `T` 就是生成出来的 `UIHolder` 类型
|
|
||||||
|
|
||||||
## 架构说明
|
|
||||||
|
|
||||||
```text
|
|
||||||
UIComponent
|
|
||||||
└─ UIService
|
|
||||||
├─ UIBase
|
|
||||||
├─ UIWindow<T>
|
|
||||||
├─ UIWidget<T>
|
|
||||||
├─ UITabWindow<T>
|
|
||||||
├─ UIHolderObjectBase
|
|
||||||
├─ UIMetaRegistry
|
|
||||||
├─ UIResRegistry
|
|
||||||
└─ UIHolderFactory
|
|
||||||
```
|
|
||||||
|
|
||||||
### 角色分工
|
|
||||||
|
|
||||||
- `UIBase`:UI 逻辑生命周期基类
|
|
||||||
- `UIWindow<T>`:顶层窗口逻辑
|
|
||||||
- `UIWidget<T>`:挂在窗口或其他 Widget 下的子部件逻辑
|
|
||||||
- `UITabWindow<T>`:支持 Tab 页懒加载与切换的窗口基类
|
|
||||||
- `UIHolderObjectBase`:预制体绑定脚本基类,负责暴露控件引用、`RectTransform`、转场播放器
|
|
||||||
- `UIHolderFactory`:根据注册信息加载预制体并创建对应 Holder
|
|
||||||
|
|
||||||
### `UIBase`、`UIHolderObjectBase`、`UIWidget<T>` 的关系
|
|
||||||
|
|
||||||
```text
|
|
||||||
UI 预制体
|
|
||||||
└─ 挂载生成的 XXXHolder : UIHolderObjectBase
|
|
||||||
↑
|
|
||||||
UIWidget<XXXHolder> / UIWindow<XXXHolder>
|
|
||||||
↑
|
|
||||||
通过泛型参数 T 访问 baseui
|
|
||||||
```
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- `UIHolderObjectBase` 挂在预制体上,持有控件引用
|
|
||||||
- `UIWindow<T>` / `UIWidget<T>` 的泛型参数 `T` 指向该 Holder 类型
|
|
||||||
- 在逻辑类内部可以通过 `baseui` 访问生成好的控件字段
|
|
||||||
|
|
||||||
## UIHolder 的作用
|
|
||||||
|
|
||||||
`UIHolderObjectBase` 的职责不是写业务逻辑,而是充当:
|
|
||||||
|
|
||||||
- **控件引用容器**:保存按钮、文本、图片、节点等引用
|
|
||||||
- **预制体桥接层**:让 UI 逻辑层不直接依赖层级查找
|
|
||||||
- **生命周期事件承载层**:暴露 `OnWindowInitEvent`、`OnWindowAfterShowEvent` 等事件
|
|
||||||
- **转场入口**:自动寻找并驱动 `IUITransitionPlayer`
|
|
||||||
|
|
||||||
因此推荐做法是:
|
|
||||||
|
|
||||||
- 业务不手写具体 `XXXHolder`
|
|
||||||
- 由 UI 绑定工具从预制体结构自动生成
|
|
||||||
|
|
||||||
## UIHolder 自动生成工作流
|
|
||||||
|
|
||||||
### 1. 配置生成规则
|
|
||||||
|
|
||||||
先在编辑器中配置 `UIGenerateConfiguration`,核心配置包括:
|
|
||||||
|
|
||||||
- `UIPrefabRootPath`:UI 预制体根目录
|
|
||||||
- `GenerateHolderCodePath`:生成代码输出目录
|
|
||||||
- `NameSpace`:生成类所在命名空间
|
|
||||||
- `LoadType`:`Resources` 或 `AssetBundle`
|
|
||||||
|
|
||||||
这些配置通常通过 `UISettingEditorWindow` 维护。
|
|
||||||
|
|
||||||
### 2. 按命名规则搭建 UI 预制体
|
|
||||||
|
|
||||||
生成器会扫描 UI 节点名和组件类型。例如默认规则会识别:
|
|
||||||
|
|
||||||
- `Btn` → 按钮组件
|
|
||||||
- `Text` → `TextMeshProUGUI`
|
|
||||||
- `Img` → `Image`
|
|
||||||
- `Tf` → `Transform`
|
|
||||||
- `Rect` → `RectTransform`
|
|
||||||
|
|
||||||
例如:
|
|
||||||
|
|
||||||
- `Btn#Close@`
|
|
||||||
- `Text#Title@`
|
|
||||||
- `Img#Icon@`
|
|
||||||
|
|
||||||
生成器会根据这些节点名推断字段名和字段类型。
|
|
||||||
|
|
||||||
### 3. 选中 UI 预制体根节点
|
|
||||||
|
|
||||||
支持两种常见操作方式:
|
|
||||||
|
|
||||||
- 在 Project 中选中 prefab 资源
|
|
||||||
- 或在 Prefab Mode 中编辑当前预制体
|
|
||||||
|
|
||||||
### 4. 执行绑定工具
|
|
||||||
|
|
||||||
菜单入口:
|
|
||||||
|
|
||||||
- `GameObject/UI生成绑定`
|
|
||||||
|
|
||||||
执行后生成器会:
|
|
||||||
|
|
||||||
1. 读取当前 UI 生成配置
|
|
||||||
2. 校验预制体路径是否位于配置的 UI 根目录
|
|
||||||
3. 扫描可绑定节点
|
|
||||||
4. 生成 `XXXHolder` 代码文件
|
|
||||||
5. 脚本编译后自动把生成的 `XXXHolder` 挂到目标预制体根节点
|
|
||||||
6. 自动回填对应字段引用
|
|
||||||
|
|
||||||
这意味着:
|
|
||||||
|
|
||||||
- **正常情况下不需要手动创建 Holder 脚本**
|
|
||||||
- **也不需要手工把字段拖到 Inspector**
|
|
||||||
|
|
||||||
### 5. 生成代码的结果
|
|
||||||
|
|
||||||
生成的 `UIHolder` 类本质上:
|
|
||||||
|
|
||||||
- 继承自 `UIHolderObjectBase`
|
|
||||||
- 带有 `UIResAttribute`
|
|
||||||
- 包含自动生成的控件字段
|
|
||||||
|
|
||||||
形态类似:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.UI.Runtime;
|
|
||||||
|
|
||||||
[UIRes(InventoryItemHolder.ResTag, EUIResLoadType.AssetBundle)]
|
|
||||||
public class InventoryItemHolder : UIHolderObjectBase
|
|
||||||
{
|
|
||||||
public const string ResTag = "UI/Inventory/InventoryItem.prefab";
|
|
||||||
|
|
||||||
[UnityEngine.SerializeField] private UnityEngine.UI.Button uiBtnClose;
|
|
||||||
[UnityEngine.SerializeField] private TMPro.TextMeshProUGUI uiTextTitle;
|
|
||||||
|
|
||||||
public UnityEngine.UI.Button BtnClose => uiBtnClose;
|
|
||||||
public TMPro.TextMeshProUGUI TextTitle => uiTextTitle;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> 上面是示意结构;实际字段名由生成规则决定。
|
|
||||||
|
|
||||||
## 在 `UIWidget<T>` 中如何引用生成的 UIHolder
|
|
||||||
|
|
||||||
关键点:
|
|
||||||
|
|
||||||
- `T` 就是生成工具输出的 Holder 类型
|
|
||||||
- 逻辑类不需要自己声明控件字段
|
|
||||||
- 通过 `baseui` 访问自动生成的 Holder 成员
|
|
||||||
|
|
||||||
例如:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.UI.Runtime;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class InventoryItemWidget : UIWidget<InventoryItemHolder>
|
|
||||||
{
|
|
||||||
protected override void OnInitialize()
|
|
||||||
{
|
|
||||||
baseui.BtnClose.onClick.AddListener(OnClickClose);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnOpen()
|
|
||||||
{
|
|
||||||
baseui.TextTitle.text = "Potion";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnClickClose()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
这里的含义是:
|
|
||||||
|
|
||||||
- `InventoryItemHolder` 由 UI 绑定工具生成
|
|
||||||
- `InventoryItemWidget` 是手写业务逻辑
|
|
||||||
- `UIWidget<InventoryItemHolder>` 把逻辑和绑定类关联起来
|
|
||||||
|
|
||||||
## 核心类与接口
|
|
||||||
|
|
||||||
### `IUIService`
|
|
||||||
|
|
||||||
负责:
|
|
||||||
|
|
||||||
- 初始化 UI 根节点
|
|
||||||
- 打开/关闭窗口
|
|
||||||
- 查询已打开窗口
|
|
||||||
- 获取层级根节点
|
|
||||||
- 注入 `ITimerService`
|
|
||||||
|
|
||||||
### `UIBase`
|
|
||||||
|
|
||||||
关键生命周期:
|
|
||||||
|
|
||||||
- `OnInitialize()`
|
|
||||||
- `OnOpen()`
|
|
||||||
- `OnClose()`
|
|
||||||
- `OnDestroy()`
|
|
||||||
- `OnUpdate()`
|
|
||||||
|
|
||||||
以及对应异步版本:
|
|
||||||
|
|
||||||
- `OnInitializeAsync()`
|
|
||||||
- `OnOpenAsync()`
|
|
||||||
- `OnCloseAsync()`
|
|
||||||
|
|
||||||
并提供:
|
|
||||||
|
|
||||||
- `CreateWidgetAsync<T>()`
|
|
||||||
- `CreateWidgetSync<T>()`
|
|
||||||
- `RemoveWidget(UIBase widget)`
|
|
||||||
|
|
||||||
### `UIWindow<T>`
|
|
||||||
|
|
||||||
适合顶层窗口,通常用于:
|
|
||||||
|
|
||||||
- 主界面
|
|
||||||
- 设置页
|
|
||||||
- 背包页
|
|
||||||
- 弹窗
|
|
||||||
|
|
||||||
常用能力:
|
|
||||||
|
|
||||||
- `CloseSelf()`
|
|
||||||
- 强制关闭
|
|
||||||
- 打开后顶层排序与层级遮挡处理
|
|
||||||
|
|
||||||
### `UIWidget<T>`
|
|
||||||
|
|
||||||
适合子部件,通常用于:
|
|
||||||
|
|
||||||
- 列表项
|
|
||||||
- 面板块
|
|
||||||
- 详情条目
|
|
||||||
- 页签子页面
|
|
||||||
|
|
||||||
公开方法:
|
|
||||||
|
|
||||||
- `Open(params object[] userDatas)`
|
|
||||||
- `Close()`
|
|
||||||
- `Destroy()`
|
|
||||||
|
|
||||||
### `UITabWindow<T>`
|
|
||||||
|
|
||||||
用于页签式窗口,支持:
|
|
||||||
|
|
||||||
- 预注册 Tab
|
|
||||||
- 按需懒加载
|
|
||||||
- `SwitchTab(int index, params object[] userDatas)`
|
|
||||||
|
|
||||||
### `UIHolderObjectBase`
|
|
||||||
|
|
||||||
核心成员:
|
|
||||||
|
|
||||||
- `Target`
|
|
||||||
- `RectTransform`
|
|
||||||
- `Visible`
|
|
||||||
- `OnWindowInitEvent`
|
|
||||||
- `OnWindowBeforeShowEvent`
|
|
||||||
- `OnWindowAfterShowEvent`
|
|
||||||
- `OnWindowBeforeClosedEvent`
|
|
||||||
- `OnWindowAfterClosedEvent`
|
|
||||||
- `OnWindowDestroyEvent`
|
|
||||||
|
|
||||||
### `UIHolderFactory`
|
|
||||||
|
|
||||||
`UIHolderFactory` 是 UI 资源实例化与 Holder 绑定的桥梁,作用是:
|
|
||||||
|
|
||||||
- 根据 `UIResRegistry` 中登记的资源信息定位 UI 预制体
|
|
||||||
- 调用 `IResourceService` 或 `Resources` 加载 UI 资源
|
|
||||||
- 实例化预制体并获取对应的 `UIHolderObjectBase`
|
|
||||||
- 把生成的 Holder 绑定到 `UIWindow<T>` / `UIWidget<T>` 对应的逻辑实例上
|
|
||||||
|
|
||||||
你通常**不会在业务层频繁直接调用它**,因为:
|
|
||||||
|
|
||||||
- 打开窗口时,`UIService` 会在内部调用 `UIHolderFactory`
|
|
||||||
- 创建 Widget 时,`UIBase.CreateWidgetAsync<T>()` / `CreateWidgetSync<T>()` 也会在内部调用它
|
|
||||||
|
|
||||||
可以把它理解为:
|
|
||||||
|
|
||||||
```text
|
|
||||||
UI 逻辑类
|
|
||||||
-> UIService / UIBase
|
|
||||||
-> UIHolderFactory
|
|
||||||
-> 加载预制体
|
|
||||||
-> 找到生成的 XXXHolder
|
|
||||||
-> 绑定到 UIWindow<T> / UIWidget<T>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 典型作用场景
|
|
||||||
|
|
||||||
1. `ShowUI<InventoryWindow>()`
|
|
||||||
- `UIService` 找到 `InventoryWindow` 对应的元数据
|
|
||||||
- `UIHolderFactory` 根据 `InventoryWindowHolder` 的 `UIResAttribute` 加载预制体
|
|
||||||
- 创建并返回 `InventoryWindowHolder`
|
|
||||||
- 把 Holder 绑定给 `InventoryWindow`
|
|
||||||
|
|
||||||
2. `CreateWidgetAsync<InventoryItemWidget>(parent)`
|
|
||||||
- `UIBase` 创建 `InventoryItemWidget` 的元数据
|
|
||||||
- `UIHolderFactory` 加载 `InventoryItemHolder` 对应的 Widget 预制体
|
|
||||||
- 把 Holder 绑定给 `InventoryItemWidget`
|
|
||||||
|
|
||||||
#### 直接调用示例
|
|
||||||
|
|
||||||
虽然业务层通常不需要直接调用,但在工具代码、调试代码或特殊预加载场景下,可以这样使用:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.UI.Runtime;
|
|
||||||
using Cysharp.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class UIHolderFactoryExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeField] private Transform previewRoot;
|
|
||||||
|
|
||||||
private async UniTaskVoid Start()
|
|
||||||
{
|
|
||||||
InventoryItemHolder holder = await UIHolderFactory.CreateUIHolderAsync<InventoryItemHolder>(previewRoot);
|
|
||||||
if (holder != null)
|
|
||||||
{
|
|
||||||
holder.TextName.text = "Preview Item";
|
|
||||||
holder.TextCount.text = "99";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
同步版本示例:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.UI.Runtime;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class UIHolderFactorySyncExample : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeField] private Transform previewRoot;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
InventoryItemHolder holder = UIHolderFactory.CreateUIHolderSync<InventoryItemHolder>(previewRoot);
|
|
||||||
if (holder != null)
|
|
||||||
{
|
|
||||||
holder.TextName.text = "Sync Preview";
|
|
||||||
holder.TextCount.text = "1";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 注意事项
|
|
||||||
|
|
||||||
- `T` 必须是正确的生成型 `UIHolder`,且继承自 `UIHolderObjectBase`
|
|
||||||
- 对应 Holder 需要已具备 `UIResAttribute`,通常由绑定工具自动生成
|
|
||||||
- 如果资源路径错误、预制体未挂对应 Holder,`UIHolderFactory` 绑定会失败
|
|
||||||
- 正常业务打开窗口和创建 Widget 时,优先走 `GameApp.UI.ShowUI<T>()`、`CreateWidgetAsync<T>()`,不建议绕过框架直接大量使用工厂
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### `IUIService.Initialize(Transform root, bool isOrthographic)`
|
|
||||||
|
|
||||||
- 必填参数:`root`
|
|
||||||
- 必填参数:`isOrthographic`
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:初始化 UI 根、Canvas、Camera 与各层级节点
|
|
||||||
|
|
||||||
### `UniTask<T> ShowUI<T>(params object[] userDatas) where T : UIBase`
|
|
||||||
|
|
||||||
- 可选参数:`userDatas`
|
|
||||||
- 返回值:`UniTask<T>`
|
|
||||||
- 泛型约束:`T : UIBase`
|
|
||||||
- 说明:异步打开窗口
|
|
||||||
- 推荐:默认优先使用该方法
|
|
||||||
|
|
||||||
### `T ShowUISync<T>(params object[] userDatas) where T : UIBase`
|
|
||||||
|
|
||||||
- 返回值:`T`
|
|
||||||
- 说明:同步打开窗口
|
|
||||||
- 注意:仅在资源已就绪时使用
|
|
||||||
|
|
||||||
### `void CloseUI<T>(bool force = false) where T : UIBase`
|
|
||||||
|
|
||||||
- 可选参数:`force`
|
|
||||||
- 返回值:无
|
|
||||||
- 说明:关闭指定窗口
|
|
||||||
|
|
||||||
### `CreateWidgetAsync<T>(Transform parent, bool visible = true) where T : UIBase`
|
|
||||||
|
|
||||||
- 必填参数:`parent`
|
|
||||||
- 可选参数:`visible`
|
|
||||||
- 返回值:`UniTask<T>`
|
|
||||||
- 泛型约束:`T : UIBase`
|
|
||||||
- 说明:从父 UI 创建 Widget
|
|
||||||
|
|
||||||
### `RemoveWidget(UIBase widget)`
|
|
||||||
|
|
||||||
- 必填参数:`widget`
|
|
||||||
- 返回值:`UniTask`
|
|
||||||
- 说明:从父 UI 中移除并销毁 Widget
|
|
||||||
|
|
||||||
## 完整使用示例
|
|
||||||
|
|
||||||
### 示例 1:窗口逻辑 + 自动生成 Holder
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.UI.Runtime;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
[Window(UILayer.UI, fullScreen: true, cacheTime: 10)]
|
|
||||||
public sealed class InventoryWindow : UIWindow<InventoryWindowHolder>
|
|
||||||
{
|
|
||||||
protected override async Cysharp.Threading.Tasks.UniTask OnInitializeAsync()
|
|
||||||
{
|
|
||||||
baseui.BtnClose.onClick.AddListener(CloseSelf);
|
|
||||||
|
|
||||||
InventoryItemWidget item = await CreateWidgetAsync<InventoryItemWidget>(baseui.TfContent, false);
|
|
||||||
item.Open("Potion", 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnOpen()
|
|
||||||
{
|
|
||||||
baseui.TextTitle.text = "Inventory";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
说明:
|
|
||||||
|
|
||||||
- `InventoryWindowHolder` 推荐由 UI 绑定工具生成
|
|
||||||
- `InventoryWindow` 由业务手写
|
|
||||||
|
|
||||||
### 示例 2:Widget 使用生成的 Holder
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.UI.Runtime;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public sealed class InventoryItemWidget : UIWidget<InventoryItemHolder>
|
|
||||||
{
|
|
||||||
private string _itemName;
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
protected override void OnInitialize()
|
|
||||||
{
|
|
||||||
baseui.BtnUse.onClick.AddListener(OnClickUse);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnOpen()
|
|
||||||
{
|
|
||||||
_itemName = (string)UserDatas[0];
|
|
||||||
_count = (int)UserDatas[1];
|
|
||||||
|
|
||||||
baseui.TextName.text = _itemName;
|
|
||||||
baseui.TextCount.text = _count.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnClose()
|
|
||||||
{
|
|
||||||
baseui.TextName.text = string.Empty;
|
|
||||||
baseui.TextCount.text = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnClickUse()
|
|
||||||
{
|
|
||||||
Debug.Log($"Use item: {_itemName}");
|
|
||||||
Close();
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 示例 3:TabWindow
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using AlicizaX.UI.Runtime;
|
|
||||||
|
|
||||||
[Window(UILayer.UI, fullScreen: true)]
|
|
||||||
public sealed class SettingWindow : UITabWindow<SettingWindowHolder>
|
|
||||||
{
|
|
||||||
protected override void OnInitialize()
|
|
||||||
{
|
|
||||||
InitTabVirtuallyView<GraphicsTabWidget>(baseui.TfTabRoot);
|
|
||||||
InitTabVirtuallyView<AudioTabWidget>(baseui.TfTabRoot);
|
|
||||||
|
|
||||||
baseui.BtnGraphics.onClick.AddListener(() => SwitchTab(0));
|
|
||||||
baseui.BtnAudio.onClick.AddListener(() => SwitchTab(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnOpen()
|
|
||||||
{
|
|
||||||
SwitchTab(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
- **不要手写大多数 UIHolder**,优先使用自动生成
|
|
||||||
- 窗口逻辑类只处理状态和行为,控件引用统一放进 Holder
|
|
||||||
- `OnInitialize` 做一次性事件绑定,`OnOpen` 做参数刷新
|
|
||||||
- 默认使用异步打开,避免首帧阻塞
|
|
||||||
- 列表项和重复块优先拆成 `UIWidget<T>`
|
|
||||||
|
|
||||||
## 常见错误
|
|
||||||
|
|
||||||
### 手工编写 UIHolder 导致与生成器冲突
|
|
||||||
|
|
||||||
- 现象:字段名、命名空间或资源路径不一致
|
|
||||||
- 规避:把 Holder 视为生成产物,由工具维护
|
|
||||||
|
|
||||||
### 在 `OnOpen` 中重复注册按钮事件
|
|
||||||
|
|
||||||
- 风险:窗口每次打开都会重复绑定
|
|
||||||
- 正确做法:放到 `OnInitialize`
|
|
||||||
|
|
||||||
### 把 `UIWidget<T>` 当顶层窗口直接 `ShowUI`
|
|
||||||
|
|
||||||
- `UIWidget<T>` 应由父 `UIBase` 通过 `CreateWidgetAsync<T>()` 或 `CreateWidgetSync<T>()` 创建
|
|
||||||
|
|
||||||
## 性能注意事项
|
|
||||||
|
|
||||||
- 首次打开大窗口优先预热资源或异步显示
|
|
||||||
- 使用自动生成 Holder 可以避免大量运行时查找和手工拖引用错误
|
|
||||||
- 高频销毁/重建的块状内容优先用 `UIWidget<T>`
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1fe4c4405e0dfd54cbe0f51ac2fbfe4c
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6877cc0b0a167be4aacecb525d56cc60
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
# UIExtension InputGlyph 输入图标模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`InputGlyph` 提供输入设备检测、绑定解析、图标数据库查询、UI Image/TMP 输出和重绑定后自动刷新能力。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 显示键盘、手柄按键图标。
|
|
||||||
- 文本中嵌入按键提示。
|
|
||||||
- 输入重绑定后自动刷新 UI 提示。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
1. 创建 `InputGlyphDatabase` 并放到 `Resources/InputGlyphDatabase.asset`。
|
|
||||||
2. 给目标对象挂 `InputGlyph`。
|
|
||||||
3. 选择动作来源与输出模式。
|
|
||||||
|
|
||||||
## 详细使用说明
|
|
||||||
- `InputGlyph` 会监听 `InputDeviceWatcher` 与 `InputBindingManager.BindingsChanged`。
|
|
||||||
- 输出为 `Image` 时设置 `targetImage.sprite`。
|
|
||||||
- 输出为 `Text` 时写入 TMP `<sprite>` 标签或回退显示文本。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`InputGlyph`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/InputGlyph/InputGlyph.cs`
|
|
||||||
- 枚举:`ActionSourceMode`、`OutputMode`
|
|
||||||
- 类型:`DeviceCategoryEvent`
|
|
||||||
- `category`
|
|
||||||
- `onMatched`
|
|
||||||
- `onNotMatched`
|
|
||||||
|
|
||||||
### 类型:`InputGlyphBehaviourBase`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/InputGlyph/InputGlyphBehaviourBase.cs`
|
|
||||||
- 说明:抽象基类,负责设备变化与绑定变化监听。
|
|
||||||
|
|
||||||
### 类型:`GlyphService`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/InputGlyph/Core/GlyphService.cs`
|
|
||||||
- `GetBindingControlPath(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)`
|
|
||||||
- `GetBindingControlPath(InputActionReference actionReference, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)`
|
|
||||||
- `TryGetTMPTagForActionPath(InputAction action, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out string tag, out string displayFallback, InputGlyphDatabase db = null)`
|
|
||||||
- `TryGetTMPTagForActionPath(InputActionReference actionReference, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out string tag, out string displayFallback, InputGlyphDatabase db = null)`
|
|
||||||
- `TryGetUISpriteForActionPath(InputAction action, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite, InputGlyphDatabase db = null)`
|
|
||||||
- `TryGetUISpriteForActionPath(InputActionReference actionReference, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite, InputGlyphDatabase db = null)`
|
|
||||||
- `TryGetTMPTagForActionPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device, out string tag, out string displayFallback, InputGlyphDatabase db = null)`
|
|
||||||
- `TryGetUISpriteForActionPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite, InputGlyphDatabase db = null)`
|
|
||||||
- `GetDisplayNameFromInputAction(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)`
|
|
||||||
- `GetDisplayNameFromControlPath(string controlPath)`
|
|
||||||
- `TryGetBindingControl(InputAction action, string compositePartName, InputDeviceWatcher.InputDeviceCategory? deviceOverride, out InputBinding binding)`
|
|
||||||
|
|
||||||
### 类型:`InputActionReader`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/InputGlyph/Core/InputActionReader.cs`
|
|
||||||
- `ReadValue<T>(string actionName)`
|
|
||||||
- `ReadValue(string actionName)`
|
|
||||||
- `TryReadValue<T>(string actionName, out T value)`
|
|
||||||
- `TryReadValue(string actionName, out object value)`
|
|
||||||
- `TryReadValueOnce<T>(UnityEngine.Object owner, string actionName, out T value)`
|
|
||||||
- `ReadButton(string actionName)`
|
|
||||||
- `ReadButtonOnce(UnityEngine.Object owner, string actionName)`
|
|
||||||
- `ReadButtonOnce(int instanceID, string actionName)`
|
|
||||||
- `ReadButtonOnce(string key, string actionName)`
|
|
||||||
- `ReadButtonToggle(UnityEngine.Object owner, string actionName)`
|
|
||||||
- `ReadButtonToggle(int instanceID, string actionName)`
|
|
||||||
- `ReadButtonToggle(string key, string actionName)`
|
|
||||||
- `ResetToggledButton(string key, string actionName)`
|
|
||||||
- `ResetToggledButton(string actionName)`
|
|
||||||
- `ResetToggledButtons()`
|
|
||||||
|
|
||||||
### 类型:`InputBindingManager`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/InputGlyph/Core/InputBindingManager.cs`
|
|
||||||
- 公开字段:`actions`、`debugMode`
|
|
||||||
- 事件:`OnApply`、`OnRebindPrepare`、`OnRebindStart`、`OnRebindEnd`、`OnRebindConflict`、`BindingsChanged`
|
|
||||||
- 属性:`ActionMaps`、`PreparedRebinds`
|
|
||||||
- 方法:`FindBestBindingIndexForKeyboard(...)`、`Action(string actionName)`、`TryGetAction(...)`、`StartRebind(...)`、`CancelRebind()`、`ConfirmApply(...)`、`DiscardPrepared()`、`ResetToDefaultAsync()`、`GetBindingPath(...)`
|
|
||||||
- 公开嵌套类型:`ActionMap`、`Action`、`Binding`、`BindingPath`、`RebindContext`
|
|
||||||
|
|
||||||
### 类型:`InputDeviceWatcher`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/InputGlyph/Core/InputDeviceWatcher.cs`
|
|
||||||
- 枚举:`InputDeviceCategory`
|
|
||||||
- 结构:`DeviceContext`
|
|
||||||
- 属性:`CurrentCategory`、`CurrentDeviceName`、`CurrentDeviceId`、`CurrentVendorId`、`CurrentProductId`、`CurrentContext`
|
|
||||||
- 事件:`OnDeviceChanged`、`OnDeviceContextChanged`
|
|
||||||
- 方法:`Initialize()`、`Dispose()`
|
|
||||||
|
|
||||||
### 类型:`InputGlyphDatabase`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/InputGlyph/Data/InputGlyphDatabase.cs`
|
|
||||||
- 字段:`tables`、`placeholderSprite`
|
|
||||||
- 方法:`GetTable(string deviceName)`、`GetTable(InputDeviceWatcher.InputDeviceCategory device)`、`GetPlatformIcon(...)`、`TryGetSprite(...)`、`FindSprite(...)`、`FindEntryByControlPath(...)`、`EditorRefreshCache()`、`EditorNormalizeControlPath(...)`
|
|
||||||
- 类型:`GlyphEntry`、`DeviceGlyphTable`
|
|
||||||
|
|
||||||
## 示例
|
|
||||||
```csharp
|
|
||||||
if (GlyphService.TryGetUISpriteForActionPath(actionRef, null, InputDeviceWatcher.CurrentCategory, out var sprite))
|
|
||||||
{
|
|
||||||
image.sprite = sprite;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d9b74be0f15fe854fadca69b14d98883
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a63300f4743578b4cbe32d788b056cd5
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
# UIExtension UXButton 按钮模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXButton` 是 `Button` 的增强版本,继承自 `UXSelectable`,统一了鼠标、键盘和手柄提交行为。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Button/UXButton.cs`
|
|
||||||
|
|
||||||
### 类型:`UXButton`
|
|
||||||
- `onClick`
|
|
||||||
- `OnPointerEnter(PointerEventData eventData)`
|
|
||||||
- `OnPointerClick(PointerEventData eventData)`
|
|
||||||
- `OnSubmit(BaseEventData eventData)`
|
|
||||||
|
|
||||||
### 接口:`AlicizaX.UI.Extension.IButton`
|
|
||||||
- 按钮能力抽象接口。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
var btn = gameObject.AddComponent<UnityEngine.UI.UXButton>();
|
|
||||||
btn.onClick.AddListener(() => UnityEngine.Debug.Log("Clicked"));
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e56d6be154e2f23409e38811debf993c
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
# UIExtension UXController 数据驱动绑定模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXController` 与 `UXBinding` 组成 UI 状态驱动绑定系统,用于把控制器状态映射到 UI 属性值。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 页签状态切换。
|
|
||||||
- UI 主题或皮肤切换。
|
|
||||||
- 可见性、文本、颜色、尺寸等属性联动。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`UXController`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Controller/UXController.cs`
|
|
||||||
- 属性:`Controllers`、`Bindings`、`ControllerCount`
|
|
||||||
- `ControllerDefinition` 属性:`Id`、`Name`、`Length`、`Description`、`SelectedIndex`
|
|
||||||
- 方法:`TryGetControllerById(...)`、`TryGetControllerByName(...)`、`GetControllerByName(...)`、`GetControllerAt(...)`、`GetControllerIndex(...)`、`SetControllerIndex(...)`、`SetControllerIndexByName(...)`、`ResetAllControllers()`
|
|
||||||
|
|
||||||
### 类型:`UXBinding`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Controller/UXBinding.cs`
|
|
||||||
- 属性:`Controller`、`Entries`
|
|
||||||
- 方法:`Initialize()`、`SetController(...)`、`CaptureDefaults()`、`ResetToDefaults()`、`PreviewEntry(...)`、`CaptureEntryValue(...)`、`CaptureEntryFallbackValue(...)`
|
|
||||||
- `BindingEntry` 属性:`ControllerId`、`ControllerIndex`、`Property`、`Value`、`FallbackMode`、`FallbackValue`、`HasCapturedDefault`
|
|
||||||
|
|
||||||
### 类型:`UXBindingValue`
|
|
||||||
- `BoolValue`
|
|
||||||
- `FloatValue`
|
|
||||||
- `StringValue`
|
|
||||||
- `ColorValue`
|
|
||||||
- `Vector2Value`
|
|
||||||
- `Vector3Value`
|
|
||||||
- `ObjectValue`
|
|
||||||
- `CopyFrom(UXBindingValue other)`
|
|
||||||
|
|
||||||
### 工具类:`UXBindingPropertyUtility`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Controller/UXBindingPropertyUtility.cs`
|
|
||||||
- `AllMetadata`
|
|
||||||
- `GetMetadata(...)`
|
|
||||||
- `IsSupported(...)`
|
|
||||||
- `GetSupportedProperties(...)`
|
|
||||||
- `CaptureValue(...)`
|
|
||||||
- `ApplyValue(...)`
|
|
||||||
|
|
||||||
### 枚举
|
|
||||||
- `UXBindingFallbackMode`
|
|
||||||
- `UXBindingValueKind`
|
|
||||||
- `UXBindingProperty`
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
controller.SetControllerIndex("TabState", 1);
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7c684c4c671e41847866139254703281
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
# UIExtension UXDraggable 拖拽模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXDraggable` 把拖拽生命周期包装为 `UnityEvent<PointerEventData>`,便于直接在 Inspector 或代码中订阅。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Drag/UXDraggable.cs`
|
|
||||||
- `onDrag`
|
|
||||||
- `onBeginDrag`
|
|
||||||
- `onEndDrag`
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
var draggable = gameObject.AddComponent<UnityEngine.UI.UXDraggable>();
|
|
||||||
draggable.onBeginDrag.AddListener(_ => UnityEngine.Debug.Log("Begin"));
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5ab5ad69624ed404da25069210b5d4c2
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
# UIExtension UXGroup 与 UXToggle 模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXGroup` 与 `UXToggle` 提供增强的单选组与 Toggle 体系,兼容更好的导航和状态控制。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`UXGroup`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Group/UXGroup.cs`
|
|
||||||
- 字段:`allowSwitchOff`、`defaultToggle`
|
|
||||||
- 方法:`NotifyToggleOn(...)`、`UnregisterToggle(...)`、`RegisterToggle(...)`、`ContainsToggle(...)`、`EnsureValidState()`、`AnyTogglesOn()`、`ActiveToggles()`、`GetFirstActiveToggle()`、`SetAllTogglesOff(...)`、`Next()`、`Preview()`
|
|
||||||
|
|
||||||
### 类型:`UXToggle`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Group/UXToggle.cs`
|
|
||||||
- 字段/属性:`toggleTransition`、`graphic`、`group`、`onValueChanged`、`isOn`
|
|
||||||
- 方法:`Rebuild(...)`、`LayoutComplete()`、`GraphicUpdateComplete()`、`SetIsOnWithoutNotify(...)`、`OnPointerEnter(...)`、`OnPointerClick(...)`、`OnSubmit(...)`
|
|
||||||
- 类型:`ToggleEvent : UnityEvent<bool>`
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
toggle.group = group;
|
|
||||||
toggle.onValueChanged.AddListener(v => UnityEngine.Debug.Log(v));
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 74b5de19eb107b64d8e4ef6eb081d2c0
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
# UIExtension UXHelper 辅助接口模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXHelper` 用于把 UI 扩展层与项目本地化、音频等外部系统解耦。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 接入项目本地化系统。
|
|
||||||
- 为 UI 组件统一注入帮助器。
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
public class DemoLocalizationHelper : IUXLocalizationHelper
|
|
||||||
{
|
|
||||||
public string GetString(string key) => key;
|
|
||||||
}
|
|
||||||
|
|
||||||
UXComponentExtensionsHelper.SetLocalizationHelper(new DemoLocalizationHelper());
|
|
||||||
```
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/UXHelper.cs`
|
|
||||||
|
|
||||||
### 类型:`UXComponentExtensionsHelper`
|
|
||||||
- `SetLocalizationHelper(IUXLocalizationHelper helper)`
|
|
||||||
- `SetAudioHelper(IUXAudioHelper helper)`
|
|
||||||
|
|
||||||
### 接口:`IUXLocalizationHelper`
|
|
||||||
- `GetString(string key)`
|
|
||||||
|
|
||||||
### 接口:`IUXAudioHelper`
|
|
||||||
- 说明:当前未定义公开方法,作为项目扩展点保留。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5da96e90155e6a54697735f6428f6812
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
# UIExtension UXHotkey 热键注册模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXHotkey` 模块统一管理 UI 热键触发器,支持作用域、层级阻断、批量绑定与调试输出。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 类型:`HotkeyComponent`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Hotkey/HotkeyComponent.cs`
|
|
||||||
- `HotkeyAction`
|
|
||||||
|
|
||||||
### 接口:`IHotkeyTrigger`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Hotkey/IHotkeyTrigger.cs`
|
|
||||||
- `HotkeyAction { get; }`
|
|
||||||
|
|
||||||
### 类型:`UXHotkeyRegisterManager`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Hotkey/UXHotkeyRegisterManager.cs`
|
|
||||||
- `GetDebugInfo()`
|
|
||||||
- 扩展方法:`BindHotKey(...)`、`UnBindHotKey(...)`、`BindHotKeyBatch(...)`、`UnBindHotKeyBatch(...)`
|
|
||||||
- 公开辅助类型:`HotkeyRegistration`、`HotkeyScope`、`ActionRegistration`、`TriggerRegistration`
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
trigger.BindHotKey();
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d08c92b1da506154683918cc2a4766b4
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
# UIExtension UXImage 图像增强模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXImage` 扩展了 Unity `Image`,支持渐变、镜像、翻转填充和顶点重映射。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Image/UXImage.cs`
|
|
||||||
|
|
||||||
### 类型:`UXImage`
|
|
||||||
- `gradient`
|
|
||||||
- `Direction`
|
|
||||||
- `m_OriginFlipMode`
|
|
||||||
- `m_FlipMode`
|
|
||||||
- `flipMode`
|
|
||||||
- `m_FlipWithCopy`
|
|
||||||
- `flipWithCopy`
|
|
||||||
- `flipEdge`
|
|
||||||
- `m_FlipEdgeHorizontal`
|
|
||||||
- `flipEdgeHorizontal`
|
|
||||||
- `m_FlipEdgeVertical`
|
|
||||||
- `flipEdgeVertical`
|
|
||||||
- `m_FlipFillCenter`
|
|
||||||
- `flipFillCenter`
|
|
||||||
- `m_FlipDirection`
|
|
||||||
- `flipDirection`
|
|
||||||
- `RemapVertex(ref UIVertex vertex, FlipMode flipMode, float Min1, float Max1, float Min2, float Max2)`
|
|
||||||
|
|
||||||
### 枚举
|
|
||||||
- `ColorType`
|
|
||||||
- `GradientDirection`
|
|
||||||
- `FlipPart`
|
|
||||||
- `FlipDirection`
|
|
||||||
- `FlipMode`
|
|
||||||
- `FlipEdge`
|
|
||||||
- `FlipEdgeHorizontal`
|
|
||||||
- `FlipEdgeVertical`
|
|
||||||
- `FlipFillCenter`
|
|
||||||
|
|
||||||
### 辅助类型
|
|
||||||
- `Vert2D`
|
|
||||||
- `Comparer`
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6661d6e0bda019844b46c7b7e087a16a
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
# UIExtension UXNavigation 导航模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXNavigation` 在新输入系统下增强 UI 导航,支持输入模式识别、导航作用域、默认选中项、上次选中记忆和跳过导航对象。
|
|
||||||
|
|
||||||
## 适用场景
|
|
||||||
- 手柄导航友好的菜单与弹窗。
|
|
||||||
- 多层 UI 叠加时管理焦点归属。
|
|
||||||
- 鼠标与手柄输入模式自动切换。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
### 枚举:`UXInputMode`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Navigation/UXInputMode.cs`
|
|
||||||
- 表示当前输入模式。
|
|
||||||
|
|
||||||
### 类型:`UXInputModeService`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Navigation/UXInputModeService.cs`
|
|
||||||
- `CurrentMode`
|
|
||||||
- `OnModeChanged`
|
|
||||||
|
|
||||||
### 类型:`UXNavigationScope`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Navigation/UXNavigationScope.cs`
|
|
||||||
- 属性:`DefaultSelectable`、`RememberLastSelection`、`RequireSelectionWhenGamepad`、`BlockLowerScopes`
|
|
||||||
- 方法:`InvalidateSelectableCache()`
|
|
||||||
|
|
||||||
### 类型:`UXNavigationSkip`
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Navigation/UXNavigationSkip.cs`
|
|
||||||
- 标记对象跳过导航体系。
|
|
||||||
|
|
||||||
### 其他核心类型
|
|
||||||
- `UXNavigationRuntime`
|
|
||||||
- `UXNavigationLayerWatcher`
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
scope.DefaultSelectable = firstSelectable;
|
|
||||||
```
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f349249d5e2bb9d409be050f28f8562d
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
# UIExtension UXSelectable 选择态增强模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXSelectable` 是 `Selectable` 的增强基类,支持对子图形做额外颜色/精灵过渡,并重写方向查找逻辑。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Selectable/UXSelectable.cs`
|
|
||||||
|
|
||||||
### 类型:`TransitionData`
|
|
||||||
- `targetGraphic`
|
|
||||||
- `transition`
|
|
||||||
- `colors`
|
|
||||||
- `spriteState`
|
|
||||||
|
|
||||||
### 类型:`UXSelectable`
|
|
||||||
- `FindSelectableOnLeft()`
|
|
||||||
- `FindSelectableOnRight()`
|
|
||||||
- `FindSelectableOnUp()`
|
|
||||||
- `FindSelectableOnDown()`
|
|
||||||
|
|
||||||
## 使用建议
|
|
||||||
- 若控件的多个子节点需要跟随选择态变化,可优先通过 `TransitionData` 配置。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 28b1ee8e6cd0239429b1ff80625c8f6e
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
# UIExtension UXTextMeshPro 文本模块手册
|
|
||||||
|
|
||||||
## 模块概述
|
|
||||||
`UXTextMeshPro` 扩展了 `TextMeshProUGUI`,用于接入项目本地化系统并支持编辑器预览刷新。
|
|
||||||
|
|
||||||
## 可调用 API
|
|
||||||
源码:`Packages/com.alicizax.unity.ui.extension/Runtime/UXComponent/Text/UXTextMeshPro.cs`
|
|
||||||
- `SetLocalization(string localizationID)`
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
```csharp
|
|
||||||
text.SetLocalization("UI_Common_Confirm");
|
|
||||||
```
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
- 需先通过 `UXComponentExtensionsHelper.SetLocalizationHelper()` 注入本地化帮助器。
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: cd107b4f367d78f4b903f7be1908cdd6
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -12,4 +12,70 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 32739bac255eb5f428628746c6e427f4, type: 3}
|
m_Script: {fileID: 11500000, guid: 32739bac255eb5f428628746c6e427f4, type: 3}
|
||||||
m_Name: PoolConfig
|
m_Name: PoolConfig
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
configs: []
|
entries:
|
||||||
|
- entryName: PoolEntry1
|
||||||
|
group: Default
|
||||||
|
assetPath:
|
||||||
|
matchMode: 0
|
||||||
|
loaderType: 0
|
||||||
|
overflowPolicy: 0
|
||||||
|
trimPolicy: 1
|
||||||
|
activationMode: 0
|
||||||
|
resetMode: 1
|
||||||
|
minRetained: 0
|
||||||
|
softCapacity: 8
|
||||||
|
hardCapacity: 8
|
||||||
|
idleTrimDelay: 30
|
||||||
|
prefabUnloadDelay: 60
|
||||||
|
autoRecycleDelay: 0
|
||||||
|
trimBatchPerTick: 2
|
||||||
|
warmupBatchPerFrame: 2
|
||||||
|
warmupFrameBudgetMs: 1
|
||||||
|
allowRuntimeExpand: 0
|
||||||
|
keepPrefabResident: 0
|
||||||
|
aggressiveTrimOnLowMemory: 0
|
||||||
|
priority: 0
|
||||||
|
- entryName: PoolEntry2
|
||||||
|
group: Default
|
||||||
|
assetPath:
|
||||||
|
matchMode: 0
|
||||||
|
loaderType: 0
|
||||||
|
overflowPolicy: 0
|
||||||
|
trimPolicy: 1
|
||||||
|
activationMode: 0
|
||||||
|
resetMode: 1
|
||||||
|
minRetained: 0
|
||||||
|
softCapacity: 8
|
||||||
|
hardCapacity: 8
|
||||||
|
idleTrimDelay: 30
|
||||||
|
prefabUnloadDelay: 60
|
||||||
|
autoRecycleDelay: 0
|
||||||
|
trimBatchPerTick: 2
|
||||||
|
warmupBatchPerFrame: 2
|
||||||
|
warmupFrameBudgetMs: 1
|
||||||
|
allowRuntimeExpand: 0
|
||||||
|
keepPrefabResident: 0
|
||||||
|
aggressiveTrimOnLowMemory: 0
|
||||||
|
priority: 1
|
||||||
|
- entryName: PoolEntry3
|
||||||
|
group: Default
|
||||||
|
assetPath:
|
||||||
|
matchMode: 0
|
||||||
|
loaderType: 0
|
||||||
|
overflowPolicy: 0
|
||||||
|
trimPolicy: 1
|
||||||
|
activationMode: 0
|
||||||
|
resetMode: 1
|
||||||
|
minRetained: 0
|
||||||
|
softCapacity: 8
|
||||||
|
hardCapacity: 8
|
||||||
|
idleTrimDelay: 30
|
||||||
|
prefabUnloadDelay: 60
|
||||||
|
autoRecycleDelay: 0
|
||||||
|
trimBatchPerTick: 2
|
||||||
|
warmupBatchPerFrame: 2
|
||||||
|
warmupFrameBudgetMs: 1
|
||||||
|
allowRuntimeExpand: 0
|
||||||
|
keepPrefabResident: 0
|
||||||
|
aggressiveTrimOnLowMemory: 0
|
||||||
|
priority: 2
|
||||||
|
|||||||
@ -67,7 +67,7 @@ TextureImporter:
|
|||||||
swizzle: 50462976
|
swizzle: 50462976
|
||||||
cookieLightType: 1
|
cookieLightType: 1
|
||||||
platformSettings:
|
platformSettings:
|
||||||
- serializedVersion: 4
|
- serializedVersion: 3
|
||||||
buildTarget: DefaultTexturePlatform
|
buildTarget: DefaultTexturePlatform
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 2048
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
@ -80,7 +80,7 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
- serializedVersion: 4
|
- serializedVersion: 3
|
||||||
buildTarget: Standalone
|
buildTarget: Standalone
|
||||||
maxTextureSize: 2048
|
maxTextureSize: 2048
|
||||||
resizeAlgorithm: 0
|
resizeAlgorithm: 0
|
||||||
@ -93,11 +93,23 @@ TextureImporter:
|
|||||||
ignorePlatformSupport: 0
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: WebGL
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
sprites: []
|
sprites: []
|
||||||
outline: []
|
outline: []
|
||||||
customData:
|
|
||||||
physicsShape: []
|
physicsShape: []
|
||||||
bones: []
|
bones: []
|
||||||
spriteID: 5e97eb03825dee720800000000000000
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
@ -107,8 +119,6 @@ TextureImporter:
|
|||||||
edges: []
|
edges: []
|
||||||
weights: []
|
weights: []
|
||||||
secondaryTextures: []
|
secondaryTextures: []
|
||||||
spriteCustomMetadata:
|
|
||||||
entries: []
|
|
||||||
nameFileIdTable: {}
|
nameFileIdTable: {}
|
||||||
mipmapLimitGroupName:
|
mipmapLimitGroupName:
|
||||||
pSDRemoveMatte: 0
|
pSDRemoveMatte: 0
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 00a54e10cd11cbd419de04cbd506b6d3
|
guid: bf510dab34b4e7847a7819b48a1cf122
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
BIN
Client/Assets/Bundles/UIRaw/Atlas/Common/bb/tst.png
Normal file
BIN
Client/Assets/Bundles/UIRaw/Atlas/Common/bb/tst.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 806 B |
127
Client/Assets/Bundles/UIRaw/Atlas/Common/bb/tst.png.meta
Normal file
127
Client/Assets/Bundles/UIRaw/Atlas/Common/bb/tst.png.meta
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5fe20064a619ceb4aacf49802ee4f70e
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 13
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
flipGreenChannel: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
vTOnly: 0
|
||||||
|
ignoreMipmapLimit: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: 1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: 0
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: 1
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 0
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
flipbookRows: 1
|
||||||
|
flipbookColumns: 1
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
ignorePngGamma: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
swizzle: 50462976
|
||||||
|
cookieLightType: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: Standalone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: WebGL
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
nameFileIdTable: {}
|
||||||
|
mipmapLimitGroupName:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -41,6 +41,7 @@ namespace GameLogic
|
|||||||
{
|
{
|
||||||
GameLocaizationTable table = await GameApp.Resource.LoadAssetAsync<GameLocaizationTable>("LocalizationTable");
|
GameLocaizationTable table = await GameApp.Resource.LoadAssetAsync<GameLocaizationTable>("LocalizationTable");
|
||||||
GameApp.Localization.IncreAddLocalizationConfig(table);
|
GameApp.Localization.IncreAddLocalizationConfig(table);
|
||||||
|
GameApp.Resource.UnloadAsset(table);
|
||||||
Log.Info("加载多语言配置表完毕");
|
Log.Info("加载多语言配置表完毕");
|
||||||
GameApp.UI.ShowUISync<UILoadUpdate>();
|
GameApp.UI.ShowUISync<UILoadUpdate>();
|
||||||
Log.Info("sdadasdas");
|
Log.Info("sdadasdas");
|
||||||
|
|||||||
@ -68,19 +68,18 @@ namespace Unity.Startup.Procedure
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void SetProgressUpdate(AssetDownloadProgressUpdateEventArgs gameEventArgs)
|
private static void SetProgressUpdate(in AssetDownloadProgressUpdateEventArgs gameEventArgs)
|
||||||
{
|
{
|
||||||
var message = (AssetDownloadProgressUpdateEventArgs)gameEventArgs;
|
_currentDownloadBytes = gameEventArgs.CurrentDownloadSizeBytes;
|
||||||
_currentDownloadBytes = message.CurrentDownloadSizeBytes;
|
float progress = gameEventArgs.CurrentDownloadSizeBytes / (gameEventArgs.TotalDownloadSizeBytes * 1f);
|
||||||
float progress = message.CurrentDownloadSizeBytes / (message.TotalDownloadSizeBytes * 1f);
|
string currentSizeMb = Utility.File.GetBytesSize(gameEventArgs.CurrentDownloadSizeBytes);
|
||||||
string currentSizeMb = Utility.File.GetBytesSize(message.CurrentDownloadSizeBytes);
|
string totalSizeMb = Utility.File.GetBytesSize(gameEventArgs.TotalDownloadSizeBytes);
|
||||||
string totalSizeMb = Utility.File.GetBytesSize(message.TotalDownloadSizeBytes);
|
|
||||||
string speed = Utility.File.GetLengthString((int)CurrentSpeed);
|
string speed = Utility.File.GetLengthString((int)CurrentSpeed);
|
||||||
|
|
||||||
|
|
||||||
string line1 = Utility.Text.Format("正在更新,已更新 {0}/{1} ({2:F2}%)", message.CurrentDownloadCount, message.TotalDownloadCount, progress);
|
string line1 = Utility.Text.Format("正在更新,已更新 {0}/{1} ({2:F2}%)", gameEventArgs.CurrentDownloadCount, gameEventArgs.TotalDownloadCount, progress);
|
||||||
string line2 = Utility.Text.Format("已更新大小 {0}MB/{1}MB", currentSizeMb, totalSizeMb);
|
string line2 = Utility.Text.Format("已更新大小 {0}MB/{1}MB", currentSizeMb, totalSizeMb);
|
||||||
string line3 = Utility.Text.Format("当前网速 {0}/s,剩余时间 {1}", speed, GetRemainingTime(message.TotalDownloadSizeBytes, message.CurrentDownloadSizeBytes, CurrentSpeed));
|
string line3 = Utility.Text.Format("当前网速 {0}/s,剩余时间 {1}", speed, GetRemainingTime(gameEventArgs.TotalDownloadSizeBytes, gameEventArgs.CurrentDownloadSizeBytes, CurrentSpeed));
|
||||||
|
|
||||||
|
|
||||||
Log.Info($"{line1} \n {line2}\n {line3}");
|
Log.Info($"{line1} \n {line2}\n {line3}");
|
||||||
|
|||||||
@ -15,9 +15,8 @@ MonoBehaviour:
|
|||||||
debugShaders:
|
debugShaders:
|
||||||
debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3}
|
debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3}
|
||||||
hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3}
|
hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3}
|
||||||
m_RendererFeatures:
|
m_RendererFeatures: []
|
||||||
- {fileID: 7833122117494664109}
|
m_RendererFeatureMap:
|
||||||
m_RendererFeatureMap: ad6b866f10d7b46c
|
|
||||||
m_UseNativeRenderPass: 1
|
m_UseNativeRenderPass: 1
|
||||||
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
|
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
|
||||||
xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2}
|
xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2}
|
||||||
@ -56,38 +55,3 @@ MonoBehaviour:
|
|||||||
m_CopyDepthMode: 0
|
m_CopyDepthMode: 0
|
||||||
m_AccurateGbufferNormals: 0
|
m_AccurateGbufferNormals: 0
|
||||||
m_IntermediateTextureMode: 0
|
m_IntermediateTextureMode: 0
|
||||||
--- !u!114 &7833122117494664109
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
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: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3}
|
|
||||||
m_Name: ScreenSpaceAmbientOcclusion
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Active: 1
|
|
||||||
m_Settings:
|
|
||||||
AOMethod: 0
|
|
||||||
Downsample: 0
|
|
||||||
AfterOpaque: 0
|
|
||||||
Source: 1
|
|
||||||
NormalSamples: 1
|
|
||||||
Intensity: 0.4
|
|
||||||
DirectLightingStrength: 0.25
|
|
||||||
Radius: 0.3
|
|
||||||
Samples: 1
|
|
||||||
BlurQuality: 0
|
|
||||||
Falloff: 100
|
|
||||||
SampleCount: -1
|
|
||||||
m_BlueNoise256Textures:
|
|
||||||
- {fileID: 2800000, guid: 36f118343fc974119bee3d09e2111500, type: 3}
|
|
||||||
- {fileID: 2800000, guid: 4b7b083e6b6734e8bb2838b0b50a0bc8, type: 3}
|
|
||||||
- {fileID: 2800000, guid: c06cc21c692f94f5fb5206247191eeee, type: 3}
|
|
||||||
- {fileID: 2800000, guid: cb76dd40fa7654f9587f6a344f125c9a, type: 3}
|
|
||||||
- {fileID: 2800000, guid: e32226222ff144b24bf3a5a451de54bc, type: 3}
|
|
||||||
- {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3}
|
|
||||||
- {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3}
|
|
||||||
m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3}
|
|
||||||
|
|||||||
53
Client/Assets/TimerBugTest.cs
Normal file
53
Client/Assets/TimerBugTest.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using AlicizaX;
|
||||||
|
using AlicizaX.Timer.Runtime;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public sealed class TimerBugTest : MonoBehaviour
|
||||||
|
{
|
||||||
|
private ITimerService _timerService;
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
_timerService = AppServices.Require<ITimerService>();
|
||||||
|
|
||||||
|
Debug.Log("=== Timer Bug Test Started ===");
|
||||||
|
TestNormalOnceTimer();
|
||||||
|
TestStopInCallback();
|
||||||
|
TestRemoveInCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestNormalOnceTimer()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 1] Creating normal once timer (1 second)...");
|
||||||
|
_timerService.AddTimer(OnNormalOnceTimer, 1f, isLoop: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestStopInCallback()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 2] Creating once timer that calls Stop() in callback (2 seconds)...");
|
||||||
|
|
||||||
|
int timerId = 0;
|
||||||
|
timerId = _timerService.AddTimer(() =>
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 2] Timer callback executed, calling Stop()...");
|
||||||
|
_timerService.Stop(timerId);
|
||||||
|
}, 2f, isLoop: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestRemoveInCallback()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 3] Creating once timer that calls RemoveTimer() in callback (3 seconds)...");
|
||||||
|
|
||||||
|
int timerId = 0;
|
||||||
|
timerId = _timerService.AddTimer(() =>
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 3] Timer callback executed, calling RemoveTimer()...");
|
||||||
|
_timerService.RemoveTimer(timerId);
|
||||||
|
}, 3f, isLoop: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnNormalOnceTimer()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 1] Timer callback executed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Client/Assets/TimerBugTest.cs.meta
Normal file
11
Client/Assets/TimerBugTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b84897f4b42a76e4fa7c21be2fdd47d0
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
122
Client/Assets/TimerGenericTest.cs
Normal file
122
Client/Assets/TimerGenericTest.cs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
using AlicizaX;
|
||||||
|
using AlicizaX.Timer.Runtime;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public sealed class TimerGenericTest : MonoBehaviour
|
||||||
|
{
|
||||||
|
private sealed class IntBox
|
||||||
|
{
|
||||||
|
public int Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class PlayerData
|
||||||
|
{
|
||||||
|
public int Id;
|
||||||
|
public string Name;
|
||||||
|
public int Score;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class Enemy
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public int Health;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ITimerService _timerService;
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
_timerService = AppServices.Require<ITimerService>();
|
||||||
|
|
||||||
|
Debug.Log("=== Timer Generic Test Started ===");
|
||||||
|
TestNoArgs();
|
||||||
|
TestIntArg();
|
||||||
|
TestStringArg();
|
||||||
|
TestPlayerDataArg();
|
||||||
|
TestClassArg();
|
||||||
|
TestLoopWithArg();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestNoArgs()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 1] No args timer (1s)");
|
||||||
|
_timerService.AddTimer(OnNoArgsCallback, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnNoArgsCallback()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 1] Callback executed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestIntArg()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 2] Boxed int reference timer (2s)");
|
||||||
|
_timerService.AddTimer(OnIntCallback, new IntBox { Value = 42 }, 2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnIntCallback(IntBox value)
|
||||||
|
{
|
||||||
|
Debug.Log(Utility.Text.Format("[Test 2] Int callback executed! Value: {0}", value.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestStringArg()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 3] String arg timer (3s)");
|
||||||
|
_timerService.AddTimer(OnStringCallback, "Hello Timer!", 3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnStringCallback(string message)
|
||||||
|
{
|
||||||
|
Debug.Log(Utility.Text.Format("[Test 3] String callback executed! Message: {0}", message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestPlayerDataArg()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 4] PlayerData class arg timer (4s)");
|
||||||
|
_timerService.AddTimer(OnPlayerDataCallback, new PlayerData
|
||||||
|
{
|
||||||
|
Id = 123,
|
||||||
|
Name = "Alice",
|
||||||
|
Score = 9999
|
||||||
|
}, 4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnPlayerDataCallback(PlayerData data)
|
||||||
|
{
|
||||||
|
Debug.Log(Utility.Text.Format("[Test 4] Player callback executed! Player: {0} (ID: {1}, Score: {2})", data.Name, data.Id, data.Score));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestClassArg()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 5] Class arg timer (5s)");
|
||||||
|
_timerService.AddTimer(OnClassCallback, new Enemy
|
||||||
|
{
|
||||||
|
Name = "Goblin",
|
||||||
|
Health = 100
|
||||||
|
}, 5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnClassCallback(Enemy enemy)
|
||||||
|
{
|
||||||
|
Debug.Log(Utility.Text.Format("[Test 5] Class callback executed! Enemy: {0}, Health: {1}", enemy.Name, enemy.Health));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestLoopWithArg()
|
||||||
|
{
|
||||||
|
Debug.Log("[Test 6] Loop timer with reference arg (0.5s interval)");
|
||||||
|
IntBox counter = new IntBox { Value = 1 };
|
||||||
|
int timerId = 0;
|
||||||
|
timerId = _timerService.AddTimer(count =>
|
||||||
|
{
|
||||||
|
Debug.Log(Utility.Text.Format("[Test 6] Loop callback #{0}", count.Value));
|
||||||
|
if (count.Value >= 3)
|
||||||
|
{
|
||||||
|
_timerService.RemoveTimer(timerId);
|
||||||
|
Debug.Log("[Test 6] Loop timer removed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
count.Value++;
|
||||||
|
}, counter, 0.5f, isLoop: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Client/Assets/TimerGenericTest.cs.meta
Normal file
11
Client/Assets/TimerGenericTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d7b412d41637467439d2e1e391f91c67
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 55079f02326c270468f1eca1808de28c
|
guid: 23fc170912d33cd499f7f04b662a6e9a
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 8e2de7df9f6693246b6ce82a1753c975
|
guid: 9f2ea1142ef07324b8f6e23022cc34e5
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
@import url("unity-theme://default");
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e65490858afddc54a80013f2f6e36e21
|
||||||
|
ScriptedImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
script: {fileID: 12388, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
disableValidation: 0
|
||||||
@ -0,0 +1 @@
|
|||||||
|
Simulate
|
||||||
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
0f2260db
|
||||||
@ -0,0 +1,185 @@
|
|||||||
|
{
|
||||||
|
"FileVersion": "2025.9.30",
|
||||||
|
"EnableAddressable": true,
|
||||||
|
"SupportExtensionless": true,
|
||||||
|
"LocationToLower": false,
|
||||||
|
"IncludeAssetGUID": false,
|
||||||
|
"ReplaceAssetPathWithAddress": false,
|
||||||
|
"OutputNameStyle": 0,
|
||||||
|
"BuildBundleType": 1,
|
||||||
|
"BuildPipeline": "EditorSimulateBuildPipeline",
|
||||||
|
"PackageName": "DefaultPackage",
|
||||||
|
"PackageVersion": "Simulate",
|
||||||
|
"PackageNote": "2026/4/24 20:49:52",
|
||||||
|
"AssetList": [
|
||||||
|
{
|
||||||
|
"Address": "LocalizationTable",
|
||||||
|
"AssetPath": "Assets/Bundles/Configs/LocalizationTable.asset",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"WEBGL_PRELOAD",
|
||||||
|
"Configs"
|
||||||
|
],
|
||||||
|
"BundleID": 0,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Address": "PoolConfig",
|
||||||
|
"AssetPath": "Assets/Bundles/Configs/PoolConfig.asset",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"WEBGL_PRELOAD",
|
||||||
|
"Configs"
|
||||||
|
],
|
||||||
|
"BundleID": 0,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Address": "Map1000",
|
||||||
|
"AssetPath": "Assets/Bundles/Scenes/Map1000.unity",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"Scenes"
|
||||||
|
],
|
||||||
|
"BundleID": 1,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Address": "MyShaderVariants",
|
||||||
|
"AssetPath": "Assets/Bundles/ShaderVariants/MyShaderVariants.shadervariants",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"ShaderVariants"
|
||||||
|
],
|
||||||
|
"BundleID": 6,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Address": "UILoadUpdateWindow",
|
||||||
|
"AssetPath": "Assets/Bundles/UI/UILoadUpdateWindow.prefab",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"UI"
|
||||||
|
],
|
||||||
|
"BundleID": 2,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Address": "UILogicTestAlert",
|
||||||
|
"AssetPath": "Assets/Bundles/UI/Window/UILogicTestAlert.prefab",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"UI"
|
||||||
|
],
|
||||||
|
"BundleID": 3,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Address": "tst",
|
||||||
|
"AssetPath": "Assets/Bundles/UIRaw/Atlas/Common/bb/tst.png",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"UIRaw"
|
||||||
|
],
|
||||||
|
"BundleID": 4,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Address": "Brush Impact 5",
|
||||||
|
"AssetPath": "Assets/Bundles/UIRaw/Atlas/Common/Grunge/Brush Impact 5.png",
|
||||||
|
"AssetGUID": "",
|
||||||
|
"AssetTags": [
|
||||||
|
"UIRaw"
|
||||||
|
],
|
||||||
|
"BundleID": 5,
|
||||||
|
"DependBundleIDs": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"BundleList": [
|
||||||
|
{
|
||||||
|
"BundleName": "assets_bundles_configs.bundle",
|
||||||
|
"UnityCRC": 0,
|
||||||
|
"FileHash": "3a378d308429cd99b280d880a27af478",
|
||||||
|
"FileCRC": 0,
|
||||||
|
"FileSize": 6942,
|
||||||
|
"Encrypted": false,
|
||||||
|
"Tags": [
|
||||||
|
"WEBGL_PRELOAD",
|
||||||
|
"Configs"
|
||||||
|
],
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BundleName": "assets_bundles_scenes_map1000.bundle",
|
||||||
|
"UnityCRC": 0,
|
||||||
|
"FileHash": "4530edb970dd229fed5dd3259fee4ece",
|
||||||
|
"FileCRC": 0,
|
||||||
|
"FileSize": 12277,
|
||||||
|
"Encrypted": false,
|
||||||
|
"Tags": [
|
||||||
|
"Scenes"
|
||||||
|
],
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BundleName": "assets_bundles_ui_uiloadupdatewindow.bundle",
|
||||||
|
"UnityCRC": 0,
|
||||||
|
"FileHash": "9ff2ef11fc95cbce9b51368acd1d4383",
|
||||||
|
"FileCRC": 0,
|
||||||
|
"FileSize": 59076,
|
||||||
|
"Encrypted": false,
|
||||||
|
"Tags": [
|
||||||
|
"UI"
|
||||||
|
],
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BundleName": "assets_bundles_ui_window_uilogictestalert.bundle",
|
||||||
|
"UnityCRC": 0,
|
||||||
|
"FileHash": "cf84038a2a1620e6ff49815bcd8e6a73",
|
||||||
|
"FileCRC": 0,
|
||||||
|
"FileSize": 21519,
|
||||||
|
"Encrypted": false,
|
||||||
|
"Tags": [
|
||||||
|
"UI"
|
||||||
|
],
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BundleName": "assets_bundles_uiraw_atlas_common_bb.bundle",
|
||||||
|
"UnityCRC": 0,
|
||||||
|
"FileHash": "472a7fd3623bc56802c6e39c904d00a3",
|
||||||
|
"FileCRC": 0,
|
||||||
|
"FileSize": 806,
|
||||||
|
"Encrypted": false,
|
||||||
|
"Tags": [
|
||||||
|
"UIRaw"
|
||||||
|
],
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BundleName": "assets_bundles_uiraw_atlas_common_grunge.bundle",
|
||||||
|
"UnityCRC": 0,
|
||||||
|
"FileHash": "3dcf5b07fab616778c379807810653ea",
|
||||||
|
"FileCRC": 0,
|
||||||
|
"FileSize": 36701,
|
||||||
|
"Encrypted": false,
|
||||||
|
"Tags": [
|
||||||
|
"UIRaw"
|
||||||
|
],
|
||||||
|
"DependBundleIDs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BundleName": "unityshaders.bundle",
|
||||||
|
"UnityCRC": 0,
|
||||||
|
"FileHash": "c9f21eee9f3febcafa65a26802cf31f0",
|
||||||
|
"FileCRC": 0,
|
||||||
|
"FileSize": 3518,
|
||||||
|
"Encrypted": false,
|
||||||
|
"Tags": [
|
||||||
|
"ShaderVariants"
|
||||||
|
],
|
||||||
|
"DependBundleIDs": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 8d9b4a32ce2274020796f54a9f0465725d0bd84f
|
Subproject commit 28edc2dfa710217fa3446e7e500b0030d9020263
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 9d755479987795111e7b8721713b70abf98846e5
|
Subproject commit f4f0ea1754a33b3e224d04cbcccedacfd41fe278
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit ae16bdcf37f77929aec1c6178321c333ad9d4d92
|
Subproject commit 8c3c13634d25ce3a1808253962e483c9bbbd9f66
|
||||||
@ -30,10 +30,10 @@ EditorUserSettings:
|
|||||||
value: 0606045450065e5d55575a241522064444161c797f7b7234757c4f32e1b0353d
|
value: 0606045450065e5d55575a241522064444161c797f7b7234757c4f32e1b0353d
|
||||||
flags: 0
|
flags: 0
|
||||||
RecentlyUsedSceneGuid-7:
|
RecentlyUsedSceneGuid-7:
|
||||||
value: 5a07065703500c59585e0e7748770d44444f4a737d2d7f35787d4f63e0b26668
|
value: 5001560504060c590f5b0f7245725a44404f1d7c297e2233787e4a36b5e4666b
|
||||||
flags: 0
|
flags: 0
|
||||||
RecentlyUsedSceneGuid-8:
|
RecentlyUsedSceneGuid-8:
|
||||||
value: 5001560504060c590f5b0f7245725a44404f1d7c297e2233787e4a36b5e4666b
|
value: 5a07065703500c59585e0e7748770d44444f4a737d2d7f35787d4f63e0b26668
|
||||||
flags: 0
|
flags: 0
|
||||||
RecentlyUsedSceneGuid-9:
|
RecentlyUsedSceneGuid-9:
|
||||||
value: 50500404540c580d0f0b5e7543725b44424f4c7a7b7c7734747e4f36e4b1676d
|
value: 50500404540c580d0f0b5e7543725b44424f4c7a7b7c7734747e4f36e4b1676d
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user