简介
Extra2D 是一个轻量级跨平台 2D 游戏引擎,采用现代 C++17 架构,支持 Windows、Linux、macOS 和 Nintendo Switch 平台。
核心特性
- 跨平台支持:Windows、Linux、macOS、Nintendo Switch
- 模块化架构:模块系统 + 服务系统,灵活可扩展
- 多后端渲染:OpenGL / Vulkan 支持,易于扩展新后端
- 资源抽象层:统一的 Buffer、Pipeline、Framebuffer 接口
- 高性能批处理:独立 Batch 层,TrigLookup 优化,支持 10000 精灵/批次
- 场景图系统:树形节点结构,支持变换继承
- 输入系统:键盘、鼠标、手柄、触摸,事件驱动
- 渲染系统:OpenGL ES 3.2,支持自定义着色器
- 视口适配:多种适配模式,自动响应窗口大小变化
- 显存管理:VRAM 预算追踪,内存泄漏防护
- 音频系统:高质量音频播放(规划中)
- UI 系统:完整的 UI 控件支持(规划中)
架构概览
flowchart TB
subgraph Application["Application (应用层)"]
direction TB
APP[Application]
end
subgraph Core["Core Layer (核心层)"]
direction LR
MR[ModuleRegistry<br/>模块注册表]
SL[ServiceLocator<br/>服务定位器]
end
subgraph Modules["Modules (模块系统)"]
direction TB
WINDOW["Window Module<br/>窗口管理 P0"]
RENDER["Render Module<br/>渲染系统 P10"]
INPUT["Input Module<br/>输入处理 P20"]
end
subgraph Services["Services (服务系统)"]
direction TB
EVENT[EventService<br/>事件分发]
TIMER[TimerService<br/>计时器]
SCENE_SVC[SceneService<br/>场景管理]
CAMERA[CameraService<br/>相机系统]
end
subgraph Scene["Scene System (场景系统)"]
direction TB
SCENE[Scene<br/>场景]
NODE[Node<br/>节点]
SHAPE[ShapeNode<br/>形状节点]
SPRITE[Sprite<br/>精灵]
end
subgraph Graphics["Graphics (图形系统)"]
direction TB
RESOURCES[Resources<br/>资源抽象层]
BACKEND[RenderBackend<br/>渲染后端]
BATCH[Batch Layer<br/>批处理层]
GL[OpenGL Backend<br/>OpenGL 后端]
VK[Vulkan Backend<br/>Vulkan 后端]
SHADER[ShaderManager<br/>着色器管理]
TEXTURE[TexturePool<br/>纹理池]
MEMORY[Memory<br/>显存管理]
end
subgraph Platform["Platform (平台层)"]
direction TB
subgraph WindowBackends["窗口后端"]
SDL2[SDL2 Backend<br/>SDL2 后端]
GLFW[GLFW Backend<br/>GLFW 后端]
end
INPUT_SYS[Input System<br/>输入系统]
end
APP --> MR
APP --> SL
MR --> Modules
SL --> Services
SCENE_SVC --> SCENE
SCENE --> NODE
NODE --> SHAPE
NODE --> SPRITE
RENDER --> BACKEND
BACKEND --> BATCH
BATCH --> GL
BATCH --> VK
GL --> RESOURCES
GL --> SHADER
GL --> TEXTURE
GL --> MEMORY
WINDOW --> SDL2
WINDOW --> GLFW
INPUT --> INPUT_SYS
INPUT_SYS --> SDL2
INPUT_SYS --> GLFW
模块系统
| 模块 |
职责 |
优先级 |
| Window |
窗口管理 |
0 |
| Render |
渲染系统 |
10 |
| Input |
输入处理 |
20 |
服务系统
| 服务 |
职责 |
优先级 |
| EventService |
事件分发 |
100 |
| TimerService |
计时器 |
200 |
| SceneService |
场景管理 |
300 |
| CameraService |
相机系统 |
400 |
渲染系统架构
多后端支持
Extra2D 采用分层架构支持多渲染后端:
┌─────────────────────────────────────┐
│ Application (游戏逻辑) │
├─────────────────────────────────────┤
│ Renderer (渲染命令) │
├─────────────────────────────────────┤
│ Resources (resources/) │ ← 资源抽象层(后端无关)
│ - Buffer 接口 │
│ - Pipeline 接口 │
│ - Framebuffer 接口 │
│ - Shader 接口 │
│ - FontAtlas 接口 │
├─────────────────────────────────────┤
│ Batch Layer (batch/) │ ← 后端无关的批处理
│ - 顶点缓存管理 │
│ - 批次策略 (10000 精灵/批次) │
│ - TrigLookup 三角函数查表 │
│ - 批量绘制接口 │
├─────────────────────────────────────┤
│ Backend Layer (backends/) │ ← 具体 GPU 实现
│ - OpenGL / Vulkan / Metal / D3D │
│ - GLBuffer / GLPipeline / GLFramebuffer
│ - GPU 提交 │
└─────────────────────────────────────┘
资源抽象层
统一的资源接口,支持多后端实现:
| 接口 |
功能 |
OpenGL 实现 |
| Buffer |
顶点/索引/统一缓冲 |
GLBuffer |
| Pipeline |
渲染状态管理 |
GLPipeline |
| Framebuffer |
离屏渲染目标 |
GLFramebuffer |
| Shader |
着色器程序 |
GLShader |
| FontAtlas |
字体图集 |
GLFontAtlas |
显存管理
// VRAM 预算管理(Switch 默认 400MB)
VRAMMgr::get().setVRAMBudget(400 * 1024 * 1024);
// 自动追踪显存使用
// - GLTexture 自动追踪纹理显存
// - GLBuffer 自动追踪缓冲区显存
// 打印显存统计
VRAMMgr::get().printStats();
着色器系统
支持多后端的 JSON 元数据着色器系统:
{
"name": "sprite",
"backends": {
"opengl": {
"vertex": "backends/opengl/builtin/sprite.vert",
"fragment": "backends/opengl/builtin/sprite.frag"
},
"vulkan": {
"vertex": "backends/vulkan/builtin/sprite.vert.spv",
"fragment": "backends/vulkan/builtin/sprite.frag.spv"
}
}
}
性能优化
| 优化技术 |
说明 |
性能提升 |
| TrigLookup |
三角函数查表,避免每帧 sin/cos 计算 |
旋转计算 5-10x |
| 大批次容量 |
10000 精灵/批次,减少 draw call |
Draw call 减少 10x |
| 批量绘制 |
drawBatch() 一次性处理多个精灵 |
CPU 开销减少 20-30% |
| 静态索引 |
预生成索引缓冲区,避免运行时分配 |
内存分配开销消除 |
| 着色器缓存 |
二进制着色器缓存,加速启动 |
启动时间减少 |
| 状态缓存 |
GLPipeline 缓存状态,避免冗余 GL 调用 |
状态切换开销减少 |
| Orphaning |
动态缓冲区 orphaning 策略 |
GPU 同步开销减少 |
构建指南
环境要求
| 组件 |
要求 |
| 编译器 |
GCC 9+ / Clang 10+ / MSVC 2019+ |
| C++ 标准 |
C++17 |
| 构建工具 |
xmake 2.5+ |
| 目标平台 |
Windows / Linux / macOS / Nintendo Switch |
安装 xmake
# Windows (PowerShell)
Invoke-Expression (Invoke-WebRequest 'https://xmake.io/psget.text' -UseBasicParsing).Content
# macOS
brew install xmake
# Linux
sudo add-apt-repository ppa:xmake-io/xmake
sudo apt update
sudo apt install xmake
构建项目
基础构建(使用 SDL2 后端,默认)
# 配置项目
xmake f -p mingw -a x86_64 -m release -y
# 构建
xmake build
# 运行示例
xmake run demo_basic
使用 GLFW 后端
# 配置项目(指定 GLFW 后端)
xmake f -p mingw -a x86_64 -m release --window_backend=glfw -y
# 构建
xmake build
# 运行示例
xmake run demo_basic
切换窗口后端
# 切换到 GLFW 后端
xmake f --window_backend=glfw -y
# 切换回 SDL2 后端
xmake f --window_backend=sdl2 -y
# 清理重新配置
xmake f -c -y
切换渲染后端
# 切换到 Vulkan 后端
xmake f --render_backend=vulkan -y
# 切换回 OpenGL 后端(默认)
xmake f --render_backend=opengl -y
# 清理重新配置
xmake f -c -y
Nintendo Switch 构建
# 设置 devkitPro 环境
export DEVKITPRO=/opt/devkitpro
# 配置并构建
xmake f -p switch -m release -y
xmake build
快速开始
创建应用
#include <extra2d/extra2d.h>
using namespace extra2d;
int main() {
// 配置应用
AppConfig config = AppConfig::createDefault();
config.appName = "My Game";
config.appVersion = "1.0.0";
// 初始化
Application& app = Application::get();
if (!app.init(config)) {
return -1;
}
// 创建场景
auto scene = Scene::create();
scene->setBackgroundColor(Color(0.1f, 0.1f, 0.15f, 1.0f));
scene->setViewportSize(app.window().width(), app.window().height());
// 配置视口适配
auto cameraService = app.camera();
if (cameraService) {
ViewportConfig vpConfig;
vpConfig.logicWidth = app.window().width();
vpConfig.logicHeight = app.window().height();
vpConfig.mode = ViewportMode::AspectRatio;
cameraService->setViewportConfig(vpConfig);
}
// 运行场景
app.enterScene(scene);
app.run();
// 清理
app.shutdown();
return 0;
}
场景图示例
// 创建节点层级
auto root = makeShared<Node>();
root->setPos(width / 2, height / 2);
scene->addChild(root);
// 添加形状节点
auto rect = ShapeNode::createFilledRect(
Rect(-50, -50, 100, 100),
Color(1.0f, 0.4f, 0.4f, 1.0f)
);
root->addChild(rect);
// 变换继承
auto child = makeShared<Node>();
child->setPos(100, 0);
child->setRotation(45); // 旋转 45 度
child->setScale(0.5f); // 缩放 0.5
root->addChild(child);
输入事件
auto eventService = app.events();
// 键盘事件
eventService->addListener(EventType::KeyPressed, [](Event& e) {
auto& key = std::get<KeyEvent>(e.data);
if (key.keyCode == static_cast<int>(Key::Escape)) {
Application::get().quit();
}
});
// 鼠标事件
eventService->addListener(EventType::MouseButtonPressed, [](Event& e) {
auto& mouse = std::get<MouseButtonEvent>(e.data);
// 处理鼠标点击
});
// 手柄事件
eventService->addListener(EventType::GamepadButtonPressed, [](Event& e) {
auto& gamepad = std::get<GamepadButtonEvent>(e.data);
// 处理手柄输入
});
示例程序
| 示例 |
说明 |
demo_basic |
基础示例:场景图、输入事件、视口适配 |
demo_text_rendering |
文字渲染示例:使用 GLFontAtlas 渲染文字 |
运行示例:
xmake run demo_basic
技术栈
| 技术 |
用途 |
版本 |
| OpenGL ES |
2D 图形渲染 |
3.2 |
| SDL2 |
窗口和输入管理(可选) |
2.0+ |
| GLFW |
窗口和输入管理(可选) |
3.4+ |
| GLM |
数学库 |
0.9.9+ |
| nlohmann_json |
JSON 解析 |
3.x |
| glad |
OpenGL 加载器 |
最新版 |
| stb_image |
图像加载 |
最新版 |
| stb_truetype |
字体渲染 |
最新版 |
| xmake |
构建系统 |
2.5+ |
文档
目录结构
Extra2D/
├── Extra2D/
│ ├── include/
│ │ ├── KHR/ # KHR 平台头文件
│ │ ├── extra2d/ # 引擎公共头文件
│ │ │ ├── app/ # 应用程序
│ │ │ ├── audio/ # 音频配置
│ │ │ ├── config/ # 配置系统
│ │ │ ├── core/ # 核心类型
│ │ │ ├── event/ # 事件系统
│ │ │ ├── graphics/ # 图形渲染
│ │ │ │ ├── backends/ # 渲染后端
│ │ │ │ │ ├── opengl/ # OpenGL 实现
│ │ │ │ │ │ ├── gl_context.h # OpenGL 上下文
│ │ │ │ │ │ ├── gl_buffer.h # 缓冲区实现
│ │ │ │ │ │ ├── gl_pipeline.h # 管线状态
│ │ │ │ │ │ ├── gl_framebuffer.h # 帧缓冲
│ │ │ │ │ │ ├── gl_renderer.h # 渲染器
│ │ │ │ │ │ ├── gl_texture.h # 纹理
│ │ │ │ │ │ ├── gl_shader.h # 着色器
│ │ │ │ │ │ ├── gl_sprite_batch.h # 精灵批处理
│ │ │ │ │ │ └── gl_font_atlas.h # 字体图集
│ │ │ │ │ └── vulkan/ # Vulkan 实现
│ │ │ │ ├── batch/ # 批处理层(后端无关)
│ │ │ │ │ ├── sprite_batch.h
│ │ │ │ │ └── shape_batch.h
│ │ │ │ ├── resources/ # 资源抽象层(新增)
│ │ │ │ │ ├── buffer.h # 缓冲区接口
│ │ │ │ │ ├── pipeline.h # 管线接口
│ │ │ │ │ ├── framebuffer.h # 帧缓冲接口
│ │ │ │ │ ├── shader.h # 着色器接口
│ │ │ │ │ └── font_atlas.h # 字体接口
│ │ │ │ ├── core/ # 渲染核心
│ │ │ │ ├── camera/ # 相机和视口
│ │ │ │ ├── shader/ # Shader 系统
│ │ │ │ ├── texture/ # 纹理系统
│ │ │ │ └── memory/ # GPU 内存管理
│ │ │ │ ├── gpu_context.h # GPU 上下文状态
│ │ │ │ └── vram_manager.h # 显存管理器
│ │ │ ├── platform/ # 平台抽象
│ │ │ ├── scene/ # 场景系统
│ │ │ ├── services/ # 服务接口
│ │ │ └── utils/ # 工具库
│ │ ├── glad/ # OpenGL 加载器
│ │ └── stb/ # STB 单文件库
│ ├── shaders/ # 着色器文件
│ │ ├── backends/ # 后端特定着色器
│ │ │ └── opengl/ # OpenGL 着色器
│ │ └── shared/ # 共享着色器元数据
│ └── src/ # 源文件
│ ├── app/ # 应用实现
│ ├── config/ # 配置实现
│ ├── core/ # 核心实现
│ ├── event/ # 事件实现
│ ├── glad/ # GLAD 实现
│ ├── graphics/ # 图形实现
│ │ ├── backends/ # 渲染后端实现
│ │ │ ├── opengl/ # OpenGL 实现
│ │ │ │ ├── gl_context.cpp
│ │ │ │ ├── gl_buffer.cpp
│ │ │ │ ├── gl_pipeline.cpp
│ │ │ │ ├── gl_framebuffer.cpp
│ │ │ │ ├── gl_renderer.cpp
│ │ │ │ ├── gl_texture.cpp
│ │ │ │ ├── gl_shader.cpp
│ │ │ │ ├── gl_sprite_batch.cpp
│ │ │ │ └── gl_font_atlas.cpp
│ │ │ └── vulkan/ # Vulkan 实现
│ │ ├── batch/ # 批处理层实现
│ │ ├── resources/ # 资源抽象层(接口定义)
│ │ ├── core/ # 渲染核心
│ │ ├── camera/ # 相机和视口
│ │ ├── shader/ # Shader 系统
│ │ ├── texture/ # 纹理系统
│ │ └── memory/ # GPU 内存管理
│ │ ├── gpu_context.cpp
│ │ └── vram_manager.cpp
│ ├── platform/ # 平台实现
│ │ └── backends/ # 后端实现
│ │ ├── sdl2/ # SDL2 后端
│ │ └── glfw/ # GLFW 后端
│ ├── scene/ # 场景实现
│ ├── services/ # 服务实现
│ └── utils/ # 工具实现
├── docs/ # 文档
├── examples/ # 示例程序
│ └── basic/ # 基础示例
└── xmake/ # 构建配置
└── toolchains/ # 工具链配置
平台支持
| 平台 |
窗口后端 |
图形 API |
状态 |
| Windows |
SDL2 / GLFW |
OpenGL ES 3.2 / Vulkan |
✅ 支持 |
| Linux |
SDL2 / GLFW |
OpenGL ES 3.2 / Vulkan |
✅ 支持 |
| macOS |
SDL2 / GLFW |
OpenGL ES 3.2 / Vulkan |
✅ 支持 |
| Nintendo Switch |
SDL2 / GLFW |
OpenGL ES 3.2 |
✅ 支持 |
贡献
欢迎提交 Issue 和 Pull Request!
许可证
Extra2D 使用 MIT 许可证。
联系方式