Extra2D/docs/module_system.md

478 lines
17 KiB
Markdown
Raw Normal View History

# Extra2D 模块系统
## 概述
Extra2D 采用模块化架构设计,核心功能通过**模块系统**和**服务系统**管理:
- **模块 (Module)**: 平台级初始化,管理硬件资源(窗口、渲染、输入)
- **服务 (Service)**: 运行时功能,通过服务定位器管理(场景、计时器、事件、相机)
## 架构图
```
┌─────────────────────────────────────────────────────────────┐
│ Application │
│ (协调模块和服务,通过服务定位器获取依赖) │
└─────────────────────────────────────────────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ 模块系统 │ │ 服务系统 │
│ (Module - 硬件资源) │ │ (Service - 运行时功能) │
├─────────────────────────────┤ ├─────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ │ │ ┌─────────┐ ┌─────────┐ │
│ │ Window │ │ Render │ │ │ │ Logger │ │ Scene │ │
│ │ Module │ │ Module │ │ │ │ Service │ │ Service │ │
│ │ P0 │ │ P10 │ │ │ │ │ │ │ │
│ └─────────┘ └─────────┘ │ │ └─────────┘ └─────────┘ │
│ ┌─────────┐ │ │ ┌─────────┐ ┌─────────┐ │
│ │ Input │ │ │ │ Timer │ │ Event │ │
│ │ Module │ │ │ │ Service │ │ Service │ │
│ │ P20 │ │ │ │ │ │ │ │
│ └─────────┘ │ │ └─────────┘ └─────────┘ │
│ │ │ ┌─────────┐ │
│ │ │ │ Camera │ │
│ │ │ │ Service │ │
│ │ │ │ │ │
│ │ │ └─────────┘ │
└─────────────────────────────┘ └─────────────────────────────┘
```
## 模块 vs 服务
| 特性 | 模块 (Module) | 服务 (Service) |
|-----|--------------|---------------|
| 用途 | 平台级初始化 | 运行时功能 |
| 生命周期 | Application 管理 | ServiceLocator 管理 |
| 依赖方式 | 通过 `deps()` 方法声明 | 通过 `ServiceLocator` 获取 |
| 可替换性 | 编译时确定 | 运行时可替换 |
| 示例 | Window, Render, Input | Scene, Timer, Event, Camera |
## 模块系统
### 模块基类
所有模块继承自 `Module` 基类:
```cpp
class Module {
public:
virtual ~Module() = default;
virtual bool init() = 0; // 初始化
virtual void shutdown() = 0; // 关闭
virtual bool ok() const = 0; // 检查状态
virtual const char* name() const = 0; // 模块名称
virtual int priority() const { return 100; } // 优先级(越小越优先)
virtual std::vector<std::type_index> deps() const { return {}; } // 依赖
void setApp(Application* app) { app_ = app; }
Application* app() const { return app_; }
protected:
Application* app_ = nullptr;
};
```
### 内置模块
| 模块 | 优先级 | 依赖 | 职责 |
|-----|-------|------|------|
| WindowModule | 0 | 无 | 窗口创建和管理 |
| RenderModule | 10 | WindowModule | 渲染后端初始化 |
| InputModule | 20 | WindowModule | 输入设备管理 |
### 模块配置
每个模块有自己的配置结构:
```cpp
// Window 模块配置
struct WindowCfg {
std::string title = "Extra2D";
int w = 1280;
int h = 720;
WindowMode mode = WindowMode::Windowed;
bool vsync = true;
int priority = 0;
std::string backend = "sdl2"; // "sdl2" 或 "glfw"
};
// Render 模块配置
struct RenderCfg {
BackendType backend = BackendType::OpenGL;
int targetFPS = 60;
bool vsync = true;
int multisamples = 0;
int priority = 10;
};
// Input 模块配置
struct InputCfg {
float deadzone = 0.15f;
float mouseSensitivity = 1.0f;
bool enableVibration = true;
int maxGamepads = 4;
int priority = 20;
};
```
### 使用模块
```cpp
Application app;
// 配置 Window 模块
app.use<WindowModule>([](auto& cfg) {
cfg.title = "My Game";
cfg.w = 1920;
cfg.h = 1080;
cfg.backend = "glfw"; // 使用 GLFW 后端
});
// 配置 Render 模块
app.use<RenderModule>([](auto& cfg) {
cfg.backend = BackendType::OpenGL;
cfg.vsync = true;
cfg.targetFPS = 60;
});
// 配置 Input 模块
app.use<InputModule>([](auto& cfg) {
cfg.deadzone = 0.2f;
cfg.enableVibration = true;
});
app.run();
```
### 构建时选择后端
```bash
# 选择窗口后端
xmake f --window_backend=sdl2 -y # 使用 SDL2默认
xmake f --window_backend=glfw -y # 使用 GLFW
# 选择渲染后端
xmake f --render_backend=opengl -y # 使用 OpenGL默认
xmake f --render_backend=vulkan -y # 使用 Vulkan
```
## 服务系统
### 服务接口基类
```cpp
class IService {
public:
virtual ~IService() = default;
virtual ServiceInfo getServiceInfo() const = 0;
virtual bool initialize() = 0;
virtual void shutdown() = 0;
virtual void update(float deltaTime) {}
virtual bool isInitialized() const = 0;
};
```
### 内置服务
| 服务 | 用途 | 自动注册宏 |
|-----|------|-----------|
| LoggerService | 日志记录 | `E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger)` |
| SceneService | 场景管理 | `E2D_AUTO_REGISTER_SERVICE(ISceneService, SceneService)` |
| TimerService | 计时器 | `E2D_AUTO_REGISTER_SERVICE(ITimerService, TimerService)` |
| EventService | 事件分发 | `E2D_AUTO_REGISTER_SERVICE(IEventService, EventService)` |
| CameraService | 相机系统 | `E2D_AUTO_REGISTER_SERVICE(ICameraService, CameraService)` |
### 使用服务
```cpp
// 获取服务
auto logger = app.logger();
auto sceneService = app.scenes();
auto timerService = app.timers();
auto eventService = app.events();
auto cameraService = app.camera();
// 使用日志服务
logger->info("Application started");
logger->setLevel(LogLevel::Debug);
E2D_LOG_INFO("Player position: {}, {}", x, y);
E2D_LOG_ERROR("Failed to load texture: {}", filepath);
// 使用场景服务
sceneService->pushScene(myScene);
// 使用计时器服务
timerService->addTimer(1.0f, []() {
E2D_LOG_INFO("Timer fired!");
});
// 使用事件服务
eventService->addListener(EventType::KeyPressed, [](Event& e) {
auto& keyEvent = std::get<KeyEvent>(e.data);
E2D_LOG_INFO("Key pressed: {}", keyEvent.keyCode);
});
// 使用相机服务
cameraService->setPosition(100, 100);
cameraService->setZoom(2.0f);
```
## 渲染后端
### 支持的后端
| 后端 | 状态 | 平台支持 |
|-----|------|---------|
| OpenGL | 完整实现 | Windows, Linux, macOS, Switch |
| Vulkan | 计划中 | Windows, Linux, macOS, Switch |
### 渲染后端接口
```cpp
class Renderer {
public:
virtual ~Renderer() = default;
// 生命周期
virtual bool init(IWindow* window) = 0;
virtual void shutdown() = 0;
// 帧管理
virtual void beginFrame(const Color &clearColor) = 0;
virtual void endFrame() = 0;
virtual void setViewport(int x, int y, int width, int height) = 0;
virtual void setVSync(bool enabled) = 0;
// 状态设置
virtual void setBlendMode(BlendMode mode) = 0;
virtual void setViewProjection(const glm::mat4 &matrix) = 0;
// 变换矩阵栈
virtual void pushTransform(const glm::mat4 &transform) = 0;
virtual void popTransform() = 0;
virtual glm::mat4 getCurrentTransform() const = 0;
// 纹理
virtual Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels, int channels) = 0;
virtual Ptr<Texture> loadTexture(const std::string &filepath) = 0;
// 精灵批处理
virtual void beginSpriteBatch() = 0;
virtual void drawSprite(const Texture &texture, const Rect &destRect, const Rect &srcRect,
const Color &tint, float rotation, const Vec2 &anchor) = 0;
virtual void endSpriteBatch() = 0;
virtual void flush() = 0;
// 形状渲染
virtual void drawLine(const Vec2 &start, const Vec2 &end, const Color &color, float width = 1.0f) = 0;
virtual void drawRect(const Rect &rect, const Color &color, float width = 1.0f) = 0;
virtual void fillRect(const Rect &rect, const Color &color) = 0;
virtual void drawCircle(const Vec2 &center, float radius, const Color &color,
int segments = 32, float width = 1.0f) = 0;
virtual void fillCircle(const Vec2 &center, float radius, const Color &color, int segments = 32) = 0;
// 文字渲染
virtual Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize, bool useSDF = false) = 0;
virtual void drawText(const FontAtlas &font, const std::string &text, const Vec2 &position, const Color &color) = 0;
// 工厂方法
static UniquePtr<Renderer> create(BackendType type);
};
```
## 资源抽象层
渲染后端通过资源抽象层实现跨平台兼容:
```
┌─────────────────────────────────────────────────────────────┐
│ 前端 (Frontend) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Renderer │ │ SpriteBatch │ │ 其他 │ │
│ └──────┬──────┘ └──────┬──────┘ └─────────────────────┘ │
└─────────┼────────────────┼──────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ 资源抽象层 (resources/) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Buffer │ │ Pipeline │ │ Framebuf │ │ Shader │ │
│ │ (缓冲区) │ │ (管线) │ │(帧缓冲) │ │ (着色器) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Texture │ │ FontAtlas│ │
│ │ (纹理) │ │(字体图集)│ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 后端实现 (backends/) │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ OpenGL │ │ Vulkan │ │
│ │ GLBuffer │ │ VKBuffer │ │
│ │ GLPipeline │ │ VKPipeline │ │
│ │ GLFramebuffer │ │ VKFramebuffer │ │
│ │ GLShader │ │ VKShader │ │
│ │ GLTexture │ │ VKTexture │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 输入事件系统
### 事件类型
```cpp
enum class EventType {
// 键盘
KeyPressed,
KeyReleased,
KeyRepeat,
// 鼠标
MouseButtonPressed,
MouseButtonReleased,
MouseMoved,
MouseScrolled,
// 手柄
GamepadConnected,
GamepadDisconnected,
GamepadButtonPressed,
GamepadButtonReleased,
// 触摸
TouchBegan,
TouchMoved,
TouchEnded,
// 窗口
WindowResize,
WindowClose,
};
```
### 事件监听
```cpp
auto eventService = app.events();
// 监听键盘事件
eventService->addListener(EventType::KeyPressed, [](Event& e) {
auto& key = std::get<KeyEvent>(e.data);
E2D_LOG_INFO("Key: {}, mods: {}", key.keyCode, key.mods);
});
// 监听鼠标事件
eventService->addListener(EventType::MouseButtonPressed, [](Event& e) {
auto& mouse = std::get<MouseButtonEvent>(e.data);
E2D_LOG_INFO("Mouse button: {} at ({}, {})",
mouse.button, mouse.position.x, mouse.position.y);
});
```
## 场景图系统
### Node 基类
```cpp
class Node : public std::enable_shared_from_this<Node> {
public:
// 层级管理
void addChild(Ptr<Node> child);
void removeChild(Ptr<Node> child);
void detach();
void clearChildren();
Ptr<Node> getParent() const;
const std::vector<Ptr<Node>>& getChildren() const;
// 变换属性
void setPos(const Vec2& pos);
void setRotation(float degrees);
void setScale(const Vec2& scale);
void setAnchor(const Vec2& anchor);
void setOpacity(float opacity);
void setVisible(bool visible);
void setZOrder(int zOrder);
// 世界变换
Vec2 toWorld(const Vec2& localPos) const;
Vec2 toLocal(const Vec2& worldPos) const;
glm::mat4 getLocalTransform() const;
glm::mat4 getWorldTransform() const;
// 生命周期回调
virtual void onEnter();
virtual void onExit();
virtual void onUpdate(float dt);
virtual void onRender(Renderer& renderer);
};
```
### 使用场景
```cpp
auto scene = Scene::create();
// 创建形状节点
auto rect = ShapeNode::createFilledRect(Rect(0, 0, 100, 100), Color(1.0f, 0.4f, 0.4f, 1.0f));
auto circle = ShapeNode::createFilledCircle(Vec2(0, 0), 50, Color(0.4f, 0.4f, 1.0f, 1.0f));
// 添加到场景
scene->addChild(rect);
scene->addChild(circle);
// 运行场景
app.scenes()->runWithScene(scene);
```
## 视口适配系统
### 视口适配模式
```cpp
enum class ViewportMode {
AspectRatio, // 保持宽高比,可能有黑边
Stretch, // 拉伸填满整个窗口
Center, // 居中显示,不缩放
Custom // 自定义缩放和偏移
};
```
### 配置视口
```cpp
auto cameraService = app.camera();
if (cameraService) {
ViewportConfig vpConfig;
vpConfig.logicWidth = 1280.0f;
vpConfig.logicHeight = 720.0f;
vpConfig.mode = ViewportMode::AspectRatio;
vpConfig.letterboxColor = Color(0.0f, 0.0f, 0.0f, 1.0f);
cameraService->setViewportConfig(vpConfig);
cameraService->updateViewport(windowWidth, windowHeight);
cameraService->applyViewportAdapter();
}
```
## 平台支持
| 平台 | 窗口后端 | 图形 API |
|-----|---------|---------|
| Windows | SDL2 / GLFW | OpenGL / Vulkan |
| Linux | SDL2 / GLFW | OpenGL / Vulkan |
| macOS | SDL2 / GLFW | OpenGL / Vulkan |
| Nintendo Switch | SDL2 / GLFW | OpenGL / Vulkan |
## 示例
完整示例请参考:
- [examples/basic/main.cpp](../../examples/basic/main.cpp) - 基础示例
- [examples/demo_shapes/main.cpp](../../examples/demo_shapes/main.cpp) - 形状绘制
- [examples/demo_sprite/main.cpp](../../examples/demo_sprite/main.cpp) - 精灵渲染
- [examples/demo_text/main.cpp](../../examples/demo_text/main.cpp) - 文字渲染
- [examples/demo_framebuffer/main.cpp](../../examples/demo_framebuffer/main.cpp) - 帧缓冲