Extra2D/docs/module_system.md

478 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 RenderBackend {
public:
virtual ~RenderBackend() = 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<RenderBackend> 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(RenderBackend& 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) - 帧缓冲