# 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 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([](auto& cfg) { cfg.title = "My Game"; cfg.w = 1920; cfg.h = 1080; cfg.backend = "glfw"; // 使用 GLFW 后端 }); // 配置 Render 模块 app.use([](auto& cfg) { cfg.backend = BackendType::OpenGL; cfg.vsync = true; cfg.targetFPS = 60; }); // 配置 Input 模块 app.use([](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(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 createTexture(int width, int height, const uint8_t *pixels, int channels) = 0; virtual Ptr 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 ¢er, float radius, const Color &color, int segments = 32, float width = 1.0f) = 0; virtual void fillCircle(const Vec2 ¢er, float radius, const Color &color, int segments = 32) = 0; // 文字渲染 virtual Ptr 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 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(e.data); E2D_LOG_INFO("Key: {}, mods: {}", key.keyCode, key.mods); }); // 监听鼠标事件 eventService->addListener(EventType::MouseButtonPressed, [](Event& e) { auto& mouse = std::get(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 { public: // 层级管理 void addChild(Ptr child); void removeChild(Ptr child); void detach(); void clearChildren(); Ptr getParent() const; const std::vector>& 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) - 帧缓冲