Files
FlowScope/docs/superpowers/specs/2026-05-14-gamecore-design.md
2026-05-15 15:38:40 +08:00

11 KiB
Raw Blame History

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 优化接口

子容器

// 全局容器(跨场景)
var root = new GameContainer();

// 场景容器(继承全局,场景销毁时一起释放)
var sceneContainer = root.CreateChild();

// 子容器可访问父容器绑定
sceneContainer.Resolve<IAudioManager>(); // 从父容器拿

// 子容器同名绑定覆盖父容器
sceneContainer.Bind<IGameManager>().To<GameManager>().AsSingleton();

注入方式

// 构造函数注入 — 普通 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)

接口定义在核心包,实现可替换。

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)

接口定义在核心包,实现可替换。

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)

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)

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 — 资源加载

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 管理

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 — 音频管理

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 — 数据/配置管理

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 — 存档系统

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 — 网络层

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~/

完整使用示例

// 入口
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;
}