文档记录

This commit is contained in:
JSD\13999
2026-05-15 15:38:40 +08:00
parent d7b09891dc
commit 019703d2a8
18 changed files with 4221 additions and 1 deletions

View File

@@ -0,0 +1,447 @@
# FlowScope Game Core 设计文档
## 定位
面向休闲/超休闲游戏的 Unity 客户端通用框架。业务逻辑层保持纯 C#,基础设施层直接使用 Unity API。
## 整体架构
```
FlowScope Game Core
├── 基础设施层
│ ├── Container — 自研轻量 DIscope/resolve/dispose无反射
│ └── R3 — ReactiveProperty、事件流、集合订阅
├── 核心服务层(全部接口化,实现可替换)
│ ├── IResourceService — 资源加载/引用计数/分组释放
│ ├── ISaveService — 存档/读档持久化
│ ├── IConfigProvider — 配置表加载/查询
│ ├── IAudioService — BGM/SFX 池化/音量控制
│ ├── INetworkService — 网络请求/推送
│ └── UIManager — MVVM Panel 生命周期/页面栈/层级
├── 数据层按业务域拆分ReactiveProperty 驱动)
│ └── 各游戏按需定义自己的 Data 类
├── 业务特性层(自包含,独立生命周期)
│ └── 各 Feature: Load → Enter → Exit → Dispose
└── 生命周期编排
└── GameFlow — 启动/切换 Feature/关闭的全局时间线
```
## 设计原则
1. 接口化:核心服务全部走接口,实现可替换
2. 显式优于隐式DI 不做反射,手动注册手动传参
3. 按域拆分:数据类按业务域拆分,不建大 Data 类
4. 特性自包含:每个 Feature 自带资源组、订阅、ViewModel切换时干净释放
5. 框架只提供工具:不预设具体 Data 类,游戏自己定义
## 依赖方向(单向,不反向)
```
Feature → Core Services → Interfaces → Infrastructure (Container + R3)
Data Classes纯 C#,无依赖)
```
---
## 基础设施层
### Container — 自研轻量 DI
不做反射、不做构造函数自动注入、不做标签注入。显式注册,显式解析。
```csharp
public class Container : IDisposable
{
void RegisterInstance<T>(T instance);
void RegisterFactory<T>(Func<T> factory);
T Resolve<T>();
bool TryResolve<T>(out T value);
Container CreateScope(); // 子 scope 可访问父级,可覆盖父级
void Dispose(); // 释放 scope 内的 IDisposable
}
```
注册方式:
```csharp
container.RegisterInstance<IConfig>(config);
container.RegisterFactory<ISaveService>(() => new FileSaveService());
```
### R3
直接使用 R3 库提供:
- ReactiveProperty — 可观察属性MVVM 绑定基石
- ReactiveCollection — 可观察列表
- Subject — 事件流
- Observable.Timer / EveryUpdate — 计时和帧调度
- CompositeDisposable — 批量释放订阅
---
## 核心服务层
### IResourceService — 资源管理
```csharp
public interface IResourceService
{
Task<IResourceHandle<T>> LoadAsync<T>(string key) where T : class;
IResourceGroup CreateGroup();
}
public interface IResourceHandle<T> : IDisposable
{
T Asset { get; }
}
public interface IResourceGroup : IDisposable
{
void Add<T>(IResourceHandle<T> handle);
}
```
引用计数机制:同一 key 多次 Load 只加载一次,最后一个 handle Dispose 时才真正卸载。
默认实现AddressablesResourceService。
### ISaveService — 持久化
```csharp
public interface ISaveService
{
Task SaveAsync<T>(string key, T data);
Task<T> LoadAsync<T>(string key, T defaultValue = default);
void Delete(string key);
}
```
默认实现可选 FileSaveServiceJSON 文件)或 PlayerPrefsSaveService。
### IConfigProvider — 配置管理
```csharp
public interface IConfigRow
{
int Id { get; }
}
public interface IConfigProvider
{
Task LoadAllAsync();
T Get<T>(int id) where T : IConfigRow;
IReadOnlyList<T> GetAll<T>() where T : IConfigRow;
}
```
不绑定数据源JSON / CSV / Luban由实现决定。默认 JsonConfigProvider。
### IAudioService — 音频管理
```csharp
public interface IAudioService
{
void PlayBgm(string key, bool loop = true);
void StopBgm(float fadeOut = 0.5f);
void PlaySfx(string key);
void SetBgmVolume(float volume);
void SetSfxVolume(float volume);
void SetMute(bool mute);
}
```
内部AudioSource 对象池BGM 单独一个SFX 池化复用。
### INetworkService — 网络管理
```csharp
public interface INetworkService
{
Task<TResponse> SendAsync<TRequest, TResponse>(string path, TRequest data);
void On<TEvent>(Action<TEvent> handler);
}
```
初期可能用不上,但留好接口。默认 HttpNetworkService。
### UIManager — UI 管理
MVVM 模式的 Panel 生命周期管理。
```csharp
public class UIManager
{
Task OpenAsync<TPanel, TViewModel>(TViewModel viewModel) where TPanel : IPanel;
void Close<TPanel>();
void CloseAll();
}
public interface IPanel
{
void Bind(object viewModel);
void Unbind();
}
```
Panel 生命周期Instantiate → Bind → Show → ... → Hide → Unbind → Destroy。
层级管理Bottom基础层、Middle弹窗层、Top提示层
ViewModel 示例(纯 C#
```csharp
public class ShopViewModel
{
public ReactiveProperty<string> Title { get; } = new("商店");
public ReactiveCollection<ShopItemViewModel> Items { get; } = new();
private readonly PlayerData _player;
private readonly IConfigProvider _config;
public void BuyItem(int itemId)
{
var config = _config.Get<ItemConfig>(itemId);
if (_player.Gold.Value < config.Price) return;
_player.Gold.Value -= config.Price;
}
}
```
Panel 示例Unity MonoBehaviour
```csharp
public class ShopPanel : MonoBehaviour, IPanel
{
[SerializeField] private Text titleText;
[SerializeField] private Transform itemListRoot;
private ShopViewModel _vm;
private CompositeDisposable _disposables = new();
public void Bind(object viewModel)
{
_vm = (ShopViewModel)viewModel;
_vm.Title.Subscribe(t => titleText.text = t).AddTo(_disposables);
_vm.Items.ObserveAdd().Subscribe(e => CreateItemCell(e.Value)).AddTo(_disposables);
}
public void Unbind()
{
_disposables.Clear();
_vm = null;
}
private void OnDestroy() => Unbind();
}
```
---
## 数据层
框架不提供任何具体 Data 类,只提供 ReactiveProperty / ReactiveCollection 工具。
每个游戏按业务域自己定义:
```csharp
// 游戏需要金币?建一个
public class PlayerData
{
public ReactiveProperty<int> Level { get; } = new(1);
public ReactiveProperty<int> Gold { get; } = new(0);
}
// 不需要背包?就不建 InventoryData
// 需要设置?按需加
public class SettingsData
{
public ReactiveProperty<float> BgmVolume { get; } = new(1f);
public ReactiveProperty<string> Language { get; } = new("zh");
}
```
原则:一个 Data 类 = 一个业务域,新业务加新类。
---
## 业务特性层
### IFeature
```csharp
public interface IFeature : IDisposable
{
Task LoadAsync(); // 加载资源、创建 ViewModel
Task EnterAsync(); // 显示 UI、订阅事件
Task ExitAsync(); // 隐藏 UI、取消订阅
void Dispose(); // 释放资源
}
```
每个 Feature 自包含自己的资源组、订阅、ViewModel。切换时干净释放。
Feature 示例:
```csharp
public class ShopFeature : IFeature
{
private readonly IResourceService _resource;
private readonly UIManager _uiManager;
private readonly PlayerData _player;
private readonly IConfigProvider _config;
private IResourceGroup _resources;
private CompositeDisposable _disposables;
private ShopViewModel _viewModel;
public async Task LoadAsync()
{
_resources = _resource.CreateGroup();
var bgm = await _resource.LoadHandleAsync<AudioClip>("audio/bgm_shop");
_resources.Add(bgm);
_viewModel = new ShopViewModel(_player, _config);
}
public async Task EnterAsync()
{
_disposables = new CompositeDisposable();
await _uiManager.OpenAsync<ShopPanel, ShopViewModel>(_viewModel);
}
public async Task ExitAsync()
{
_uiManager.Close<ShopPanel>();
_disposables?.Dispose();
}
public void Dispose()
{
_resources?.Dispose();
_viewModel = null;
}
}
```
---
## 生命周期编排
### GameFlow
```csharp
public class GameFlow
{
private readonly Container _container;
private IFeature _currentFeature;
public async Task StartupAsync()
{
var config = _container.Resolve<IConfigProvider>();
await config.LoadAllAsync();
var save = _container.Resolve<ISaveService>();
var player = await save.LoadAsync<PlayerData>("player", new PlayerData());
_container.RegisterInstance(player);
await SwitchToAsync<MainMenuFeature>();
}
public async Task SwitchToAsync<TFeature>() where TFeature : IFeature, new()
{
if (_currentFeature != null)
{
await _currentFeature.ExitAsync();
_currentFeature.Dispose();
}
var feature = new TFeature();
await feature.LoadAsync();
await feature.EnterAsync();
_currentFeature = feature;
}
public async Task ShutdownAsync()
{
if (_currentFeature != null)
{
await _currentFeature.ExitAsync();
_currentFeature.Dispose();
}
var save = _container.Resolve<ISaveService>();
await save.SaveAsync("player", _container.Resolve<PlayerData>());
}
}
```
### 启动入口
```csharp
public class GameBootstrap : MonoBehaviour
{
private void Awake()
{
var container = new Container();
// 核心服务
container.RegisterInstance<IResourceService>(new AddressablesResourceService());
container.RegisterInstance<ISaveService>(new FileSaveService());
container.RegisterInstance<IConfigProvider>(new JsonConfigProvider());
container.RegisterInstance<IAudioService>(new UnityAudioService());
container.RegisterInstance<UIManager>(new UIManager());
// 游戏数据
container.RegisterInstance(new PlayerData());
container.RegisterInstance(new SettingsData());
var flow = new GameFlow(container);
flow.StartupAsync().Forget();
}
}
```
---
## 模块总表
| 模块 | 职责 | 类型 |
|------|------|------|
| Container | 轻量 DIscope/resolve/dispose | 自研 |
| R3 | ReactiveProperty、事件流、调度 | 第三方库 |
| IResourceService | 资源加载、引用计数、分组释放 | 接口 |
| ISaveService | 存档/读档持久化 | 接口 |
| IConfigProvider | 配置表加载/查询 | 接口 |
| IAudioService | BGM/SFX 池化、音量控制 | 接口 |
| INetworkService | 网络请求/推送 | 接口 |
| UIManager | MVVM Panel 生命周期、页面栈、层级 | 类 |
| Data 类 | 按业务域拆分的运行时状态 | 游戏自定义 |
| IFeature | 自包含特性模块,独立生命周期 | 接口 |
| GameFlow | 全局启动/切换/关闭时间线 | 类 |
## 技术选型
| 选型 | 决定 | 理由 |
|------|------|------|
| DI 容器 | 自研 | 休闲游戏只需显式注册/解析/scope不需要反射注入 |
| 响应式 | R3 | 成熟的 Unity 响应式库,自带 ObservableProperty/Collection |
| 异步 | C# Task + async/await | 休闲游戏的 GC 开销可忽略,不需要 UniTask 的零 GC |
| 资源加载 | Addressables | Unity 标准,通过 IResourceService 接口可替换 |
| 配置数据 | JSON默认 | 通过 IConfigProvider 接口可换 Luban |
| UI | uGUI + MVVM | BindableProperty 驱动ViewModel 纯 C# |
## 不做的事
- 不做反射式 DI / 自动注入
- 不做完整的 ORM
- 不做 UI 自动绑定
- 不做热更新框架
- 不做编辑器工具
- 不预设具体业务 Data 类
- 不依赖 UniTaskC# Task 够用)

View File

@@ -0,0 +1,89 @@
# FlowScope Game Core 需求分档
## 背景
FlowScope Game Core 的 P0 需求已经从早期“大而全框架蓝图”收敛为一套可执行的最小纵向切片。旧讨论中的部分能力已经重新分档:
- DI 自动注入进入 P0但 Container 核心保持轻量。
- UI 层级从固定三层改为可配置层级。
- UI 层内 LIFO 栈进入 P0完整导航路由延后。
- 配置 P0 只支持 JSON。
- 存档 P0 只支持本地轻量实现。
- 资源 P0 支持引用计数,但只保留 Addressables 默认后端。
- 音频 P0 只保留基础 BGM/SFX 能力和轻量 AudioHandle。
## 当前 P0 单一事实来源
P0 详细需求以以下文档为准:
- `docs/requirements/p0-requirements-set.md`
- `docs/requirements/p0-container.md`
- `docs/requirements/p0-gameflow.md`
- `docs/requirements/p0-feature.md`
- `docs/requirements/p0-data-r3.md`
- `docs/requirements/p0-configprovider.md`
- `docs/requirements/p0-saveservice.md`
- `docs/requirements/p0-resourceservice.md`
- `docs/requirements/p0-uimanager.md`
- `docs/requirements/p0-audioservice.md`
并行实施计划:
- `docs/superpowers/plans/2026-05-15-p0-parallel-implementation-plan.md`
---
## P0最小可运行核心
目标:跑通一个真实休闲/超休闲 Unity 游戏的启动、配置加载、存档加载、Feature 生命周期、MVVM UI、资源释放、音频播放和退出保存。
P0 包含:
| 模块 | P0 决策 |
|------|---------|
| Container | 显式工厂、Source Generator 自动注入、运行时反射降级 |
| GameFlow | 全局生命周期编排和 FeatureContext 所有权 |
| Feature | 消费 FeatureContext负责业务行为和引用清理 |
| R3 + Data | 直接使用 R3Data 保持纯 C# |
| ConfigProvider | JSON-only 强类型配置 |
| SaveService | 本地轻量存档 |
| ResourceService | Addressables-only 默认后端,支持引用计数 |
| UIManager | 可配置层级,层内 LIFO |
| AudioService | BGM/SFX、音量、静音、简单 SFX 池 |
---
## P1生产能力扩展
P1 只在 P0 接口稳定后推进,优先做成扩展而不是污染核心。
- CSV / Luban 配置插件。
- 按模块配置加载。
- 存档版本迁移。
- Resources / YooAsset 后端。
- UI 返回策略。
- Panel 预加载。
- AudioMixer / 3D 音频。
---
## P2包分发与编辑器体验
- Unity Package 分发。
- Samples~。
- Editor 导入向导。
- 配置检查工具。
- 资源扫描工具。
- 云存档适配。
- AssetBundle 适配。
---
## P3长期演进
- `[Inject]` 属性/方法注入。
- 全局 EventBus。
- 网络长连接。
- 热更新框架。
- UI 自动绑定。
- 大型项目资源预算和内存分析。

View File

@@ -0,0 +1,452 @@
# GameCore 游戏框架设计文档
## 概述
通用 Unity 游戏框架,以 Unity Package 形式分发,基于自研轻量 DI 容器,采用核心扩展式架构。目标:跨项目可复用 + 开箱即用的常用系统。
- **目标平台:** Unity 2022 LTS
- **架构模式:** 依赖注入 (DI)
- **分发形式:** Unity Package
- **DI 容器:** 自研轻量实现(反射,预留 Source Generator 优化接口)
---
## 架构:核心扩展式
```
GameCore (核心 asmdef)
├── DI 容器
├── 所有模块接口定义
└── 核心模块:事件系统、对象池、游戏流程控制、计时器
扩展包 (各自独立 asmdef只依赖核心)
├── GameCore.UI
├── GameCore.Audio
├── GameCore.Resource
├── GameCore.Data
├── GameCore.Save
└── GameCore.Network
可替换实现 (各自独立 asmdef)
├── GameCore.Defaults — 默认 EventBus + Timer
├── GameCore.R3 — R3 实现(可选替换 Defaults
├── GameCore.Resource.Resources
├── GameCore.Resource.Addressables
├── GameCore.Save.FileStorage
└── GameCore.Save.PlayerPrefsStorage
```
**设计原则:**
- 核心包定义接口不包含具体实现DI、Pool、Lifecycle 除外)
- 扩展包只依赖核心,互不依赖
- 可替换实现通过 DI Installer 注册,换实现不改上层代码
---
## DI 容器
### 能力
- 接口→实现绑定 (`Bind<IAudioManager>().To<AudioManager>()`)
- 实例绑定 (`ToValue(instance)`)
- 生命周期:`AsSingleton()` / `AsTransient()`
- 子容器(场景级作用域,子容器销毁时自动释放其单例)
- 构造函数注入(普通 C# 类)
- 属性注入 `[Inject]`MonoBehaviour
- 方法注入 `[Inject]`(初始化/PostConstruct
- 自动递归解析依赖链
- 反射实现,预留 Source Generator 优化接口
### 子容器
```csharp
// 全局容器(跨场景)
var root = new GameContainer();
// 场景容器(继承全局,场景销毁时一起释放)
var sceneContainer = root.CreateChild();
// 子容器可访问父容器绑定
sceneContainer.Resolve<IAudioManager>(); // 从父容器拿
// 子容器同名绑定覆盖父容器
sceneContainer.Bind<IGameManager>().To<GameManager>().AsSingleton();
```
### 注入方式
```csharp
// 构造函数注入 — 普通 C# 类
public class AudioManager : IAudioManager
{
private readonly IEventBus _eventBus;
public AudioManager(IEventBus eventBus) { _eventBus = eventBus; }
}
// 属性注入 — MonoBehaviour
public class GameCoreEntry : MonoBehaviour
{
[Inject] private IEventBus _eventBus;
}
// 方法注入 — 初始化/PostConstruct
public class GameManager : IGameManager
{
[Inject]
public void Init(IEventBus eventBus, IDataManager data)
{
// 所有依赖就绪后执行
}
}
```
---
## 核心模块
### 事件总线 (IEventBus)
接口定义在核心包,实现可替换。
```csharp
public interface IEventBus
{
void Subscribe<T>(Action<T> handler) where T : IEvent;
void Unsubscribe<T>(Action<T> handler) where T : IEvent;
void Publish<T>(T evt) where T : IEvent;
}
```
- 事件用 `struct`,避免 GC 压力
- 泛型事件分发,每个事件类型独立维护订阅者列表
默认实现:`GameCore.Defaults.DefaultEventBus`
R3 实现:`GameCore.R3.R3EventBus`
### 计时器/调度器 (ITimerManager)
接口定义在核心包,实现可替换。
```csharp
public interface ITimerManager
{
ITimerHandle Delay(float seconds, Action callback);
ITimerHandle Repeat(float interval, Action callback);
void Tick(float deltaTime);
}
public interface ITimerHandle
{
void Cancel();
bool IsDone { get; }
}
```
- 不依赖 MonoBehaviour Coroutine纯 Tick 驱动
- 内部用对象池管理 Timer 对象
默认实现:`GameCore.Defaults.DefaultTimerManager`
R3 实现:`GameCore.R3.R3TimerManager`
### 对象池 (IPoolManager)
```csharp
public interface IPoolManager
{
IPool<T> CreatePool<T>(Func<T> factory, int prewarm = 0);
IGameObjectPool CreateGameObjectPool(string prefabPath, int prewarm = 0);
}
public interface IPool<T>
{
T Get();
void Release(T item);
}
```
- 泛型对象池,支持任意类型
- 预加载容量,支持预热
- GameObject 池的创建/销毁由 Resource 扩展包实现,核心只定义接口
### 游戏流程控制 (GameLifecycle)
```csharp
public static class GameCore
{
public static void Launch(StartupConfig config);
public static void Tick();
public static void Shutdown();
}
public class StartupConfig
{
public IInstaller[] Installers;
public IStartupTask[] StartupTasks;
}
public interface IInstaller
{
void Install(IGameContainer container);
}
public interface IStartupTask
{
Task Execute();
}
```
生命周期阶段:
```
Launch → Installers 注册绑定 → ResolveAll 创建单例 → StartupTasks 按序执行 → Running
场景切换时
子容器销毁
Shutdown
```
- `IInstaller` 统一模块注册入口
- `IStartupTask` 控制启动顺序(支持异步)
- 场景切换时自动销毁场景级子容器
- Shutdown 时按反序释放所有模块
---
## 扩展包
### GameCore.Resource — 资源加载
```csharp
public interface IResourceLoader
{
T Load<T>(string path) where T : Object;
Task<T> LoadAsync<T>(string address) where T : Object;
void Release<T>(T asset);
void ReleaseAll();
}
```
- 统一封装,支持引用计数,同一资源多次加载不重复
- 存储实现可替换Resources / Addressables / AssetBundle / 自定义
### GameCore.UI — UI 管理
```csharp
public interface IUIManager
{
T Open<T>(string layer = null) where T : UIPanelBase;
void Close<T>() where T : UIPanelBase;
void CloseAll();
void CloseLayer(string layer);
void RegisterLayer(string name, Canvas canvas, int sortOrder);
}
public abstract class UIPanelBase : MonoBehaviour
{
[Inject] protected IEventBus _eventBus;
[Inject] protected IResourceLoader _loader;
public virtual void OnOpen() { }
public virtual void OnClose() { }
}
```
- 层级由用户自定义注册,不预设固定层级
- 面板栈管理,支持返回上一级
- 面板复用(配合对象池)
### GameCore.Audio — 音频管理
```csharp
public interface IAudioManager
{
IAudioHandle PlayBGM(string name, bool loop = true, float fadeIn = 0f);
void StopBGM(float fadeOut = 0f);
IAudioHandle PlaySFX(string name);
void Stop(IAudioHandle handle);
void Pause(IAudioHandle handle);
void Resume(IAudioHandle handle);
void SetBGMVolume(float volume);
void SetSFXVolume(float volume);
void MuteAll();
void UnmuteAll();
}
public interface IAudioHandle
{
float Volume { get; set; }
bool IsPlaying { get; }
void Stop(float fadeOut = 0f);
}
```
- fadeIn/fadeOut 处理音频过渡,具体曲线在实现层
- IAudioHandle 可停止单个音频
- SFX 用对象池管理 AudioSource
### GameCore.Data — 数据/配置管理
```csharp
public interface IDataManager
{
void RegisterParser<TParser>(string format) where TParser : IDataParser;
void LoadModule(string moduleName);
void UnloadModule(string moduleName);
bool IsModuleLoaded(string moduleName);
T GetConfig<T>(string key) where T : IConfig;
IReadOnlyList<T> GetConfigs<T>() where T : IConfig;
}
public interface IDataParser
{
IEnumerable<IConfig> Parse(string content);
}
```
- 格式自定义:注册 IDataParser 实现JSON/CSV/ScriptableObject/自定义)
- 分模块按需加载和卸载
### GameCore.Save — 存档系统
```csharp
public interface ISaveManager
{
Task Save(string slotName, object data);
Task<T> Load<T>(string slotName);
void Delete(string slotName);
bool Exists(string slotName);
string[] ListSaves();
}
public interface ISaveStorage
{
Task Write(string key, byte[] data);
Task<byte[]> Read(string key);
void Delete(string key);
bool Exists(string key);
}
```
- ISaveManager 负责序列化和业务逻辑
- ISaveStorage 负责底层读写可替换File / PlayerPrefs / 云存档 / 自定义
- 支持多存档位
### GameCore.Network — 网络层
```csharp
public interface INetworkService
{
Task<T> Request<T>(string url, object body);
Task Connect(string url);
void Disconnect();
void Send<T>(T message);
void OnReceive<T>(Action<T> handler);
}
```
- HTTP 请求封装GET/POST
- WebSocket 长连接
- 断线重连、超时处理、心跳机制
---
## 包结构
```
com.yourname.gamecore/
├── package.json
├── README.md
├── CHANGELOG.md
├── LICENSE
├── Runtime/
│ ├── GameCore/ # 核心 asmdef
│ │ ├── DI/
│ │ ├── Events/IEventBus.cs
│ │ ├── Timer/ITimerManager.cs
│ │ ├── Pool/
│ │ ├── Lifecycle/
│ │ └── Interfaces/
│ │
│ ├── GameCore.Defaults/ # 默认 EventBus + Timer
│ ├── GameCore.R3/ # R3 实现(可选)
│ │
│ ├── GameCore.UI/
│ ├── GameCore.Audio/
│ │
│ ├── GameCore.Resource/ # 接口
│ ├── GameCore.Resource.Resources/ # Resources 实现
│ ├── GameCore.Resource.Addressables/ # Addressables 实现
│ │
│ ├── GameCore.Data/
│ │
│ ├── GameCore.Save/ # 接口 + 序列化
│ ├── GameCore.Save.FileStorage/
│ ├── GameCore.Save.PlayerPrefsStorage/
│ │
│ └── GameCore.Network/
├── Editor/
│ └── GameCore.Editor/
└── Samples~/
```
---
## 完整使用示例
```csharp
// 入口
public class GameBootstrap : MonoBehaviour
{
void Awake()
{
GameCore.Launch(new StartupConfig
{
Installers = new IInstaller[]
{
new CoreInstaller(),
new TimerInstaller(),
new ResourceInstaller<AddressablesResourceLoader>(),
new AudioInstaller(),
new UIInstaller(),
new DataInstaller(),
new SaveInstaller<FileSaveStorage>(),
},
StartupTasks = new IStartupTask[]
{
new LoadConfigTask(),
new ShowMainMenuTask(),
}
});
}
void Update() => GameCore.Tick();
void OnDestroy() => GameCore.Shutdown();
}
// 使用模块
public class MainMenuPanel : UIPanelBase
{
[Inject] private IAudioManager _audio;
[Inject] private IEventBus _eventBus;
[Inject] private IDataManager _data;
public override void OnOpen()
{
_audio.PlayBGM("main_menu", fadeIn: 1f);
var weapons = _data.GetConfigs<WeaponConfig>();
RenderWeaponList(weapons);
}
public void OnStartGameClick()
{
_audio.PlaySFX("click");
_eventBus.Publish(new StartGameEvent { Level = 1 });
}
}
// 事件定义
public struct StartGameEvent : IEvent
{
public int Level;
}
```