# 应用层与 Core 分层设计 本文记录当前项目的代码分层。`src/Core` 是可复用底层库,`src/Apps` 放具体应用和游戏。 ## 目录边界 ```text src/ Core/ # 底层库:渲染、数学、资源、平台适配 Asset/ # 离线资源格式加载 Core/ # FrameBuffer、DepthBuffer、Renderer、Timer Draw2D/ # Core::DrawContext Math/ # Vector、Matrix、MathUtil Platform/ # 显示、时间、音频、按键等平台接口和后端 Rasterizer/ # 线段和三角形光栅化 RenderData/ # Color、Image、Triangle、Tilemap 等数据结构 Scene/ # Camera、Transform、Mesh、Model Shading/ # Shader 相关代码 Apps/ Demo/ # Core 能力演示 Game/ # Tom 游戏 ``` `src/Core/Core` 这个二级目录保留的是原底层库里的核心运行时对象。它和顶层 `src/Core` 名称重复,但含义不同: - `src/Core`:整个底层库。 - `src/Core/Core`:底层库内部的 framebuffer、depthbuffer、timer 等核心对象。 后续如果觉得重复命名影响阅读,可以再把 `src/Core/Core` 单独改成 `Runtime/` 或 `Buffer/`,但这次先只做旧底层库名称到 `Core` 的一致性修复。 ## 依赖方向 允许: ```text Apps -> Shared -> Core -> Platform Apps -> Core ``` 禁止: ```text Core -> Apps Core -> Shared GameA -> GameB GameB -> GameA Platform -> Game ``` Core 层不应该知道具体游戏规则、场景流程、角色状态机、关卡数据或游戏专属资源路径。 ## Core 职责 Core 只提供底层能力: - 管理 `FrameBuffer`、`DepthBuffer` 和绘制上下文。 - 提供基础绘制接口:line、triangle、sprite、sprite region、tilemap、bitmap font。 - 提供基础数学、颜色、图片、三角形、tilemap 等数据结构。 - 封装 SDL2 / framebuffer 显示提交。 - 提供独立时间源 `Platform::ITimeSource`。 - 提供音频输入、音频输出和按键输入的抽象接口。 - 使用离线转换后的运行时资源,不在热路径解码 PNG/TTF。 Core 不做: - 不实现具体游戏规则。 - 不直接读取某个游戏专属资源目录。 - 不在核心绘制接口暴露 SDL2 类型。 - 不在每帧热路径中执行图片、字体解码或文件 IO。 ## 应用职责 `src/Apps/*` 负责具体应用流程: - 创建具体游戏或 Demo 的主循环。 - 加载应用自己的资源。 - 调用 `Core::DrawContext` 绘制画面。 - 根据平台输入更新游戏状态。 当前主程序位于: ```text src/Apps/Game/Main.cpp ``` 它默认启动 Tom 游戏视觉入口。 ## DrawContext `Core::DrawContext` 是当前统一绘制入口,位于: ```text src/Core/Draw2D/DrawContext.h src/Core/Draw2D/DrawContext.cpp ``` 它封装: - `Core::FrameBuffer` - `Core::DepthBuffer` - `Rasterizer::Rasterizer` - `Rasterizer::TriangleRasterizer` 对外提供: ```cpp Core::DrawContext ctx(width, height); ctx.clear(RenderData::Color(18, 18, 24, 255)); ctx.draw_sprite(x, y, image); ctx.draw_text(font, x, y, color, "text"); ctx.present(display); ``` ## 显示后端 平台层采用“抽象接口 + 多套后端实现”的模式。 显示层通过 `Platform::IDisplay` 抽象: ```text Platform::IDisplay SDLDisplay # PC / SDL2 调试后端 FBDisplay # Linux /dev/fb0 后端 ``` 音频输入通过 `Platform::IAudioInput` 抽象: ```text Platform::IAudioInput SdlAudioInput # PC / SDL2 麦克风后端 AlsaAudioInput # Linux ALSA 录音后端 ``` 音频输出通过 `Platform::IAudioOutput` 抽象: ```text Platform::IAudioOutput SdlAudioOutput # PC / SDL2 扬声器后端 AlsaAudioOutput # Linux ALSA 播放后端 ``` 按键输入通过 `Platform::IButtonInput` 抽象: ```text Platform::IButtonInput SdlKeyboardButtonInput # PC / SDL2 键盘后端,默认空格键 EvdevButtonInput # Linux evdev 按键后端 ``` 游戏代码只能依赖这些 `I*` 接口。ALSA、evdev、SDL2、`/dev/fb0` 等平台细节只能出现在 `src/Core/Platform` 或明确的平台适配代码中。 如果只需要当前构建平台的默认后端,可以使用 `Platform::DefaultAudioInput`、`Platform::DefaultAudioOutput` 和 `Platform::DefaultButtonInput`。 CMake 通过 `USE_FRAMEBUFFER` 选择实现: ```cmake -DUSE_FRAMEBUFFER=OFF # 默认,使用 SDLDisplay -DUSE_FRAMEBUFFER=ON # 使用 FBDisplay ``` ## 后续建议 1. 保持 `Core` 不依赖 `Apps`。 2. 新增游戏逻辑放在 `src/Apps/Game` 或新的 `src/Apps/*`。 3. 新增底层绘制、数学、资源格式、平台显示能力放在 `src/Core`。 4. 如果继续清理命名,优先处理 `src/Core/Core` 这个重复目录名。