# 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 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 #include 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 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::KeyPressed, [](extra2d::Event& e) { auto& keyEvent = std::get(e.data); E2D_LOG_INFO("Key pressed: {}", keyEvent.keyCode); }); ``` --- ## 输入事件系统 ### 事件类型 ```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); if (key.keyCode == static_cast(Key::Escape)) { Application::get().quit(); } }); // 监听鼠标事件 eventService->addListener(EventType::MouseButtonPressed, [](Event& e) { auto& mouse = std::get(e.data); E2D_LOG_INFO("Click at ({}, {})", 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); Ptr 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(); parent->setPos(100, 100); parent->setRotation(45); auto child = makeShared(); 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(); } ```