Files
zeling_v2/Docs/Standards/AssetFolderSpec.md
Joywayer e879efaa89 Add InputDeviceIconSetSO configuration guide and related documentation
- Created a new markdown file detailing the configuration of InputDeviceIconSetSO.
- Included sections on system architecture, field explanations, image specifications, and complete workflow from setup to runtime.
- Documented the automatic device recognition logic and provided troubleshooting for common issues.
- Added references to relevant files and scripts for easier navigation.
2026-05-23 00:10:23 +08:00

907 lines
52 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 资源文件夹目录规划与管理规范
> **版本**1.3
> **创建日期**2026-05
> **适用范围**`Assets/` 目录下所有非代码资源(美术、数据、预制体、场景等)
> **资源管理系统**Unity Addressables禁止使用 `Resources.Load`
> **关联文档**`Architecture/01_ProjectStructure.md`、`Architecture/13_AssetPoolModule.md`
---
## 目录
1. [为什么使用 `_Game/` 父目录](#0-为什么使用-_game-父目录)
2. [整体目录结构总览](#1-整体目录结构总览)
3. [Art/ 美术资源规范](#2-art-美术资源规范)
4. [Data/ ScriptableObject 规范](#3-data-scriptableobject-规范)
5. [Prefabs/ 预制体规范](#4-prefabs-预制体规范)
6. [Scenes/ 场景规范](#5-scenes-场景规范)
7. [Shaders/ 着色器规范](#6-shaders-着色器规范)
8. [UI Toolkit/ 规范](#7-ui-toolkit-规范)
9. [Addressables 管理规范](#8-addressables-管理规范)
10. [Import Settings 规范](#9-import-settings-规范)
11. [资源新增工作流](#10-资源新增工作流)
12. [禁止行为清单](#11-禁止行为清单)
13. [编辑器工具参考](#12-编辑器工具参考)
---
## 0. 为什么使用 `_Game/` 父目录
### 核心矛盾
Unity 项目的 `Assets/` 根目录通常同时存放**第一方游戏内容**和**第三方插件目录**。两者混杂会导致:
- Project 窗口难以快速定位自有资产(需要在 `Art/``Feel/``Opsive/` 之间来回跳转)
- 插件升级时不清楚哪些目录是项目本身的
- 构建分析工具(如 Addressables Analyze、Build Layout的输出路径噪音多
### 解决方案:`_Game/` 父目录
将**所有第一方资产**归入 `Assets/_Game/`,下划线前缀使其在字母排序中始终置顶。
```
Assets/
├── _Game/ ← 所有第一方资产Art、Data、Prefabs、Scenes、Scripts 等)
├── AddressableAssetsData/ ← Unity 托管,必须保持在 Assets/ 根
├── Feel/ ← 第三方(只读)
├── Opsive/ ← 第三方(只读)
├── PathBerserker2d/ ← 第三方(只读)
├── Plugins/ ← 第三方(只读)
└── Tests/ ← 测试(可独立于 _Game/
```
### 迁移注意事项
| 项目 | 说明 |
|------|------|
| `AddressableAssetsData/` | **必须留在 `Assets/` 根目录**Unity Addressables 硬编码此路径 |
| `Settings/` | URP asset、Input Actions 等 Unity 项目设置文件可随 `_Game/` 迁移 |
| `Resources/` | 如存在,应逐步清空并删除;过渡期可临时留在根目录 |
| `StreamingAssets/` | 必须留在 `Assets/` 根目录Unity 特殊文件夹) |
| asmdef 路径 | 迁移 `Scripts/` 后需在 Unity 中重新扫描asmdef 引用由 GUID 追踪,路径变更不影响依赖 |
---
## 1. 整体目录结构总览
```
Assets/
├── _Game/ ← 所有第一方游戏资产
│ ├── Art/ 美术源文件Sprites、Animations、Materials、Atlases
│ │ ├── Characters/ 角色美术(玩家 / 敌人 / NPC
│ │ │ ├── Player/ 按形态 ID 分子目录Player01、Player02…
│ │ │ ├── Enemies/ 按敌人 ID 分子目录E001、E002…
│ │ │ └── NPCs/ 非战斗 NPC按角色名分子目录
│ │ ├── Environment/ 场景环境Tilesets、Backgrounds、Props
│ │ ├── Effects/ 特效美术Sprites、Materials、Atlases
│ │ ├── UI/ UI 专用图片Icons、Frames、Backgrounds、Atlases、Materials
│ │ │ ├── Icons/
│ │ │ │ ├── Skills/ 技能图标
│ │ │ │ ├── Items/ 道具 / 护身符图标
│ │ │ │ ├── Status/ 状态效果图标
│ │ │ │ └── InputKeys/ 按键/手柄按键图标(供 InputDeviceIconSetSO 引用)
│ │ │ ├── Frames/
│ │ │ ├── Backgrounds/
│ │ │ └── Atlases/
│ │ └── Shared/ 跨模块复用基础资产Palettes、Textures、Materials
│ │
│ ├── Data/ ScriptableObject 资产(按模块分类)
│ │ ├── Events/ 事件频道 SO按模块分子目录
│ │ ├── Player/
│ │ ├── Combat/
│ │ ├── Enemies/
│ │ ├── Progression/
│ │ ├── Audio/
│ │ ├── World/
│ │ ├── UI/
│ │ │ ├── Panels/ UI 面板配置 SO
│ │ │ └── InputIcons/ 按键图标集 SOInputDeviceIconSetSO每设备一个文件
│ │ └── Settings/
│ │
│ ├── Prefabs/ 预制体
│ │ ├── Player/
│ │ ├── Enemies/
│ │ ├── Combat/
│ │ ├── Effects/
│ │ ├── Environment/ 场景骨架结构Tilemap 层、视差背景层)
│ │ ├── World/
│ │ ├── UI/
│ │ └── Persistent/ Persistent 场景专属 Prefabs
│ │
│ ├── Scenes/ 场景文件
│ │ └── Testings/ 测试专用场景(不进入 Addressables 构建)
│ │
│ ├── Scripts/ 游戏代码(见 Architecture/01_ProjectStructure.md
│ │
│ ├── Shaders/ 自定义着色器 & HLSL include
│ │ ├── BaseASE/ Shader Graph / ASE 材质图
│ │ └── Includes/ 共享 HLSL 函数库ColorUtils、NoiseUtils 等)
│ │
│ ├── UI Toolkit/ UITK 资产UXML、USS、主题
│ │ ├── Layouts/
│ │ ├── Styles/
│ │ └── UnityThemes/
│ │
│ └── Settings/ URP 配置、Input Actions 等项目设置资产
├── AddressableAssetsData/ ← Unity 托管,必须在 Assets/ 根(不可移动)
├── StreamingAssets/ ← Unity 特殊文件夹(如有 FMOD bank
├── Feel/ ← MoreMountains Feel 插件(只读)
├── Opsive/ ← Behavior Designer 插件(只读)
├── PathBerserker2d/ ← 寻路插件(只读)
├── Plugins/ ← 其他第三方插件(只读)
└── Tests/ ← EditMode / PlayMode 测试(可在 _Game/ 外独立维护)
```
> **强制约束**`AddressableAssetsData/` 和 `StreamingAssets/` 是 Unity 硬编码路径,**永远不得移入 `_Game/`**。所有第三方插件目录**不修改内部结构**,定制内容一律放入 `_Game/` 下的对应模块目录。
---
## 2. Art/ 美术资源规范
### 2.1 目录结构
```
Art/
├── Characters/ 角色美术资产(玩家 / 敌人 / NPC
│ ├── Player/ 玩家角色,按形态 ID 分子目录
│ │ └── {FormID}/ 例Player01、Player02
│ │ ├── Sprites/ 像素帧图 (.png) + Emission 自发光贴图PPU=32, Filter=Point · PLY_{FormID}_{Action}.png
│ │ ├── Animations/ 动作片段 (.anim) + 状态机控制器 (.controller)12fps · {Action}.anim / PLY_{FormID}_Animator.controller
│ │ ├── Materials/ 渲染材质 (.mat),引用角色 Shader控制 Emission、受击闪白参数· PLY_{FormID}.mat
│ │ └── Atlases/ Sprite 图集 (.spriteatlas),合并同形态所有帧,减少 DrawCall · Atlas_Player_{FormID}.spriteatlas
│ ├── Enemies/ 敌人,按 ID 分子目录ID 与 AddressKeys ENM_ 前缀对应)
│ │ └── {EnemyID}/ 例E001、E002
│ │ ├── Sprites/ 像素帧图 (.png) + Emission 贴图PPU=32 · {ID}_{Name}_{Action}.png
│ │ ├── Animations/ 动作片段 (.anim) + 状态机控制器 (.controller) · {Action}.anim / {ID}_{Name}_Animator.controller
│ │ ├── Materials/ 渲染材质 (.mat),引用角色 Shader · {ID}.mat
│ │ └── Atlases/ Sprite 图集 (.spriteatlas),含主体与 Emission 帧 · Atlas_Enemy_{ID}.spriteatlas
│ └── NPCs/ 非战斗 NPC按角色名分子目录
│ └── {NPCName}/
│ ├── Sprites/ 像素帧图 (.png) · {NPCName}_{Action}.png
│ ├── Animations/ 动作片段 (.anim) + 状态机控制器 (.controller) · {Action}.anim / {NPCName}_Animator.controller
│ ├── Materials/ 渲染材质 (.mat) · NPC_{NPCName}.mat
│ └── Atlases/ Sprite 图集 (.spriteatlas) · Atlas_NPC_{NPCName}.spriteatlas
├── Environment/ 场景环境资产
│ ├── Tilesets/ 瓦片纹理 (.png),配合 RuleTile 实现地形自动拼接
│ │ └── {Region}/ 按区域分子目录Forest、Dungeon、Cave· TILE_{Region}_{Name}.png
│ ├── Backgrounds/ 视差滚动背景图 (.png),按 Far / Mid / Near 分层渲染
│ │ └── {Region}/ 按区域分子目录 · BG_{Region}_{Layer}.png
│ └── Props/ 可复用场景道具纹理(箱子、灯柱、机关等,无逻辑纯视觉)
│ └── {Category}/ 按类别分子目录Furniture、Traps、Lights· PROP_{Category}_{Name}.png
├── Effects/ 特效美术资产Prefab 见 Prefabs/Effects/,此处仅存源图与材质)
│ ├── Sprites/ VFX 帧序列图 (.png)PPU=32用于粒子 / 帧动画特效 · VFX_{Description}.png
│ ├── Materials/ 特效专用材质 (.mat),引用 Effects Shader支持扭曲、混合· VFX_{Description}.mat
│ └── Atlases/ 高频特效 Sprite 图集 (.spriteatlas),减少特效渲染批次 · Atlas_Effects_{Name}.spriteatlas
├── UI/ UI 专用图片(布局 / 样式见 UI Toolkit/ 目录)
│ ├── Icons/ 图标按子类分目录,统一 32x32 或 64x64 规格
│ │ ├── Skills/ 技能图标,用于技能栏 / 技能选择界面 · IC_Skills_{Name}.png
│ │ ├── Items/ 道具 / 护身符图标,用于物品栏 · IC_Items_{Name}.png
│ │ ├── Status/ 状态效果图标(中毒、燃烧等),用于角色状态栏 · IC_Status_{Name}.png
│ │ └── InputKeys/ 按键/手柄按键图标,用于 InputDeviceIconSetSO 绑定路径图标映射 · IC_Key_{DeviceShort}_{KeyName}.png
│ ├── Frames/ 面板框架、血条框、对话框边框等 (.png) · FRAME_{Description}.png
│ ├── Backgrounds/ 界面背景图、全屏半透明遮罩、渐变填充图 (.png) · UIBG_{Description}.png
│ └── Atlases/ UI 图标与框架图集 (.spriteatlas),减少 UI 渲染批次 · Atlas_UI_{Category}.spriteatlas
└── Shared/ 跨模块复用的基础资产,不属于任何具体角色或场景
├── Palettes/ 色板参考文件 (.png / .aco),仅供美术设计参考,不用于运行时
└── Textures/ 通用基础纹理:噪点图、渐变纹理、光晕贴图,供 Shader 采样使用
```
### 2.2 美术文件命名规则
| 资产类型 | 存放位置 | 命名格式 | 示例 |
|---------|---------|---------|------|
| 敌人 Sprite Sheet | `_Game/Art/Characters/Enemies/{EnemyID}/Sprites/` | `{ID}_{Name}_{Action}.png` | `E001_CaoZhi_Idle.png` |
| 敌人 Emission 贴图 | `_Game/Art/Characters/Enemies/{EnemyID}/Sprites/` | `{ID}_{Name}_{Action}_Emission.png` | `E001_CaoZhi_Idle_Emission.png` |
| 敌人 AnimationClip | `_Game/Art/Characters/Enemies/{EnemyID}/Animations/` | `{Action}.anim` | `Idle.anim``Skill_Start.anim` |
| 敌人 AnimatorController | `_Game/Art/Characters/Enemies/{EnemyID}/Animations/` | `{ID}_{Name}_Animator.controller` | `E001_CaoZhi_Animator.controller` |
| 敌人材质 | `_Game/Art/Characters/Enemies/{EnemyID}/Materials/` | `{ID}.mat` | `E001.mat` |
| 玩家 Sprite Sheet | `_Game/Art/Characters/Player/{FormID}/Sprites/` | `PLY_{FormID}_{Action}.png` | `PLY_Player01_Run.png` |
| 玩家 AnimationClip | `_Game/Art/Characters/Player/{FormID}/Animations/` | `{Action}.anim` | `Idle.anim``Attack01.anim` |
| 玩家材质 | `_Game/Art/Characters/Player/{FormID}/Materials/` | `PLY_{FormID}.mat` | `PLY_Player01.mat` |
| 特效 Sprite Sheet | `_Game/Art/Effects/Sprites/` | `VFX_{Description}.png` | `VFX_HitSpark_Sheet.png` |
| 特效材质 | `_Game/Art/Effects/Materials/` | `VFX_{Description}.mat` | `VFX_HitSpark.mat` |
| 瓦片纹理 | `_Game/Art/Environment/Tilesets/{Region}/` | `TILE_{Region}_{Name}.png` | `TILE_Forest_Ground.png` |
| 背景层 | `_Game/Art/Environment/Backgrounds/{Region}/` | `BG_{Region}_{Layer}.png` | `BG_Forest_Far.png` |
| 场景道具 | `_Game/Art/Environment/Props/{Category}/` | `PROP_{Category}_{Name}.png` | `PROP_Furniture_Chest.png` |
| UI 图标 | `_Game/Art/UI/Icons/{SubType}/` | `IC_{Category}_{Name}.png` | `IC_Skills_SoulBlade.png` |
| 按键图标 | `_Game/Art/UI/Icons/InputKeys/` | `IC_Key_{DeviceShort}_{KeyName}.png` | `IC_Key_KBM_Space.png``IC_Key_Xbox_A.png` |
| UI 框架 | `_Game/Art/UI/Frames/` | `FRAME_{Description}.png` | `FRAME_HealthBar.png` |
| UI 背景 | `_Game/Art/UI/Backgrounds/` | `UIBG_{Description}.png` | `UIBG_PauseMenu.png` |
| 色板参考 | `_Game/Art/Shared/Palettes/` | `PAL_{Name}.png` | `PAL_Forest.png` |
### 2.3 Sprite Atlas 策略
| Atlas 文件 | 覆盖内容 | 存放位置 |
|-----------|---------|--------|
| `Atlas_Player_{FormID}.spriteatlas` | 该形态玩家所有 Sprite | `_Game/Art/Characters/Player/{FormID}/Atlases/` |
| `Atlas_Enemy_{EnemyID}.spriteatlas` | 该敌人所有 Sprite含 Emission| `_Game/Art/Characters/Enemies/{EnemyID}/Atlases/` |
| `Atlas_NPC_{NPCName}.spriteatlas` | 该 NPC 所有 Sprite | `_Game/Art/Characters/NPCs/{NPCName}/Atlases/` |
| `Atlas_Effects_Common.spriteatlas` | 通用高频特效 Sprite | `_Game/Art/Effects/Atlases/` |
| `Atlas_UI_Icons.spriteatlas` | 所有 UI 图标(技能/道具/状态)| `_Game/Art/UI/Atlases/` |
| `Atlas_UI_Frames.spriteatlas` | 面板框架、血条框等 | `_Game/Art/UI/Atlases/` |
**规则**
- Atlas 文件放在**被打包 Sprite 的同目录下的 `Atlases/` 子文件夹**,而非集中到单独目录
- **Atlas 本身不注册 Addressable**,通过所属 Prefab/Material 间接引用,由 Unity 自动处理依赖
- 区域特有的敌人或环境资产可单独建 Atlas避免跨区域 Atlas 导致整体加载
- Atlas 内不混入不同生命周期的资产(例如:角色 Sprite 与 UI 图标不合并)
---
## 3. Data/ ScriptableObject 规范
### 3.1 完整目录结构
```
Data/
├── Events/ 所有事件频道 SO每个事件独立一个文件
│ ├── Core/ 游戏状态、场景加载等核心事件
│ ├── Player/ 玩家相关事件
│ ├── Combat/ 战斗相关事件
│ ├── Enemies/ 敌人相关事件
│ ├── World/ 世界交互事件(含 EVT_ShowInteractPrompt、EVT_HideInteractPrompt
│ ├── UI/ UI 显隐事件(含 EVT_InputDeviceChanged
│ ├── Audio/ 音频播放事件
│ ├── Progression/ 进度成长事件
│ ├── Dialogue/ 对话事件
│ ├── Quest/ 任务事件
│ ├── Boss/ Boss 相关事件
│ └── Difficulty/ 难度调整事件
├── Player/
│ ├── Forms/ 各形态配置
│ └── Input/ 输入配置
├── Combat/
│ ├── DamageSources/ 伤害源配置
│ └── Weapons/ 武器配置
├── Enemies/
│ └── {EnemyID}/ 每个敌人的数据目录
├── Progression/
│ ├── Skills/ 技能配置
│ ├── Spells/ 法术配置
│ ├── Charms/ 护身符配置
│ └── Abilities/ 能力配置
├── Audio/
│ ├── BGM/ 背景音乐配置
│ └── SFX/ 音效配置
├── World/
│ ├── Map/ 地图与房间配置
│ └── Shop/ 商店配置
├── UI/
│ ├── Panels/ UI 面板配置
│ └── InputIcons/ 按键图标集 SO每设备一个文件通过 Inspector 直接引用,不走 Addressables
└── Settings/ 全局设置与难度配置
```
### 3.2 SO 资产命名规则
格式:`{SystemPrefix}_{描述}.asset`,参考 `Architecture/01_ProjectStructure.md §3` 前缀表。
| 前缀 | 系统 | 示例 |
|------|------|------|
| `EVT_` | 事件频道 | `EVT_PlayerDied.asset` |
| `PLY_` | 玩家 | `PLY_PlayerStats.asset` |
| `CMB_` | 战斗 | `CMB_DamageSource_Sword.asset` |
| `ENM_` | 敌人 | `ENM_E001_Stats.asset` |
| `WPN_` | 武器 | `WPN_SkyBlade.asset` |
| `SKL_` | 技能/法术 | `SKL_SoulBlade.asset` |
| `SPL_` | 法术Spell | `SPL_Fireball.asset` |
| `CHM_` | 护身符 | `CHM_GhostMantis.asset` |
| `SHP_` | 商店 | `SHP_Inventory_Forest.asset` |
| `MAP_` | 地图 | `MAP_RoomData_Forest_01.asset` |
| `AUD_` | 音频 | `AUD_BGMPlaylist_Forest.asset` |
| `UI_` | UI 配置 | `UI_PanelConfig_HUD.asset` |
| `SET_` | 设置 | `SET_GlobalSettings.asset` |
| `ABL_` | 能力 | `ABL_DoubleJump.asset` |
| `ICN_` | 按键图标集 | `ICN_KeyboardMouse.asset``ICN_Xbox.asset` |
### 3.3 事件频道 SO 特别规则
- 每个事件频道**独立一个文件**,禁止在同一 `.cs` 脚本中定义多个频道类(防止 Script 引用丢失)
- 文件名与类型名严格对应:`EVT_PlayerDied.asset` 对应 `PlayerDiedEventChannelSO`
- **事件频道 SO 不注册 Addressable**,通过 Inspector 直接引用
---
## 4. Prefabs/ 预制体规范
### 4.1 目录结构
```
Prefabs/
├── Player/ 玩家顶级 Prefab含控制器 / 动画 / 碰撞体AddressablePLY_Player· PLY_Player.prefab
├── Enemies/
│ └── {EnemyID}/ 敌人顶级 Prefab含 AI 行为树 / 动画 / 碰撞体AddressableENM_{Name})· ENM_{Name}.prefab
├── Combat/
│ ├── HitBox/ 主动攻击碰撞盒,嵌套于角色 Prefab 内,随角色一同打包,不单独注册 Addressable
│ ├── HurtBox/ 受击判定盒,同上规则,不单独注册 Addressable
│ └── Projectiles/ 抛射物顶级 Prefab独立实例化纳入对象池标签 Poolable· PROJ_{Name}.prefab
├── Effects/ 特效顶级 Prefab粒子系统 / 帧动画),纳入对象池,标签 Poolable · VFX_{Name}.prefab
├── Collectibles/ 可收集物件(灵魂碎片、道具、恢复球),纳入对象池,标签 Poolable · COL_{Name}.prefab├── Environment/ 场景骨架结构 Prefab由关卡场景直接引用不注册 Addressable
│ ├── Tilemaps/ Tilemap 层 GameObject Prefab含 Grid / TilemapRenderer / Collider2D每种地形层独立一个 Prefab · ENV_Tilemap_{Layer}.prefab
│ └── Backgrounds/ 视差滚动背景层 Prefab含 SpriteRenderer + ParallaxScroller每区域按 Far / Mid / Near 分层 · ENV_BG_{Region}_{Layer}.prefab├── World/
│ ├── Interactables/ 场景可交互物件宝箱、NPC 对话触发器、传送门),含交互逻辑组件 · WLD_{Name}.prefab
│ ├── Traps/ 机关陷阱(刺、摆锤、喷火),含周期性伤害触发逻辑 · WLD_{Name}.prefab
│ └── Props/ 纯视觉场景道具(无逻辑),用于场景布景装饰 · WLD_{Name}.prefab
├── UI/ UI 面板顶级 Prefab由 UIManager 通过 Addressable 实例化UI· UI_{PanelName}.prefab
└── Persistent/ 持久场景全局管理器,随 Persistent 场景加载,全程不销毁 · SYS_{ManagerName}.prefab
```
### 4.2 Prefab 命名规则
| 类型 | 前缀 | 示例 |
|------|------|------|
| 玩家 | `PLY_` | `PLY_Player.prefab` |
| 敌人 | `ENM_` | `ENM_GruntWarrior.prefab` |
| 抛射物 | `PROJ_` | `PROJ_Arrow.prefab` |
| 特效 | `VFX_` | `VFX_HitSpark.prefab` |
| UI | `UI_` | `UI_HUD.prefab` |
| 收集物 | `COL_` | `COL_HPOrb.prefab` |
| 世界物件 | `WLD_` | `WLD_Torch.prefab` |
| 武器 | `WPN_` | `WPN_SkyBlade.prefab` |
| 持久对象 | `SYS_` | `SYS_GameManager.prefab` |
| 环境结构 | `ENV_` | `ENV_Tilemap_Ground.prefab``ENV_BG_Forest_Far.prefab` |
### 4.3 Prefab 嵌套规则
- Prefab 内的子物件HitBox、HurtBox、骨骼节点**不单独注册 Addressable**
- 武器 Prefab 嵌套在角色 Prefab 内时,通过 Nested Prefab 引用,不用 Addressables 动态加载
- 只有**顶级可实例化对象**才注册 Addressable 地址
---
## 5. Scenes/ 场景规范
### 5.1 目录结构
```
Scenes/
├── Persistent.unity 常驻场景,承载全局管理器 PrefabGameManager / AudioManager / UIManager永不卸载
├── MainMenu.unity 主菜单场景,游戏启动后首先加载,含主题音乐与过场动画
├── Room_{Region}_{Index:D2}.unity 普通关卡房间,含静态地形与区域触发器(敌人 / 道具由 Spawner 动态实例化)· 例Room_Forest_01.unity
├── Boss_{Name}.unity Boss 专属战斗场景,含专属 BGM、Boss AI 与阶段触发逻辑 · 例Boss_CaoZhi.unity
└── Testings/ 开发测试专用场景,不注册 Addressable不进入正式构建流程
```
### 5.2 场景命名规则
| 类型 | 命名格式 | Addressable 地址 |
|------|---------|----------------|
| 常驻场景 | `Persistent.unity` | `Scene_Persistent` |
| 主菜单 | `MainMenu.unity` | `Scene_MainMenu` |
| 关卡房间 | `Room_{Region}_{Index:D2}.unity` | `Room_Forest_01` |
| Boss 战 | `Boss_{Name}.unity` | `Boss_CaoZhi` |
| 测试场景 | 任意(在 Testings/ | **不注册 Addressable** |
### 5.3 场景内容规范
- **Persistent 场景**:只放全局管理器 Prefab`SYS_GameManager``SYS_AudioManager``SYS_UIManager`),其余全部通过 Addressables 动态加载
- **关卡场景**:只放该关卡的静态地形与触发器;角色、敌人由 Spawner 通过 Addressables 实例化
- 禁止在场景中直接拖拽引用 `Prefabs/` 下的动态对象(改用 Spawner + Addressable Key
---
## 6. Shaders/ 着色器规范
### 6.1 目录结构
```
_Game/Shaders/
├── BaseASE/ Shader Graph 图,每个文件对应一个渲染目的,不合并不相关效果 · {Category}_{Purpose}.shadergraph
│ ├── Character/ 角色类主材质Emission 自发光 + 受击闪白参数)、描边、溶解 / 死亡效果
│ ├── Environment/ 环境类Tilemap 地形着色、多层视差背景、水面 / 液体流动效果
│ ├── Effects/ 特效类VFX Sprite 通用Alpha 混合 + 颜色偏移)、热浪扭曲
│ └── UI/ UI 类:默认 UI 渲染、灰度效果(用于禁用状态的技能 / 道具图标)
└── Includes/ 跨 Shader 共享 HLSL 函数库,通过相对路径 #include 引用 · {FunctionGroup}.hlsl
```
### 6.2 Shader 命名规则
| 类型 | 命名格式 | 示例 |
|------|---------|------|
| Shader Graph | `{Category}_{Purpose}.shadergraph` | `Character_Main.shadergraph` |
| HLSL include | `{FunctionGroup}.hlsl` | `ColorUtils.hlsl` |
| Shader Variant Collection | `SVC_{Category}.shadervariants` | `SVC_Characters.shadervariants` |
### 6.3 Shader 管理规则
- Shader 资产**不注册 Addressable**,由 Material 直接引用Material 随 Prefab 打包
- HLSL include 文件放在 `Shaders/Includes/`,使用**相对路径** `#include` 引用
- 每个渲染目的对应一个 `.shadergraph`**不合并多个不相关效果到同一 Graph**
- Shader 变体数量需受控:通过 `Shader Variant Collection` 预热,避免运行时卡顿
---
## 6.5 Material 管理规范
### 6.5.1 Material 存放原则
Material`.mat`**紧邻使用它的资产存放**,不设全局集中目录:
| 使用对象 | Material 存放位置 | 命名格式 | 示例 |
|---------|----------------|---------|------|
| 玩家角色 | `_Game/Art/Characters/Player/{FormID}/Materials/` | `PLY_{FormID}.mat` | `PLY_Player01.mat` |
| 敌人 | `_Game/Art/Characters/Enemies/{EnemyID}/Materials/` | `ENM_{ID}.mat` | `ENM_E001.mat` |
| NPC | `_Game/Art/Characters/NPCs/{NPCName}/Materials/` | `NPC_{Name}.mat` | `NPC_Merchant.mat` |
| 特效 VFX | `_Game/Art/Effects/Materials/` | `VFX_{Description}.mat` | `VFX_HitSpark.mat` |
| 环境/Tilemap | `_Game/Art/Environment/Tilesets/{Region}/Materials/` | `TILE_{Region}_{Name}.mat` | `TILE_Forest_Ground.mat` |
| 环境背景 | `_Game/Art/Environment/Backgrounds/{Region}/Materials/` | `BG_{Region}.mat` | `BG_Forest.mat` |
| 场景道具 | `_Game/Art/Environment/Props/{Category}/Materials/` | `PROP_{Name}.mat` | `PROP_Chest.mat` |
| UI 专用 | `_Game/Art/UI/Materials/` | `UI_{Description}.mat` | `UI_HealthBar.mat` |
| 共享/通用 | `_Game/Art/Shared/Materials/` | `MAT_{Description}.mat` | `MAT_Dissolve.mat` |
### 6.5.2 Material 命名规则
- 同一对象有多个 Material 时加 `_{Variant}` 后缀区分:
- `ENM_E001.mat`(主材质)
- `ENM_E001_Emission.mat`(发光变体,若需要单独材质)
- `ENM_E001_Flash.mat`(受击闪白材质,通过代码切换)
- Emission 贴图与主贴图共享同一 Material通过 Shader 属性 `_EmissionMap` 关联,**无需单独 Material**
- 受击闪白效果推荐通过 Shader 属性(如 `_FlashAmount`)在运行时控制,避免 Material 实例爆炸
### 6.5.3 Material 实例化规则
```csharp
// ✅ 推荐:通过 MaterialPropertyBlock 修改,不产生 Material 实例
var mpb = new MaterialPropertyBlock();
mpb.SetFloat("_FlashAmount", 1f);
renderer.SetPropertyBlock(mpb);
// ⚠ 避免:直接修改 renderer.material每次调用都创建新实例造成内存泄漏
renderer.material.SetFloat("_FlashAmount", 1f); // ⚠ 产生实例
// ✅ 允许:需要持久独立状态时显式用 Instantiate并在 OnDestroy 中手动 Destroy
_matInstance = Instantiate(renderer.sharedMaterial);
renderer.material = _matInstance;
// ... OnDestroy: Destroy(_matInstance);
```
---
## 7. UI Toolkit/ 规范
```
UI Toolkit/
├── PanelSettings.asset 面板渲染配置Scale Mode、Sort Order、Reference Resolution全局唯一不得创建多个
├── UnityThemes/ Unity 编辑器内置主题文件,不修改
├── Layouts/ UXML 布局文件,每个面板对应一个文件,与 Prefabs/UI/ 同名 · {PanelName}.uxml
└── Styles/ USS 样式表Variables.uss全局 CSS 变量、Common.uss通用控件样式、{PanelName}.uss面板专属样式
```
- `PanelSettings.asset` 全局唯一,不得创建多个
- UXML 和 USS 按界面功能命名,与对应的 `Prefabs/UI/` 同名
---
## 8. Addressables 管理规范
### 8.1 分组Group划分策略
| 组名 | 包含内容 | Build 类型 | 加载时机 |
|------|---------|-----------|---------|
| `Default Local Group` | 常驻 PrefabGameManager、UIManager 等)、全局配置 SO | Local | 启动时自动加载 |
| `UI` | 所有 UI PrefabHUD、菜单、弹框等 | Local | 启动时预加载 |
| `Player` | 玩家 Prefab、武器 Prefab | Local | 游戏开始时加载 |
| `VFX_Common` | 通用高频特效HitSpark、BloodSplat 等) | Local | 启动时预加载 |
| `Collectibles` | 收集物 PrefabGeo、Item、HPOrb | Local | 启动时预加载 |
| `Projectiles` | 抛射物 Prefab | Local | 启动时预加载 |
| `Enemies` | 所有敌人 Prefab`ENM_*` | Local | 进入区域时加载 |
| `Room_{Region}` | 该区域的关卡场景 + 区域专属资产 | Local | 进入区域时加载 |
| `Boss_{Name}` | Boss 专属 Prefab + 场景 | Local | Boss 战开始前加载 |
| `Audio_Music` | BGM 音频FMOD bank 引用) | Remote可选| 按需流式加载 |
| `Config` | 运行时需要动态加载的配置 SO | Local | 按需加载 |
**划分原则**
1. **生命周期相同的资源放同一组**——一起加载、一起卸载
2. **不同区域的资源绝对隔离**——防止 Region A 的资产随 Region B 打包
3. **高频小资产合入 Common 组**——避免大量小 handle 的运行时开销
4. **场景文件与其依赖资产放同一组**——确保 SceneManager 加载时依赖已在本地
### 8.2 Address 命名规则
地址字符串格式:`{SystemPrefix}_{描述}``{Category}/{描述}`
```
# Prefab 类(无路径前缀)
PLY_Player
ENM_GruntWarrior
ENM_SkullArcher
PROJ_Arrow
VFX_HitSpark
UI_HUD
COL_HPOrb
# 场景类
Scene_Persistent
Scene_MainMenu
Room_Forest_01
Boss_CaoZhi
# 配置数据类(带路径前缀区分)
Config/FootstepCatalog
Config/DifficultyEasy
```
**强制要求**:所有 Address 必须在 `AddressKeys.cs` 中定义对应常量,**禁止在代码中硬编码字符串**。
### 8.3 Label标签使用规范
> 完整定义见 `Standards/AddressablesLabelSpec.md`。
| 标签 | 用途 | 相关常量 |
|------|------|---------|
| `Preload` | 游戏启动时通过 `DownloadDependenciesAsync` 预热下载依赖 | `AddressKeys.Labels.Preload` |
| `Poolable` | 纳入 `GlobalObjectPool` 对象池管理的 PrefabVFX、投射物、收集物等| `AddressKeys.Labels.Poolable` |
| `Enemy` | 所有敌人 Prefab用于区域 Spawner `LoadAssetsAsync` 批量加载 | `AddressKeys.Labels.Enemy` |
| `BGM` | BGM 音频 AudioClip / FMOD bank 引用 SO | `AddressKeys.Labels.BGM` |
| `SFX` | 音效 AudioClip / SFX 配置 SO | `AddressKeys.Labels.SFX` |
| `Charms` | 所有护身符配置 SO供 EquipmentManager 批量加载列表 | `AddressKeys.Labels.Charms` |
| `Config` | 运行时动态加载的配置类 SO | `AddressKeys.Labels.Config` |
| `Weapon` | 所有武器 Prefab玩家换形态时批量加载 | `AddressKeys.Labels.Weapon` |
- 一个资产可附加多个标签(例如 `VFX_HitSpark` 同时有 `Poolable``Preload` 标签)
- 新增标签前确认是否有批量加载的实际需求,避免标签膨胀(决策流程见 `AddressablesLabelSpec.md §6`
### 8.4 AddressKeys.cs 维护流程
文件路径:`Assets/_Game/Scripts/Core/Assets/AddressKeys.cs`
**工作流(添加新资产)**
```
1. 在 Project 中创建/导入资产
2. 在 AddressKeys.cs 中添加对应 const 字符串
3. 在 AddressableBatchTool菜单 `BaseGames/Addressables/Addressable Batch Tool`)中:
a. 切换到 "① 同步 AddressKeys" 标签
b. 点击 "Scan" 找到未注册的 Key
c. 选择目标 Group点击 "Register" 完成注册
4. 运行 AddressKeyValidator菜单 `BaseGames/Addressables/Validate Address Keys`
确认无 Missing / Mismatch 警告
5. 提交 AddressKeys.cs 和 AddressableAssetSettings.asset 的修改
```
**工作流(删除/重命名资产)**
```
1. 先在 AddressKeys.cs 中删除/修改对应常量
2. 全局搜索该常量的所有引用并更新
3. 在 Addressables Groups 窗口手动删除或重命名对应条目
4. 重新运行 AddressKeyValidator 验证
5. 提交所有修改(.cs + .asset 文件)
```
### 8.5 AssetLoader 使用规范
封装类路径:`Assets/_Game/Scripts/Core/Assets/AssetLoader.cs`
```csharp
// ✅ 正确:使用 AssetLoader + AddressKeys 常量
var (prefab, handle) = await AssetLoader.LoadAsync<GameObject>(AddressKeys.PrefabPlayer);
_tracker.Track(handle); // 注册到 AssetReleaseTracker场景卸载时自动 Release
// ✅ 正确:对象池中不直接 Release由池管理器统一处理
// ❌ 禁止:直接调用 Addressables API绕过封装层
var handle = Addressables.LoadAssetAsync<GameObject>("PLY_Player"); // ❌
// ❌ 禁止:加载后不 Release内存泄漏
var (prefab, _) = await AssetLoader.LoadAsync<GameObject>(AddressKeys.PrefabPlayer); // ❌ 忘记 Track
```
### 8.6 加载/释放生命周期
```
场景加载时:
SceneManager 激活 → 场景根 GO 上挂 AssetReleaseTracker
→ 各 Spawner/Manager 调用 AssetLoader.LoadAsync → Track handle
场景卸载时:
AsyncOperation.completed → AssetReleaseTracker.OnDestroy 自动 Release 所有 handle
→ 内存归零(无需手动清理)
对象池:
Pool 持有 handle不 Track 到 AssetReleaseTracker
→ Pool 销毁时显式 ReleasePool 自身管理生命周期)
```
### 8.7 Build 策略
| 构建目标 | 命令 | 说明 |
|---------|------|------|
| 开发测试 | `Build > New Build > Default Build Script` | 全量本地构建,输出到 `Library/com.unity.addressables/` |
| 内容更新 | `Build > Update a Previous Build` | 仅重打修改的 Group需保留上次 catalog |
| 生产发布 | CI 流水线触发全量构建 | Remote Group 上传 CDNLocal Group 打入安装包 |
**注意**`AddressableAssetsData/` 目录下的文件由 Unity 自动维护,**不得手动修改 .asset 内容**,只通过 Addressables Groups 窗口操作。
---
## 9. Import Settings 规范
### 9.1 Sprite / Texture Import 规范
| 设置项 | 规范值 | 说明 |
|-------|-------|------|
| Texture Type | `Sprite (2D and UI)` | 角色/特效/UI 图 |
| Sprite Mode | `Multiple`Sprite Sheet`Single` | Sprite Sheet 用 Multiple |
| Pixels Per Unit | `32` | 与项目像素密度保持统一 |
| Filter Mode | `Point (no filter)` | Pixel Art 项目固定值 |
| Compression | `None`(移动平台用 `ASTC 6x6`| 开发阶段 None发布时切换 |
| Generate Mip Maps | `关闭` | 2D 游戏不需要 Mip Maps |
| Read/Write Enabled | `关闭`(除非代码需要像素读写) | 减少内存占用 |
| Max Size | 角色 `2048`UI `1024`,特效 `512` | 按实际尺寸设置上限 |
> **Emission 贴图**`_Emission.png`)使用 **相同 Import 设置**,与主贴图保持一致的 PPU 和 Filter Mode。
### 9.2 AnimationClip Import 规范
- 直接创建的 `.anim` 文件(非 FBX 内嵌)无需额外 Import 设置
- Loop Time循环动作Idle、Move、Skill_Loop开启非循环Death、Hit、Skill_Start关闭
- Sample Rate`12` fpsPixel Art 动画标准帧率)
### 9.3 Audio Import 规范
| 设置项 | SFX | BGM |
|-------|-----|-----|
| Load Type | `Decompress On Load` | `Streaming` |
| Compression Format | `Vorbis` | `Vorbis` |
| Quality | `70%` | `60%` |
| Load In Background | `关闭` | `开启` |
> **注**:若使用 FMODAudio 资产由 FMOD Studio 管理Unity 侧只保留 FMOD Bank 引用 SO不直接导入 AudioClip。
---
## 10. 资源新增工作流
### 10.1 新增敌人
> **推荐工具**`BaseGames → Data → Enemy Data Manager``EnemyDataWindow`)——在左栏点击 [New] 可自动创建 `ENM_*_Stats.asset`,在右栏 Loot Tab 配置掉落表。
```
1. _Game/Art/Characters/Enemies/ 下创建 {EnemyID}/ 目录,内含 Sprites/ Animations/ Materials/ Atlases/
2. 导入 Sprite Sheet 到 Sprites/,配置 Import SettingsPPU=32, Filter=Point, Multiple
3. 在 Sprite Editor 中切割 Sprite
4. 在 Animations/ 下创建动画片段(.anim和 Animator Controller
5. 在 Materials/ 下创建材质(引用 _Game/Shaders/ 中的角色 Shader关联主纹理和 Emission 贴图)
6. 在 Atlases/ 下创建 Atlas_Enemy_{ID}.spriteatlas包含该敌人所有 Sprite
7. 在 Enemy Data Manager菜单 BaseGames/Data/Enemy Data Manager创建 ENM_{ID}_Stats.asset
8. 在 _Game/Prefabs/Enemies/{EnemyID}/ 下创建 ENM_{Name}.prefab
9. 在 AddressKeys.cs 中添加 PrefabEnemy{Name} 常量
10. 使用 Rule Sync菜单 BaseGames/Addressables/Rule SyncScan → Fix All自动分组并打 Enemy 标签
11. 运行 AddressKeyValidator菜单 BaseGames/Addressables/Validate Address Keys验证
```
### 10.2 新增武器Weapon
> **推荐工具**`BaseGames → Data → Weapon Editor``WeaponEditorWindow`)创建 `WPN_*_Data.asset``BaseGames → Create → Weapon HitBox Prefab``WeaponHitBoxWizard`)创建 4 方向 HitBox Prefab。
```
1. 在 _Game/Art/Characters/Player/{FormID}/Sprites/ 下放置武器帧动画 Sprite Sheet配置 Import Settings
2. 在 Weapon Editor菜单 BaseGames/Data/Weapon Editor左栏 [New] 创建 WPN_{Name}_Data.asset
- 路径_Game/Data/Combat/Weapons/WPN_{Name}_Data.asset
- 命名WPN_{Name}示例WPN_SkyBlade、WPN_EarthClaw
3. 使用 Weapon HitBox Wizard菜单 BaseGames/Create/Weapon HitBox Prefab生成
_Game/Prefabs/Weapons/WPN_{Name}_HitBox.prefab自动创建 4 方向 Ground/Up/Down/Air
4. 在 _Game/Prefabs/Player/ 下创建或更新武器顶级 Prefab WPN_{Name}.prefab
5. 在 AddressKeys.cs 中添加 PrefabWeapon{Name} 常量
6. 使用 Rule Sync 自动分组Player 组)并打 Weapon + Preload 标签
7. 运行 AddressKeyValidator 验证
```
### 10.3 新增技能Skill
> **推荐工具**`BaseGames → Data → Skill Editor``SkillEditorWindow`)创建 `SKL_*_Data.asset``BaseGames → Create → Skill HitBox Prefab``SkillHitBoxWizard`)创建多段 HitBox Prefab。
```
1. 在 _Game/Art/Characters/Player/{FormID}/Animations/ 下创建技能动画片段(.anim
2. 在 Skill Editor菜单 BaseGames/Data/Skill Editor左栏 [New] 创建 SKL_{SkillID}_Data.asset
- 路径:`_Game/Data/Progression/Skills/SKL_{SkillID}_Data.asset`
- 命名SKL_{SkillID}示例SKL_DashSlash、SKL_SpiritWave
3. 使用 Skill HitBox Wizard菜单 BaseGames/Create/Skill HitBox Prefab生成
_Game/Prefabs/Skills/SKL_{SkillID}_HitBox.prefab支持多段伤害配置
4. 在 AddressKeys.cs 中添加对应常量(如需独立 Addressable 加载)
5. 运行 AddressKeyValidator 验证(如已注册 Addressable
```
### 10.4 新增护身符Charm
> **推荐工具**`BaseGames → Data → Character Wizard`(切换到 Charm 标签)或直接在 Project 窗口 右键 → Create使用 `CharmSOEditor`Custom Inspector配置**必须确保路径为 `_Game/Data/Progression/Charms/`,命名为 `CHM_{Name}.asset`**;若护身符类型较多,建议在 §12 中增加专属 Charm Editor 入口以强制规范。
```
1. 使用 Character Wizard菜单 BaseGames/Data/Character Wizard → Charm 标签)创建 CHM_{Name}.asset
- 路径_Game/Data/Progression/Charms/CHM_{Name}.asset
- 命名CHM_{Name}示例CHM_SoulReaper、CHM_IronSkin
2. 在 Inspector 中通过 CharmSOEditor 下拉选择效果类型并配置参数
3. 在 AddressKeys.cs 中添加 DataCharm{Name} 常量
4. 使用 Rule Sync 自动分组Config 组)并打 Charms 标签
5. 运行 AddressKeyValidator 验证
```
### 10.5 新增玩家形态Player Form
> **推荐工具**`BaseGames → Tools → Character Wizard``CharacterWizardWindow`)统一入口——创建 FormSO、绑定武器引用、跳转到 Form Editor`BaseGames → Data → Form Editor``FormEditorWindow`)进行三魂列阵可视化编辑。
```
1. 在 Character Wizard菜单 BaseGames/Data/Character Wizard切换到 Player 标签
- 填写 FormID点击 [Create Form Assets],自动在正确路径创建 FormSO 和相关 SO
2. 在 _Game/Art/Characters/Player/{FormID}/ 下创建 Sprites/ Animations/ Materials/ Atlases/ 目录
3. 导入 Sprite Sheet配置 Import SettingsPPU=32, Filter=Point, Multiple
4. 在 Form Editor菜单 BaseGames/Data/Form Editor三栏网格中选择形态格位绑定武器和技能列表
5. 在 _Game/Prefabs/Player/ 下创建 PLY_{FormID}.prefab
6. 在 AddressKeys.cs 中添加 PrefabPlayer{FormID} 常量(如为独立 Addressable
7. 使用 Rule Sync 自动分组Player 组)并打 Preload 标签
8. 运行 AddressKeyValidator 验证
```
### 10.6 新增 VFX
> **提示**VFX Prefab 必须纳入 `GlobalObjectPool`,在 Pool 配置中指定初始预热数量。
```
1. 在 _Game/Art/Effects/Sprites/ 下导入特效 Sprite Sheet配置 Import SettingsPPU=32, Filter=Point
2. 在 _Game/Art/Effects/Materials/ 下创建特效材质
3. 在 _Game/Prefabs/Effects/ 下创建 VFX_{Name}.prefab
4. 在 AddressKeys.cs 中添加 PrefabVFX{Name} 常量
5. 使用 Rule Sync 自动分组VFX_Common 组)并打 Poolable + Preload 标签
6. 在 GlobalObjectPool._warmupConfigs 中添加初始池数量配置
```
### 10.7 新增 UI 界面
```
1. 在 _Game/UI Toolkit/Layouts/ 下创建 {PanelName}.uxml
2. 在 _Game/UI Toolkit/Styles/ 下创建或复用对应 .uss
3. 在 _Game/Prefabs/UI/ 下创建 UI_{PanelName}.prefab
4. 在 _Game/Data/UI/Panels/ 下创建 UI_PanelConfig_{PanelName}.asset如需配置 SO
5. 在 AddressKeys.cs 中添加 PrefabUI{PanelName} 常量
6. 使用 Rule Sync 自动分组UI 组);常驻全局面板额外打 Preload 标签
```
### 10.8 新增关卡场景
```
1. 在 _Game/Scenes/ 下创建 Room_{Region}_{Index:D2}.unity
2. 在 AddressKeys.cs 中添加地址常量(复用 SceneRoomPrefix + 动态拼接或新增独立常量)
3. 将场景注册到 Room_{Region} 组Rule Sync 可自动识别 Room_ 前缀并动态计算组名)
4. 在 _Game/Data/World/Map/ 下创建 MAP_RoomData_{Region}_{Index:D2}.asset
```
### 10.9 新增输入设备图标集Input Device Icon Set
> **推荐工具**`BaseGames/Input Icon Studio``InputIconStudioWindow`)——可视化管理所有设备的按键图标,自动写入对应 SO。
**⚠ Addressable 决策:不需要 Addressable。**
`InputDeviceIconSetSO``InputIconService`(挂载在 UIRoot 上)通过 `SerializeField` 直接引用,随常驻场景加载,无需运行时动态加载。
```
1. 美术导入
a. 在 _Game/Art/UI/Icons/InputKeys/ 下放置按键图标 Sprite Sheet 或单张 PNG
b. Import SettingsTexture Type = Sprite, Filter=Point, PPU=32像素图或 PPU=1矢量/高分辨率图)
c. 命名格式IC_Key_{DeviceShort}_{KeyName}.png
DeviceShortKBM键鼠/ Xbox / PS / Switch
示例IC_Key_KBM_Space.png、IC_Key_Xbox_A.png、IC_Key_PS_Cross.png
2. 创建图标集 SO
a. 菜单 BaseGames/Input Icon Studio → 点击对应设备行的「+ 新建」按钮
b. 选择保存路径(推荐 _Game/Data/UI/InputIcons/
c. 命名ICN_{DeviceType}.assetICN_KeyboardMouse.asset、ICN_Xbox.asset
3. 填充图标映射
a. 在 Input Icon Studio 左列选择 Action右列指定 Sprite或在 Inspector 的 InputDeviceIconSetSOEditor 中操作)
b. 可使用 Inspector 顶部「从 Action Asset 填充路径」按钮批量生成条目,再逐一拖入 Sprite
c. 覆盖率芯片变为绿色100%)表示该设备全部 Action 已配置
4. 绑定到 InputIconService
a. 在 Persistent 场景的 UIRoot → InputIconService 组件 Inspector 中
b. 将 4 个 ICN_*.asset 拖入对应 SerializeField 字段_kbMouseSet / _xboxSet / _playStationSet / _switchSet
5. 验证
a. 进入 PlayMode切换输入设备观察 HUD 交互提示图标是否正确切换
b. 在 Input Icon Studio 的「交互提示预览」中模拟检查各设备外观
```
**ICN_ SO 命名与路径规则:**
| SO 名称 | 路径 | 对应设备 |
|---------|------|---------|
| `ICN_KeyboardMouse.asset` | `_Game/Data/UI/InputIcons/` | 键鼠(`InputDeviceType.KeyboardMouse` |
| `ICN_Xbox.asset` | `_Game/Data/UI/InputIcons/` | Xbox 手柄(`InputDeviceType.XboxController` |
| `ICN_PlayStation.asset` | `_Game/Data/UI/InputIcons/` | PS4/PS5`InputDeviceType.PlayStationController` |
| `ICN_Switch.asset` | `_Game/Data/UI/InputIcons/` | Switch Pro/Joy-Con`InputDeviceType.SwitchController` |
**按键图标命名规范(`IC_Key_{DeviceShort}_{KeyName}.png`**
| 设备简称 | 适用范围 | 示例 |
|---------|---------|------|
| `KBM` | 键盘按键 / 鼠标按键 | `IC_Key_KBM_Space.png``IC_Key_KBM_E.png``IC_Key_KBM_LMB.png` |
| `Xbox` | Xbox 面板按钮 / 摇杆 / 扳机 | `IC_Key_Xbox_A.png``IC_Key_Xbox_RT.png``IC_Key_Xbox_LStick.png` |
| `PS` | PlayStation 按钮 / 摇杆 / 扳机 | `IC_Key_PS_Cross.png``IC_Key_PS_R2.png``IC_Key_PS_L1.png` |
| `Switch` | Switch 面板按钮 / Joy-Con | `IC_Key_Switch_A.png``IC_Key_Switch_ZR.png``IC_Key_Switch_DPad.png` |
---
## 11. 禁止行为清单
| 禁止行为 | 原因 | 正确做法 |
|---------|------|---------|
| `Resources.Load<T>("path")` | 绕过 Addressables无法热更 | `AssetLoader.LoadAsync<T>(AddressKeys.Xxx)` |
| 在代码中硬编码 Address 字符串 | 重构困难,易拼写错误 | 使用 `AddressKeys` 常量 |
| 直接调用 `Addressables.LoadAssetAsync` | 绕过封装,难以追踪泄漏 | 使用 `AssetLoader.LoadAsync` |
| 加载后不 Release / 不 Track | 内存泄漏 | `_tracker.Track(handle)` 或显式 Release |
| 在场景中直接引用动态对象 Prefab | 导致场景与 Prefab 耦合,阻碍动态加载 | Spawner + Addressable Key |
| 手动修改 `AddressableAssetsData/*.asset` | 破坏 Addressables 内部状态 | 只通过 Groups 窗口 / AddressableBatchTool 操作 |
| 将 Test 场景注册 Addressable | 污染构建内容 | Test 场景放 `Scenes/Testings/` 并排除于所有 Group |
| 在同一 Prefab 中跨模块直接引用 SO | 产生跨组依赖,导致资产重复打包 | 通过 Addressables 按需加载配置 SO |
| 美术和数据混放在同一目录 | 职责不清,影响构建分析 | 美术在 `_Game/Art/`,数据在 `_Game/Data/`,预制体在 `_Game/Prefabs/` |
| 第三方插件目录内创建自定义资产 | 插件升级时被覆盖 | 自定义内容放在 `_Game/` 下对应模块目录 |
| 将 `_Game/` 内的资产移到 `Assets/` 根目录 | 破坏第一方/第三方隔离原则 | 所有自有资产必须在 `_Game/` 内 |
| 将 `AddressableAssetsData/` 移入 `_Game/` | Unity 硬编码此路径,移动后 Addressables 完全失效 | 永远保留在 `Assets/` 根目录 |
| 绕过编辑器工具手动创建 SO / Prefab | 路径或命名不符合规范,导致 Addressables 工具误报 | 使用 §12 中的对应编辑器窗口创建 |
---
## 12. 编辑器工具参考
所有**资产创建**均应通过以下编辑器工具进行以保证路径、命名、Addressables 注册完全符合本规范。
### 12.1 资产创建工具
| 工具名称 | 菜单路径 | 负责资产类型 | 说明 |
|---------|---------|------------|------|
| **Character Wizard** | `BaseGames/Data/Character Wizard` | 角色 SO玩家形态 / Minion / Boss 通用入口) | 统一入口,自动在正确路径创建所有配套 SO内含快捷跳转按钮 |
| **Form Editor** | `BaseGames/Data/Form Editor` | 玩家三魂形态FormSO | 三栏可视化网格,自动绑定武器/技能引用,支持 TianHun / DiHun / MingHun |
| **Enemy Data Manager** | `BaseGames/Data/Enemy Data Manager` | 敌人配置 SO`ENM_*_Stats.asset`+ 掉落表 | 双面板列表编辑,左栏搜索 + [New],右栏 Stats/Loot 标签 |
| **Boss Skill Sequence** | `BaseGames/Data/Boss Skill Sequence` | Boss 技能阶段BossSkillSO / SkillSequenceSO | Gantt 时间轴可视化Windup / Active / Recovery 三段颜色标记 |
| **Skill Editor** | `BaseGames/Data/Skill Editor` | 技能配置 SO`SKL_*_Data.asset` | 按 SkillEffectType 分组筛选,右栏含 HitBox 验证 + 资源费预览 |
| **Weapon Editor** | `BaseGames/Data/Weapon Editor` | 武器配置 SO`WPN_*_Data.asset` | 双面板列表,右栏全属性 + HitBox Prefab 验证 + 快捷操作 |
| **Weapon HitBox Wizard** | `BaseGames/Create/Weapon HitBox Prefab` | 武器 HitBox Prefab4 方向 Ground/Up/Down/Air | 自动生成 `WPN_{ID}_HitBox.prefab`,支持各方向碰撞体形状配置 |
| **Skill HitBox Wizard** | `BaseGames/Create/Skill HitBox Prefab` | 技能 HitBox Prefab多段伤害支持 | 自动生成 `SKL_{ID}_HitBox.prefab`,可配置 14 段 hitBoxCount |
| **Input Icon Studio** | `BaseGames/Input Icon Studio` | 按键图标集 SO`ICN_*.asset`+ 按键图标 Sprite 映射 | 设备标签栏 + Action 列表覆盖率指示 + 实时编辑 + 交互提示模拟预览 |
### 12.2 场景搭建工具
| 工具名称 | 菜单路径 | 说明 |
|---------|---------|------|
| **Boot Flow Wizard** | `BaseGames/Scene/Setup/Boot Flow Wizard` | 4 步启动流程一键配置(事件频道 → Persistent 场景 → MainMenu → 验证) |
| **Scaffold Persistent Scene** | `BaseGames/Scene/Setup/Scaffold Persistent Scene` | 一键创建 Persistent 场景的 Services/Input/Camera/UI 层次结构 |
| **Scaffold Main Menu Scene** | `BaseGames/Scene/Setup/Scaffold Main Menu Scene` | 一键创建 MainMenu 场景基础层次结构 |
| **Scaffold Game Room** | `BaseGames/Scene/Setup/Scaffold Game Room` | 一键创建关卡房间场景基础层次结构 |
| **Persistent Auto-Loader** | `BaseGames/Scene/Setup/Auto-Open Persistent Scene` | 编辑模式下打开任意场景时自动附加 PersistentToggle仅编辑模式 |
| **Scene Object Placer** | `BaseGames/Scene/Place/{类型}` | 场景中快速放置角色/陷阱/检查点/摄像机等,自动绑定组件和事件频道 |
| **Camera Area Setup** | `BaseGames/Scene/Camera Area Setup` | 在当前场景中快速创建并配置摄像机区域 |
| **Bake All NavSurfaces** | `BaseGames/Scene/Bake All NavSurfaces` (Ctrl+Shift+B) | 一键烘焙场景中所有 NavSurface仅编辑模式可用 |
### 12.3 Addressables 管理工具
| 工具名称 | 菜单路径 | 说明 |
|---------|---------|------|
| **Rule Sync** | `BaseGames/Addressables/Rule Sync` | 批量扫描/修复分组和标签(基于 `AddressableRules.cs` 规则,支持导出 CSV |
| **Addressable Batch Tool** | `BaseGames/Addressables/Addressable Batch Tool` (Alt+Shift+A) | 三标签操作:① 同步 AddressKeys → ② 文件夹批量注册 → ③ Selection 注册 |
| **Asset Reference Graph** | `BaseGames/Addressables/Asset Reference Graph` | 可视化 Addressable 地址间的引用依赖关系 |
| **Validate Address Keys** | `BaseGames/Addressables/Validate Address Keys` | 验证 `AddressKeys.cs` 所有常量在 Addressables 中均已注册,构建前自动触发 |
### 12.4 事件系统工具
| 工具名称 | 菜单路径 | 说明 |
|---------|---------|------|
| **Event Bus Monitor** | `BaseGames/Events/Event Bus Monitor` (Ctrl+Shift+E) | 运行时事件派发监控(类型/侦听器数/触发次数实时显示) |
| **Event Chain Viewer** | `BaseGames/Events/Event Chain Viewer` | 叙事事件链可视化,运行时显示完成/满足/等待状态 |
| **Create Event Channels** | `BaseGames/Events/Create Event Channels` | 一键生成全局事件频道 SO幂等跳过已存在资产 |
| **Reimport Event Channels** | `BaseGames/Events/Reimport Event Channels` | 重新导入/刷新全局事件频道 SO |
### 12.5 工具与维护
| 工具名称 | 菜单路径 | 说明 |
|---------|---------|------|
| **SO Manager** | `BaseGames/Tools/SO Manager` | 全项目 ScriptableObject 浏览器,支持类型/路径搜索 + Ping |
| **GM Debug Tool** | `BaseGames/Tools/GM Debug Tool` | 运行时快速注入资源/切换形态/解锁技能(仅 PlayMode |
| **Validate All SOs** | `BaseGames/Tools/Validation/Validate All ScriptableObjects` | 扫描所有 `IValidatable` SO 并报告错误(构建前自动触发) |
| **Apply Script Order** | `BaseGames/Tools/Validation/Apply Script Execution Order Preset` | 将脚本执行顺序预设应用到项目 |
| **Validate Script Order** | `BaseGames/Tools/Validation/Validate Script Execution Order Preset` | 验证当前脚本执行顺序是否符合预设 |
| **Missing Scripts (Scene)** | `BaseGames/Tools/Maintenance/Missing Scripts/...` | 在场景/Prefab 中查找或清除 Missing Script 引用 |
| **Physics2D Layer Matrix** | `BaseGames/Tools/Maintenance/Physics2D Layer Matrix/...` | 检查或自动修复 Physics2D 层碰撞矩阵配置 |
> **原则**:新增资产类型时,必须同步在对应编辑器工具中增加创建入口;严禁绕过工具手动在 Project 窗口 "Create" 并手动填写路径/命名,否则将导致 Addressables Rule Sync 工具误报分组或标签不一致。