Files
zeling_v2/Docs/Architecture/01_ProjectStructure.md
2026-05-08 11:04:00 +08:00

474 lines
19 KiB
Markdown
Raw Permalink 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.
# 01 · 项目结构与规范
> **作用**定义文件夹布局、Assembly Definition 清单、命名规范、ScriptableObject 资产路径、代码风格约束。
> **所有程序员必读**,开始任何模块开发前先阅读本文档。
---
## 目录
1. [文件夹布局](#1-文件夹布局)
2. [Assembly Definitionsasmdef](#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.AIBehavior 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.EditorEditor 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.EditorEditor 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` | BGMFMOD 包) | 按需加载 |
---
## 6. 代码风格约束
### 禁止模式
```csharp
// ❌ 禁止FindObjectOfType
var player = FindObjectOfType<PlayerController>();
// ❌ 禁止:跨 GameObject GetComponent组件不在同一 Prefab 内)
var stats = otherGO.GetComponent<PlayerStats>();
// ❌ 禁止:静态单例暴露子系统
public static AudioManager Instance { get; private set; } // 禁止全局访问
// ❌ 禁止Resources.Load
var sprite = Resources.Load<Sprite>("Enemies/goblin");
// ❌ 禁止:跨系统 Inspector 序列化引用
[SerializeField] private PlayerController _player; // 在 EnemyBase 中引用玩家 ❌
// ❌ 禁止:硬编码 Addressable 字符串
var handle = Addressables.LoadAsset<GameObject>("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<HitEffect>(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
│ └── CameraConfinerPolygonCollider2D
└── [Lighting]
└── GlobalLight2D
```
### Persistent 场景组织
```
Scene: Persistent
├── GameManager ← DontDestroyOnLoad 协调器
├── AudioManager ← FMOD 封装
├── ObjectPoolManager ← 对象池
├── SettingsManager ← 设置管理
└── InputReader ← InputReaderSO持久化
```