Extra2D/docs/module_system.md

656 lines
14 KiB
Markdown
Raw 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 采用模块化架构设计(参考 Kiwano所有核心功能通过模块系统和服务系统管理。系统提供
- **统一的生命周期管理**:初始化、更新、渲染、关闭
- **优先级排序**:确保模块按正确顺序初始化
- **显式注册**:通过 `Application::use()` 注册模块
- **Context 模式**:使用上下文对象遍历模块链
- **依赖注入**:通过服务定位器解耦模块间依赖
## 架构图
```
┌─────────────────────────────────────────────────────────────┐
│ Application │
│ (协调模块和服务,通过服务定位器获取依赖) │
└─────────────────────────────────────────────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ Modules │ │ ServiceLocator │
│ (模块列表,按优先级排序) │ │ (服务定位器,管理运行时服务) │
└─────────────────────────────┘ └─────────────────────────────┘
│ │
┌─────┴─────┐ ┌───────┴───────┐
▼ ▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ Config │ │ Window │ │ Scene │ │ Timer │
│ Module │ │ Module │ │ Service │ │ Service │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
```
---
## 模块基类
### Module
所有模块只需继承 `Module` 基类,实现需要的生命周期方法:
```cpp
class Module {
public:
virtual ~Module() = default;
/**
* @brief 设置模块(初始化)
*/
virtual void setupModule() {}
/**
* @brief 销毁模块
*/
virtual void destroyModule() {}
/**
* @brief 更新时
*/
virtual void onUpdate(UpdateContext& ctx) { ctx.next(); }
/**
* @brief 渲染前
*/
virtual void beforeRender(RenderContext& ctx) { ctx.next(); }
/**
* @brief 渲染时
*/
virtual void onRender(RenderContext& ctx) { ctx.next(); }
/**
* @brief 渲染后
*/
virtual void afterRender(RenderContext& ctx) { ctx.next(); }
/**
* @brief 事件处理
*/
virtual void handleEvent(EventContext& ctx) { ctx.next(); }
/**
* @brief 获取模块名称
*/
virtual const char* getName() const = 0;
/**
* @brief 获取模块优先级
*/
virtual int getPriority() const { return 0; }
};
```
### 模块上下文
用于遍历模块链,支持链式调用:
```cpp
/**
* @brief 模块上下文基类
*/
class ModuleContext {
public:
void next(); // 遍历下一个模块
bool isDone() const; // 检查是否完成
};
/**
* @brief 更新上下文
*/
class UpdateContext : public ModuleContext {
public:
float getDeltaTime() const; // 获取帧间隔时间
};
/**
* @brief 渲染上下文
*/
class RenderContext : public ModuleContext {
public:
enum class Phase { Before, On, After };
Phase getPhase() const;
};
/**
* @brief 事件上下文
*/
class EventContext : public ModuleContext {
};
```
---
## 模块 vs 服务
| 特性 | 模块 (Module) | 服务 (Service) |
|-----|--------------|---------------|
| 用途 | 平台级初始化 | 运行时功能 |
| 生命周期 | Application 管理 | ServiceLocator 管理 |
| 注册方式 | `app.use(module)` | `locator.registerService()` |
| 可替换性 | 编译时确定 | 运行时可替换 |
| 示例 | Window, Render, Input | Scene, Timer, Event, Camera |
---
## 模块优先级
模块按优先级从小到大初始化,关闭时逆序执行:
| 模块 | 优先级 | 说明 |
|------|--------|------|
| LoggerModule | -1 | 最先初始化 |
| ConfigModule | 0 | 配置加载 |
| PlatformModule | 10 | 平台初始化 |
| WindowModule | 20 | 窗口创建 |
| InputModule | 30 | 输入系统 |
| RenderModule | 40 | 渲染系统 |
| ScriptModule | 500 | 脚本系统 |
| 用户模块 | 1000+ | 用户自定义 |
---
## 创建新模块
### 简单示例
```cpp
#include <extra2d/core/module.h>
class MyModule : public extra2d::Module {
public:
const char* getName() const override { return "MyModule"; }
int getPriority() const override { return 1000; }
void setupModule() override {
// 初始化资源
extra2d::E2D_LOG_INFO("MyModule initialized");
}
void destroyModule() override {
// 清理资源
extra2d::E2D_LOG_INFO("MyModule destroyed");
}
void onUpdate(extra2d::UpdateContext& ctx) override {
// 更新逻辑
ctx.next(); // 继续下一个模块
}
};
```
### 注册模块
```cpp
int main() {
auto& app = extra2d::Application::get();
MyModule myModule;
app.use(myModule); // 显式注册
app.init();
app.run();
return 0;
}
```
### 带配置的模块
```cpp
// my_module.h
#pragma once
#include <extra2d/core/module.h>
#include <string>
struct MyModuleConfig {
std::string greeting = "Hello!";
int repeatCount = 1;
};
class MyModule : public extra2d::Module {
public:
MyModule();
~MyModule() override;
const char* getName() const override { return "MyModule"; }
int getPriority() const override { return 1000; }
void setupModule() override;
void destroyModule() override;
void onUpdate(extra2d::UpdateContext& ctx) override;
void setConfig(const MyModuleConfig& config) { config_ = config; }
void sayHello() const;
private:
MyModuleConfig config_;
float time_ = 0.0f;
};
```
```cpp
// my_module.cpp
#include "my_module.h"
#include <extra2d/utils/logger.h>
MyModule::MyModule() : Module() {}
MyModule::~MyModule() {
if (isInitialized()) {
destroyModule();
}
}
void MyModule::setupModule() {
if (isInitialized()) return;
setInitialized(true);
E2D_LOG_INFO("MyModule initialized");
E2D_LOG_INFO(" Greeting: {}", config_.greeting);
E2D_LOG_INFO(" Repeat Count: {}", config_.repeatCount);
sayHello();
}
void MyModule::destroyModule() {
if (!isInitialized()) return;
E2D_LOG_INFO("MyModule shutdown");
setInitialized(false);
}
void MyModule::onUpdate(extra2d::UpdateContext& ctx) {
if (!isInitialized()) {
ctx.next();
return;
}
time_ += ctx.getDeltaTime();
if (time_ >= 5.0f) {
sayHello();
time_ = 0.0f;
}
ctx.next();
}
void MyModule::sayHello() const {
for (int i = 0; i < config_.repeatCount; ++i) {
E2D_LOG_INFO("[MyModule] {}", config_.greeting);
}
}
```
---
## 内置模块
### Config 模块
**职责**:管理 ConfigManager 和应用配置
**优先级**0
```cpp
extra2d::AppConfig config;
config.appName = "My Application";
config.appVersion = "1.0.0";
```
---
### Logger 模块
**职责**:日志系统初始化
**优先级**-1最先初始化
```cpp
extra2d::LoggerModule loggerModule;
loggerModule.setLogLevel(extra2d::LogLevel::Debug);
loggerModule.setFileOutput("app.log");
app.use(loggerModule);
```
---
### Platform 模块
**职责**:平台检测和平台特定初始化
**优先级**10
**支持平台**
- Windows
- Linux
- macOS
- Nintendo Switch
---
### Window 模块
**职责**:窗口创建和管理
**优先级**20
**后端**:统一使用 SDL2
```cpp
extra2d::WindowModule windowModule;
extra2d::WindowConfigData windowConfig;
windowConfig.title = "My App";
windowConfig.width = 1280;
windowConfig.height = 720;
windowConfig.vsync = true;
windowModule.setWindowConfig(windowConfig);
app.use(windowModule);
```
---
### Input 模块
**职责**:输入设备管理(键盘、鼠标、手柄)
**优先级**30
```cpp
extra2d::InputModule inputModule;
extra2d::InputConfigData inputConfig;
inputConfig.deadzone = 0.15f;
inputConfig.enableVibration = true;
inputModule.setInputConfig(inputConfig);
app.use(inputModule);
```
---
### Render 模块
**职责**:渲染器初始化和管理
**优先级**40
```cpp
extra2d::RenderModule renderModule;
extra2d::RenderModuleConfig renderConfig;
renderConfig.vsync = true;
renderConfig.multisamples = 4;
renderModule.setRenderConfig(renderConfig);
app.use(renderModule);
```
---
## 服务系统
### IService
服务接口基类:
```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);
};
```
### 内置服务
| 服务 | 用途 | 优先级 |
|-----|------|-------|
| EventService | 事件分发 | 100 |
| TimerService | 计时器 | 200 |
| SceneService | 场景管理 | 300 |
| CameraService | 相机系统 | 400 |
### 使用服务
```cpp
auto& app = extra2d::Application::get();
// 获取服务
auto sceneService = app.scenes();
auto timerService = app.timers();
auto eventService = app.events();
auto cameraService = app.camera();
// 使用场景服务
sceneService->pushScene(myScene);
// 使用计时器服务
timerService->addTimer(1.0f, []() {
E2D_LOG_INFO("Timer fired!");
});
// 使用事件服务
eventService->addListener(extra2d::EventType::KeyPress, [](extra2d::Event& e) {
auto& keyEvent = std::get<extra2d::KeyEvent>(e.data);
E2D_LOG_INFO("Key pressed: {}", keyEvent.keyCode);
});
```
---
## 输入事件系统
### 事件类型
```cpp
enum class EventType {
// 键盘
KeyPress,
KeyRelease,
KeyRepeat,
// 鼠标
MousePress,
MouseRelease,
MouseMove,
MouseScroll,
// 手柄
GamepadConnect,
GamepadDisconnect,
GamepadPress,
GamepadRelease,
// 触摸
TouchBegin,
TouchMove,
TouchEnd,
// 窗口
WindowResize,
WindowClose,
};
```
### 事件监听
```cpp
auto eventService = app.events();
// 监听键盘事件
eventService->addListener(EventType::KeyPress, [](Event& e) {
auto& key = std::get<KeyEvent>(e.data);
if (key.keyCode == static_cast<int>(Key::Escape)) {
Application::get().quit();
}
});
// 监听鼠标事件
eventService->addListener(EventType::MousePress, [](Event& e) {
auto& mouse = std::get<MouseEvent>(e.data);
E2D_LOG_INFO("Click at ({}, {})", 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);
Ptr<Node> getParent() const;
// 变换属性
void setPos(const Vec2& pos);
void setRotation(float degrees);
void setScale(const Vec2& scale);
// 世界变换
Vec2 toWorld(const Vec2& localPos) const;
glm::mat4 getWorldTransform() const;
// 生命周期回调
virtual void onEnter();
virtual void onExit();
virtual void onUpdate(float dt);
virtual void onRender(RenderBackend& renderer);
};
```
### ShapeNode 形状节点
```cpp
// 创建形状节点
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)
);
auto triangle = ShapeNode::createFilledTriangle(
Vec2(0, -40), Vec2(-35, 30), Vec2(35, 30),
Color(0.4f, 1.0f, 0.4f, 1.0f)
);
```
### 变换继承
```cpp
auto parent = makeShared<Node>();
parent->setPos(100, 100);
parent->setRotation(45);
auto child = makeShared<Node>();
child->setPos(50, 0); // 相对于父节点
parent->addChild(child);
// child 会随 parent 一起旋转
```
---
## 视口适配系统
### ViewportAdapter
```cpp
enum class ViewportMode {
AspectRatio, // 保持宽高比,可能有黑边
Stretch, // 拉伸填满整个窗口
Center, // 居中显示,不缩放
Custom // 自定义缩放和偏移
};
```
### 使用 CameraService 配置视口
```cpp
auto cameraService = app.camera();
if (cameraService) {
extra2d::ViewportConfig vpConfig;
vpConfig.logicWidth = 1280.0f;
vpConfig.logicHeight = 720.0f;
vpConfig.mode = extra2d::ViewportMode::AspectRatio;
cameraService->setViewportConfig(vpConfig);
cameraService->updateViewport(windowWidth, windowHeight);
}
```
---
## 示例
完整示例请参考:
- [examples/hello_module/](../../examples/hello_module/) - 自定义模块示例
- [examples/basic/main.cpp](../../examples/basic/main.cpp) - 基础示例
---
## 最佳实践
### 1. 模块优先级
```cpp
// 核心模块使用低优先级
class LoggerModule : public Module {
int getPriority() const override { return -1; }
};
// 用户模块使用高优先级
class MyModule : public Module {
int getPriority() const override { return 1000; }
};
```
### 2. 链式调用
```cpp
void onUpdate(UpdateContext& ctx) override {
// 执行更新逻辑
doSomething();
// 继续下一个模块
ctx.next();
}
```
### 3. 检查初始化状态
```cpp
void onUpdate(UpdateContext& ctx) override {
if (!isInitialized()) {
ctx.next();
return;
}
// 执行更新逻辑
ctx.next();
}
```