# 01 · 项目结构与规范 > **作用**:定义文件夹布局、Assembly Definition 清单、命名规范、ScriptableObject 资产路径、代码风格约束。 > **所有程序员必读**,开始任何模块开发前先阅读本文档。 --- ## 目录 1. [文件夹布局](#1-文件夹布局) 2. [Assembly Definitions(asmdef)](#2-assembly-definitions) 3. [命名规范](#3-命名规范) 4. [ScriptableObject 资产组织](#4-scriptableobject-资产组织) 5. [Addressables 资产组织](#5-addressables-资产组织) 6. [代码风格约束](#6-代码风格约束) 7. [Prefab 组织规范](#7-prefab-组织规范) 8. [场景组织规范](#8-场景组织规范) --- ## 1. 文件夹布局 ``` Assets/ ├── Scripts/ ← 所有游戏代码(按模块分文件夹) │ ├── Core/ BaseGames.Core + BaseGames.Core.Events │ │ ├── Events/ SO 事件频道类型 │ │ └── Save/ SaveManager + ISaveStorage + SaveData │ ├── Input/ BaseGames.Input │ ├── Camera/ BaseGames.Camera │ ├── Player/ BaseGames.Player │ │ └── States/ BaseGames.Player.States │ ├── Combat/ BaseGames.Combat │ │ └── StatusEffects/ BaseGames.Combat.StatusEffects │ ├── Parry/ BaseGames.Parry │ ├── Enemies/ BaseGames.Enemies │ │ ├── AI/ BaseGames.Enemies.AI(Behavior Designer Tasks) │ │ ├── Boss/ │ │ │ └── Patterns/ BaseGames.Enemies.Boss.Patterns │ │ └── Navigation/ BaseGames.Enemies.Navigation │ ├── Feedback/ BaseGames.Feedback │ ├── World/ BaseGames.World │ │ ├── Map/ BaseGames.World.Map │ │ └── Shop/ BaseGames.World.Shop │ ├── UI/ BaseGames.UI │ ├── Audio/ BaseGames.Audio │ ├── Progression/ BaseGames.Progression │ ├── Dialogue/ BaseGames.Dialogue │ ├── Equipment/ BaseGames.Equipment │ ├── Cutscene/ BaseGames.Cutscene │ ├── Animation/ BaseGames.Animation │ ├── Spells/ BaseGames.Spells │ ├── Localization/ BaseGames.Localization │ ├── Tutorial/ BaseGames.Tutorial │ ├── Platform/ BaseGames.Platform │ └── Editor/ BaseGames.Editor(Editor Only) │ ├── Data/ ← ScriptableObject 资产(按模块分文件夹) │ ├── Events/ 所有事件频道 SO │ ├── Player/ PlayerStatsSO、PlayerMovementConfigSO 等 │ ├── Combat/ WeaponSO、ProjectileConfigSO 等 │ ├── Enemies/ EnemyStatsSO、AttackPatternSO 等 │ ├── Progression/ SkillSO、CharmSO、AbilityConfigSO 等 │ ├── Audio/ AudioCueSO、BGMPlaylistSO 等 │ ├── World/ MapRoomDataSO、ShopInventorySO 等 │ ├── UI/ UIConfigSO 等 │ └── Settings/ GlobalSettingsSO │ ├── Prefabs/ ← 预制体 │ ├── Player/ │ ├── Enemies/ │ ├── World/ │ ├── UI/ │ ├── Combat/ HitBox、HurtBox、Projectile 等 │ ├── Effects/ VFX Prefabs │ └── Persistent/ Persistent 场景专用 Prefabs │ ├── Scenes/ │ ├── Persistent.unity 常驻场景 │ ├── MainMenu.unity │ ├── Room_*/ 各关卡房间场景 │ └── Boss_*/ Boss 战场景 │ ├── Art/ 美术资源(不在此文档范围) ├── Audio/ 音频资源(FMOD 项目) └── StreamingAssets/ FMOD 音频包等 ``` --- ## 2. Assembly Definitions 所有 asmdef 均位于对应的 `Scripts/` 子文件夹下,文件名与程序集名称一致。 ### 依赖层次(底层 → 上层) ``` BaseGames.Core.Events └─→ BaseGames.Core ├─→ BaseGames.Input ├─→ BaseGames.Camera ├─→ BaseGames.Audio ├─→ BaseGames.Localization ├─→ BaseGames.Platform ├─→ BaseGames.World │ └─→ BaseGames.World.Map │ └─→ BaseGames.World.Shop └─→ BaseGames.Combat ├─→ BaseGames.Parry ├─→ BaseGames.Combat.StatusEffects └─→ BaseGames.Player ├─→ BaseGames.Player.States ├─→ BaseGames.Progression ├─→ BaseGames.Equipment ├─→ BaseGames.Spells └─→ BaseGames.Enemies ├─→ BaseGames.Enemies.AI ├─→ BaseGames.Enemies.Navigation └─→ BaseGames.Enemies.Boss.Patterns BaseGames.Feedback(依赖:Core.Events、Player、Enemies) BaseGames.Animation(依赖:Core.Events、Player) BaseGames.UI(依赖:Core.Events、Core、Progression) BaseGames.Dialogue(依赖:Core.Events、UI) BaseGames.Cutscene(依赖:Core.Events、UI、Dialogue) BaseGames.Tutorial(依赖:Core.Events、Progression) BaseGames.Editor(Editor Only,依赖全部运行时程序集) ``` ### asmdef 文件清单 | 文件名 | 程序集名称 | 编辑器 | 关键外部引用 | |--------|----------|--------|------------| | `BaseGames.Core.Events.asmdef` | `BaseGames.Core.Events` | ✗ | — | | `BaseGames.Core.asmdef` | `BaseGames.Core` | ✗ | `Newtonsoft.Json` | | `BaseGames.Input.asmdef` | `BaseGames.Input` | ✗ | `Unity.InputSystem` | | `BaseGames.Camera.asmdef` | `BaseGames.Camera` | ✗ | `Cinemachine` | | `BaseGames.Audio.asmdef` | `BaseGames.Audio` | ✗ | `FMODUnity`(可选) | | `BaseGames.Localization.asmdef` | `BaseGames.Localization` | ✗ | `Unity.Localization` | | `BaseGames.Platform.asmdef` | `BaseGames.Platform` | ✗ | `Steamworks.NET`(条件编译) | | `BaseGames.Combat.asmdef` | `BaseGames.Combat` | ✗ | — | | `BaseGames.Combat.StatusEffects.asmdef` | `BaseGames.Combat.StatusEffects` | ✗ | — | | `BaseGames.Parry.asmdef` | `BaseGames.Parry` | ✗ | — | | `BaseGames.World.asmdef` | `BaseGames.World` | ✗ | — | | `BaseGames.World.Map.asmdef` | `BaseGames.World.Map` | ✗ | — | | `BaseGames.World.Shop.asmdef` | `BaseGames.World.Shop` | ✗ | — | | `BaseGames.Player.asmdef` | `BaseGames.Player` | ✗ | `Kybernetik.Animancer` | | `BaseGames.Player.States.asmdef` | `BaseGames.Player.States` | ✗ | `Kybernetik.Animancer` | | `BaseGames.Progression.asmdef` | `BaseGames.Progression` | ✗ | — | | `BaseGames.Equipment.asmdef` | `BaseGames.Equipment` | ✗ | — | | `BaseGames.Spells.asmdef` | `BaseGames.Spells` | ✗ | — | | `BaseGames.Enemies.asmdef` | `BaseGames.Enemies` | ✗ | `Kybernetik.Animancer` | | `BaseGames.Enemies.AI.asmdef` | `BaseGames.Enemies.AI` | ✗ | `BehaviorDesigner.Runtime` | | `BaseGames.Enemies.Navigation.asmdef` | `BaseGames.Enemies.Navigation` | ✗ | `PathBerserker2d` | | `BaseGames.Enemies.Boss.Patterns.asmdef` | `BaseGames.Enemies.Boss.Patterns` | ✗ | — | | `BaseGames.Feedback.asmdef` | `BaseGames.Feedback` | ✗ | `MoreMountains.Tools`, `MoreMountains.Feedbacks` | | `BaseGames.Animation.asmdef` | `BaseGames.Animation` | ✗ | `Kybernetik.Animancer` | | `BaseGames.UI.asmdef` | `BaseGames.UI` | ✗ | — | | `BaseGames.Dialogue.asmdef` | `BaseGames.Dialogue` | ✗ | `Unity.Localization` | | `BaseGames.Cutscene.asmdef` | `BaseGames.Cutscene` | ✗ | `Unity.Timeline` | | `BaseGames.Tutorial.asmdef` | `BaseGames.Tutorial` | ✗ | — | | `BaseGames.Editor.asmdef` | `BaseGames.Editor` | ✓ | 所有运行时程序集 | --- ## 3. 命名规范 ### 类型名称 | 类型 | 后缀 / 规则 | 示例 | |------|-----------|------| | MonoBehaviour 组件 | 无后缀 | `PlayerController`、`EnemyBase` | | ScriptableObject | `SO` 后缀 | `PlayerStatsSO`、`ShopItemSO` | | 事件频道 SO | `EventChannelSO` 后缀 | `VoidEventChannelSO`、`IntEventChannelSO` | | 接口 | `I` 前缀 | `ISaveable`、`IInteractable`、`ICharmEffect` | | 枚举 | PascalCase 无后缀 | `GameState`、`AbilityType`、`DamageType` | | 泛型基类 | `Base` 后缀 | `PlayerStateBase`、`EnemyStateBase` | | Editor 扩展 | `Editor` 后缀 | `PlayerControllerEditor`、`EnemyBaseEditor` | | 协程方法 | `Coroutine` 后缀 | `LoadSceneCoroutine()`、`DeathSequenceCoroutine()` | ### 字段命名 ```csharp // 私有序列化字段:_camelCase(下划线前缀) [SerializeField] private PlayerMovementConfigSO _movementConfig; // 私有非序列化字段:_camelCase private float _currentSpeed; // 属性:PascalCase public float CurrentSpeed => _currentSpeed; // 常量:ALL_CAPS private const float MAX_SPEED = 10f; // 局部变量:camelCase float deltaSpeed = targetSpeed - _currentSpeed; ``` ### 文件命名 | 类型 | 规则 | 示例 | |------|------|------| | C# 脚本 | 与类名完全一致 | `PlayerController.cs` | | SO 资产 | `[SystemPrefix]_[Name]` | `PLY_Stats_Default.asset`、`EVT_PlayerDied.asset` | | Prefab | `[SystemPrefix]_[Name]` | `PLY_Player.prefab`、`ENM_GruntWarrior.prefab` | | 场景 | `Room_{Region}_{Index:D2}` | `Room_Forest_01.unity` | | asmdef | 与程序集名称一致 | `BaseGames.Player.asmdef` | ### SO 资产前缀表 | 前缀 | 系统 | |------|------| | `EVT_` | 事件频道 | | `PLY_` | 玩家配置 | | `CMB_` | 战斗配置 | | `ENM_` | 敌人配置 | | `WPN_` | 武器配置 | | `SKL_` | 技能 / 法术 | | `CHM_` | 护身符 | | `SHP_` | 商店 | | `MAP_` | 地图 | | `AUD_` | 音频 | | `UI_` | UI 配置 | | `SET_` | 设置 | --- ## 4. ScriptableObject 资产组织 ### 目录结构(`Assets/Data/`) ``` Assets/Data/ ├── Events/ │ ├── Core/ EVT_GameStateChanged.asset, EVT_SceneLoadRequest.asset … │ ├── Player/ EVT_PlayerDied.asset, EVT_HPChanged.asset … │ ├── Combat/ EVT_DamageDealt.asset … │ ├── World/ EVT_RoomTransition.asset … │ └── UI/ EVT_ShowPanel.asset … ├── Player/ │ ├── PLY_Stats_Default.asset │ ├── PLY_MovementConfig.asset │ ├── PLY_AnimConfig.asset │ └── PLY_FormConfig.asset ├── Combat/ │ ├── CMB_WeaponBase.asset │ └── CMB_ProjectileConfig_*.asset ├── Enemies/ │ ├── ENM_Stats_*.asset │ └── ENM_AttackPattern_*.asset ├── Progression/ │ ├── SKL_SoulSpell_*.asset │ ├── CHM_Charm_*.asset │ └── ABL_AbilityConfig_*.asset ├── Audio/ │ ├── AUD_BGMPlaylist_*.asset │ └── AUD_SFXCue_*.asset ├── World/ │ ├── MAP_RoomData_*.asset │ └── SHP_ShopInventory_*.asset └── Settings/ └── SET_GlobalSettings.asset ``` --- ## 5. Addressables 资产组织 ### AddressKeys 静态类(路径:`Scripts/Core/AddressKeys.cs`) ```csharp // 路径: Assets/Scripts/Core/Assets/AddressKeys.cs // ⚠️ 命名规范:驼峰式,无下划线分隔(`PrefabPlayer` 不是 `Pfx_Player_Main`) // 地址值与 Addressables Groups 窗口 Address 列保持完全一致 namespace BaseGames.Core { public static class AddressKeys { // ── Scenes ────────────────────────────────────────────── public const string ScenePersistent = "Scene_Persistent"; public const string SceneMainMenu = "Scene_MainMenu"; public const string SceneRoomPrefix = "Room_"; public const string SceneBossPrefix = "Boss_"; // ── Player ────────────────────────────────────────────── public const string PrefabPlayer = "PLY_Player"; // ── UI ────────────────────────────────────────────────── public const string PrefabUIHUD = "UI_HUD"; public const string PrefabUIPauseMenu = "UI_PauseMenu"; public const string PrefabUIDeathScreen = "UI_DeathScreen"; public const string PrefabUILoadingScreen = "UI_LoadingScreen"; // ── VFX ───────────────────────────────────────────────── public const string PrefabVFXHitSpark = "VFX_HitSpark"; public const string PrefabVFXDeathBurst = "VFX_DeathBurst"; public const string PrefabVFXParryFlash = "VFX_ParryFlash"; // ── Audio ──────────────────────────────────────────────── public const string PrefabAudioMasterMixer = "MasterMixer"; // ── Labels(用于 Addressables.LoadAssetsAsync 批量加载)─── public const string LabelEnemy = "Enemy"; public const string LabelPoolable = "Poolable"; public const string LabelBGM = "BGM"; public const string LabelCharms = "Charms"; } } ``` > **完整 `AddressKeys` 定义见 `13_AssetPoolModule.md §2`**,本节仅展示命名约定示例。 ### Addressables 分组策略 | 组名 | 内容 | 加载时机 | |------|------|---------| | `DefaultLocalGroup` | 常驻资源(GameManager Prefab、HUD 等) | 启动时预加载 | | `Room_{Region}` | 各区域房间所有资产 | 进入区域时加载 | | `Boss_{Name}` | Boss 战专属资产 | Boss 战开始前加载 | | `UI` | 所有 UI Prefab | 启动时预加载 | | `VFX_Common` | 通用特效 | 启动时预加载 | | `Audio_Music` | BGM(FMOD 包) | 按需加载 | --- ## 6. 代码风格约束 ### 禁止模式 ```csharp // ❌ 禁止:FindObjectOfType var player = FindObjectOfType(); // ❌ 禁止:跨 GameObject GetComponent(组件不在同一 Prefab 内) var stats = otherGO.GetComponent(); // ❌ 禁止:静态单例暴露子系统 public static AudioManager Instance { get; private set; } // 禁止全局访问 // ❌ 禁止:Resources.Load var sprite = Resources.Load("Enemies/goblin"); // ❌ 禁止:跨系统 Inspector 序列化引用 [SerializeField] private PlayerController _player; // 在 EnemyBase 中引用玩家 ❌ // ❌ 禁止:硬编码 Addressable 字符串 var handle = Addressables.LoadAsset("PLY_Player"); // ❌ 用 AddressKeys 常量 ``` ### 推荐模式 ```csharp // ✅ SO 事件频道(跨模块通信) [SerializeField] private VoidEventChannelSO _onPlayerDied; private void OnEnable() => _onPlayerDied.OnEventRaised += HandlePlayerDied; private void OnDisable() => _onPlayerDied.OnEventRaised -= HandlePlayerDied; // ✅ Inspector 序列化(同 Prefab 内) [SerializeField] private PlayerMovement _movement; // 在 PlayerController 中 ✅ // ✅ Addressables 加载 Addressables.InstantiateAsync(AddressKeys.PrefabPlayer).Completed += OnPlayerLoaded; // ✅ 对象池 GlobalObjectPool.Instance.Spawn(AddressKeys.PrefabVFXHitSpark, position, rotation); ``` ### OnEnable / OnDisable 规则 每个订阅 SO 事件频道的组件**必须**在 `OnDisable` 中取消订阅,防止内存泄漏: ```csharp private void OnEnable() { _channel.OnEventRaised += HandleEvent; } private void OnDisable() { _channel.OnEventRaised -= HandleEvent; } ``` --- ## 7. Prefab 组织规范 ### Player Prefab 层级 ``` [PLY_Player] ← PlayerController(协调器) ├── PlayerMovement ← Rigidbody2D 封装 ├── PlayerStats ← 属性容器 ├── PlayerCombat ← 攻击逻辑 ├── FormController ← 形态管理 ├── WeaponManager ← 武器切换 ├── SkillManager ← 技能执行 ├── SpringSystem ← 灵泉管理 ├── ParrySystem ← 弹反逻辑 ├── AnimancerComponent ← Animancer 入口 ├── PlayerFeedback ← MMF_Player ├── HurtBox ← Composite Collider 受击区域 ├── HitBox_Ground ← BoxCollider2D 地面攻击判定 ├── HitBox_Up ← BoxCollider2D 上劈判定 ├── HitBox_Down ← BoxCollider2D 下劈判定 ├── HitBox_Air ← BoxCollider2D 空中判定 └── SpriteRenderer ``` ### Enemy Prefab 通用层级 ``` [ENM_{EnemyName}] ← EnemyBase(协调器)+ BehaviorTree ├── EnemyMovement ← PathBerserker2d EnemyNavAgent 封装 ├── EnemyStats ← HP/攻击等属性 ├── EnemyCombat ← HitBox 管理 ├── AnimancerComponent ← 动画 ├── EnemyFeedback ← MMF_Player ├── HurtBox ← 受击区域 └── HitBox_{N} ← 各攻击 HitBox ``` --- ## 8. 场景组织规范 ### 场景文件命名 ``` Persistent ← 常驻场景(GameManager、AudioManager 等单例) MainMenu ← 主菜单 Room_{Region}_{Index:D2} ← 关卡房间 例: Room_Forest_01 Boss_{Region} ← Boss 战 例: Boss_Forest Hub_Town ← 区域枢纽 例: Hub_RestCamp ``` ### 房间场景层级结构 ``` Scene: Room_{Region}_{Index} ├── [Level] │ ├── Tilemap_Ground │ ├── Tilemap_Background │ ├── Tilemap_Foreground │ ├── Tilemap_OneWay │ └── Tilemap_Destructible ├── [NavMesh] │ ├── NavSurface │ └── NavLink_{N} ├── [Enemies] │ └── Enemy_*(Prefab 实例) ├── [World] │ ├── RoomTransition_{Direction} │ ├── SavePoint(可选) │ └── Collectible_* ├── [Camera] │ ├── CinemachineVirtualCamera │ └── CameraConfiner(PolygonCollider2D) └── [Lighting] └── GlobalLight2D ``` ### Persistent 场景组织 ``` Scene: Persistent ├── GameManager ← DontDestroyOnLoad 协调器 ├── AudioManager ← FMOD 封装 ├── ObjectPoolManager ← 对象池 ├── SettingsManager ← 设置管理 └── InputReader ← InputReaderSO(持久化) ```