19 KiB
19 KiB
01 · 项目结构与规范
作用:定义文件夹布局、Assembly Definition 清单、命名规范、ScriptableObject 资产路径、代码风格约束。
所有程序员必读,开始任何模块开发前先阅读本文档。
目录
- 文件夹布局
- Assembly Definitions(asmdef)
- 命名规范
- ScriptableObject 资产组织
- Addressables 资产组织
- 代码风格约束
- Prefab 组织规范
- 场景组织规范
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() |
字段命名
// 私有序列化字段:_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)
// 路径: 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. 代码风格约束
禁止模式
// ❌ 禁止: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 常量
推荐模式
// ✅ 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 中取消订阅,防止内存泄漏:
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(持久化)