Extra2D/docs/module_system.md

17 KiB
Raw Permalink Blame 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 基类:

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 输入设备管理

模块配置

每个模块有自己的配置结构:

// 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;
};

使用模块

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();

构建时选择后端

# 选择窗口后端
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

服务系统

服务接口基类

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)

使用服务

// 获取服务
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

渲染后端接口

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      │                   │
│  └─────────────────┘  └─────────────────┘                   │
└─────────────────────────────────────────────────────────────┘

输入事件系统

事件类型

enum class EventType {
    // 键盘
    KeyPressed,
    KeyReleased,
    KeyRepeat,
    
    // 鼠标
    MouseButtonPressed,
    MouseButtonReleased,
    MouseMoved,
    MouseScrolled,
    
    // 手柄
    GamepadConnected,
    GamepadDisconnected,
    GamepadButtonPressed,
    GamepadButtonReleased,
    
    // 触摸
    TouchBegan,
    TouchMoved,
    TouchEnded,
    
    // 窗口
    WindowResize,
    WindowClose,
};

事件监听

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 基类

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);
};

使用场景

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);

视口适配系统

视口适配模式

enum class ViewportMode {
    AspectRatio,  // 保持宽高比,可能有黑边
    Stretch,      // 拉伸填满整个窗口
    Center,       // 居中显示,不缩放
    Custom        // 自定义缩放和偏移
};

配置视口

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

示例

完整示例请参考: