474 lines
19 KiB
Markdown
474 lines
19 KiB
Markdown
# 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<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
|
||
│ └── CameraConfiner(PolygonCollider2D)
|
||
└── [Lighting]
|
||
└── GlobalLight2D
|
||
```
|
||
|
||
### Persistent 场景组织
|
||
|
||
```
|
||
Scene: Persistent
|
||
├── GameManager ← DontDestroyOnLoad 协调器
|
||
├── AudioManager ← FMOD 封装
|
||
├── ObjectPoolManager ← 对象池
|
||
├── SettingsManager ← 设置管理
|
||
└── InputReader ← InputReaderSO(持久化)
|
||
```
|