# Extra2D 快速入门指南 本指南将帮助您快速上手 Extra2D 游戏引擎,从安装到创建您的第一个游戏。 --- ## 目录 1. [环境准备](#环境准备) 2. [创建项目](#创建项目) 3. [基础概念](#基础概念) 4. [创建场景](#创建场景) 5. [添加节点](#添加节点) 6. [处理输入](#处理输入) 7. [自定义模块](#自定义模块) 8. [完整示例](#完整示例) --- ## 环境准备 ### 安装 xmake **Windows (PowerShell):** ```powershell Invoke-Expression (Invoke-WebRequest 'https://xmake.io/psget.text' -UseBasicParsing).Content ``` **macOS:** ```bash brew install xmake ``` **Linux:** ```bash sudo add-apt-repository ppa:xmake-io/xmake sudo apt update sudo apt install xmake ``` ### 克隆项目 ```bash git clone https://github.com/ChestnutYueyue/extra2d.git cd extra2d ``` ### 构建项目 ```bash # 配置项目 xmake f -p mingw -a x86_64 -m release -y # 构建 xmake build # 运行示例 xmake run demo_basic ``` --- ## 创建项目 ### 最小示例 创建一个 `main.cpp` 文件: ```cpp #include using namespace extra2d; int main() { // 1. 配置应用 AppConfig config; config.appName = "My First Game"; config.appVersion = "1.0.0"; // 2. 获取应用实例 Application& app = Application::get(); // 3. 初始化 if (!app.init(config)) { return -1; } // 4. 创建场景 auto scene = Scene::create(); scene->setBackgroundColor(Color(0.1f, 0.1f, 0.2f, 1.0f)); // 5. 进入场景 app.enterScene(scene); // 6. 运行游戏循环 app.run(); // 7. 清理 app.shutdown(); return 0; } ``` --- ## 基础概念 ### 模块系统 Extra2D 使用模块化架构,通过 `Application::use()` 注册模块: ```cpp // 内置模块会自动注册,您也可以自定义 MyModule myModule; app.use(myModule); ``` **内置模块优先级:** | 模块 | 优先级 | 说明 | |------|--------|------| | Logger | -1 | 日志系统 | | Config | 0 | 配置管理 | | Platform | 10 | 平台检测 | | Window | 20 | 窗口管理 | | Input | 30 | 输入系统 | | Render | 40 | 渲染系统 | ### 服务系统 服务提供运行时功能,通过 `Application` 的便捷方法访问: ```cpp auto sceneService = app.scenes(); // 场景管理 auto timerService = app.timers(); // 计时器 auto eventService = app.events(); // 事件分发 auto cameraService = app.camera(); // 相机系统 ``` ### 场景图 场景图是一个树形结构,由 `Scene` 和 `Node` 组成: ``` Scene (根节点) ├── Node (父节点) │ ├── Node (子节点) │ └── ShapeNode (形状节点) └── Sprite (精灵) ``` --- ## 创建场景 ### 基本场景 ```cpp class MyScene : public Scene { public: static Ptr create() { return makeShared(); } void onEnter() override { Scene::onEnter(); // 设置背景颜色 setBackgroundColor(Color(0.1f, 0.1f, 0.2f, 1.0f)); // 在这里添加节点和设置游戏逻辑 } void onUpdate(float dt) override { Scene::onUpdate(dt); // 每帧更新逻辑 } }; ``` ### 使用场景 ```cpp auto scene = MyScene::create(); app.enterScene(scene); ``` --- ## 添加节点 ### 创建形状节点 ```cpp // 矩形 auto rect = ShapeNode::createFilledRect( Rect(0, 0, 100, 100), // 位置和大小 Color(1.0f, 0.4f, 0.4f, 1.0f) // 颜色 ); scene->addChild(rect); // 圆形 auto circle = ShapeNode::createFilledCircle( Vec2(50, 50), // 圆心 30, // 半径 Color(0.4f, 0.4f, 1.0f, 1.0f) // 颜色 ); scene->addChild(circle); // 三角形 auto triangle = ShapeNode::createFilledTriangle( Vec2(50, 0), // 顶点1 Vec2(0, 100), // 顶点2 Vec2(100, 100), // 顶点3 Color(0.4f, 1.0f, 0.4f, 1.0f) // 颜色 ); scene->addChild(triangle); // 线段 auto line = ShapeNode::createLine( Vec2(0, 0), // 起点 Vec2(100, 100), // 终点 Color(1.0f, 1.0f, 1.0f, 1.0f), // 颜色 2.0f // 线宽 ); scene->addChild(line); ``` ### 节点变换 ```cpp // 位置 node->setPos(100, 200); Vec2 pos = node->getPosition(); // 旋转(角度) node->setRotation(45); float rotation = node->getRotation(); // 缩放 node->setScale(2.0f); // 统一缩放 node->setScale(2.0f, 1.5f); // 分别设置 X/Y Vec2 scale = node->getScale(); // 锚点(变换中心) node->setAnchor(0.5f, 0.5f); // 中心(默认) // 透明度 node->setOpacity(0.5f); // 0.0 - 1.0 // 可见性 node->setVisible(false); // Z 序(渲染顺序) node->setZOrder(10); ``` ### 节点层级 ```cpp // 添加子节点 parent->addChild(child); // 移除子节点 parent->removeChild(child); // 从父节点分离 child->detach(); // 查找子节点 Ptr found = parent->findChild("nodeName"); Ptr foundByTag = parent->findChildByTag(1); // 清除所有子节点 parent->clearChildren(); ``` ### 变换继承 子节点会继承父节点的变换: ```cpp auto parent = makeShared(); parent->setPos(400, 300); parent->setRotation(30); // 旋转 30 度 auto child = ShapeNode::createFilledRect( Rect(-25, -25, 50, 50), Color(1.0f, 0.0f, 0.0f, 1.0f) ); child->setPos(100, 0); // 相对于父节点 parent->addChild(child); scene->addChild(parent); // child 会随 parent 一起旋转 // child 的世界位置约为 (486.6, 350) ``` --- ## 处理输入 ### 在场景中处理事件 ```cpp class MyScene : public Scene { public: void onEnter() override { Scene::onEnter(); // 键盘事件 addListener(EventType::KeyPress, [](Event& e) { auto& key = std::get(e.data); if (key.scancode == static_cast(Key::Escape)) { e.handled = true; Application::get().quit(); } if (key.scancode == static_cast(Key::Space)) { E2D_LOG_INFO("Space pressed!"); } }); // 鼠标事件 addListener(EventType::MousePress, [](Event& e) { auto& mouse = std::get(e.data); E2D_LOG_INFO("Click at ({}, {})", mouse.position.x, mouse.position.y); }); // 手柄事件 addListener(EventType::GamepadPress, [](Event& e) { auto& gamepad = std::get(e.data); E2D_LOG_INFO("Gamepad button: {}", gamepad.button); }); } }; ``` ### 实时输入查询 ```cpp void onUpdate(float dt) override { Scene::onUpdate(dt); auto& input = Application::get().input(); // 键盘 if (input.down(Key::W)) { // W 键被按住 } if (input.pressed(Key::Space)) { // 空格键刚按下 } if (input.released(Key::Space)) { // 空格键刚释放 } // 鼠标 Vec2 mousePos = input.mouse(); if (input.down(Mouse::Left)) { // 左键被按住 } // 手柄 if (input.gamepad()) { Vec2 leftStick = input.leftStick(); Vec2 rightStick = input.rightStick(); if (input.down(Gamepad::A)) { // A 键被按住 } // 振动 input.vibrate(0.5f, 0.5f); } } ``` --- ## 自定义模块 ### 创建模块 ```cpp #include class GameModule : public extra2d::Module { public: const char* getName() const override { return "GameModule"; } int getPriority() const override { return 1000; } void setupModule() override { // 初始化游戏资源 E2D_LOG_INFO("Game module initialized"); } void destroyModule() override { // 清理资源 E2D_LOG_INFO("Game module destroyed"); } void onUpdate(extra2d::UpdateContext& ctx) override { // 更新游戏逻辑 float dt = ctx.getDeltaTime(); // ... ctx.next(); // 继续下一个模块 } }; ``` ### 注册模块 ```cpp int main() { Application& app = Application::get(); GameModule gameModule; app.use(gameModule); app.init(); app.run(); return 0; } ``` --- ## 完整示例 下面是一个完整的游戏示例,展示如何创建一个简单的交互式场景: ```cpp #include using namespace extra2d; // 自定义场景 class GameScene : public Scene { public: static Ptr create() { return makeShared(); } void onEnter() override { Scene::onEnter(); // 设置背景 setBackgroundColor(Color(0.1f, 0.1f, 0.15f, 1.0f)); // 创建玩家 player_ = ShapeNode::createFilledRect( Rect(-25, -25, 50, 50), Color(1.0f, 0.4f, 0.4f, 1.0f) ); player_->setPos(getWidth() / 2, getHeight() / 2); addChild(player_); // 键盘控制 addListener(EventType::KeyPressed, [this](Event& e) { auto& key = std::get(e.data); if (key.keyCode == static_cast(Key::Escape)) { e.handled = true; Application::get().quit(); } }); E2D_LOG_INFO("Game scene entered"); } void onUpdate(float dt) override { Scene::onUpdate(dt); // 移动玩家 auto& input = Application::get().input(); float speed = 200.0f * dt; Vec2 pos = player_->getPosition(); if (input.down(Key::W) || input.down(Key::Up)) pos.y -= speed; if (input.down(Key::S) || input.down(Key::Down)) pos.y += speed; if (input.down(Key::A) || input.down(Key::Left)) pos.x -= speed; if (input.down(Key::D) || input.down(Key::Right)) pos.x += speed; // 边界检测 pos.x = std::clamp(pos.x, 25.0f, getWidth() - 25.0f); pos.y = std::clamp(pos.y, 25.0f, getHeight() - 25.0f); player_->setPos(pos); // 旋转 rotation_ += 90.0f * dt; player_->setRotation(rotation_); } private: Ptr player_; float rotation_ = 0.0f; }; int main() { // 配置 AppConfig config; config.appName = "My Game"; config.appVersion = "1.0.0"; // 初始化 Application& app = Application::get(); if (!app.init(config)) { return -1; } // 创建并进入场景 auto scene = GameScene::create(); app.enterScene(scene); // 运行 app.run(); // 清理 app.shutdown(); return 0; } ``` --- ## 下一步 - 查看 [模块系统文档](./module_system.md) 了解更多高级功能 - 查看 `examples/` 目录中的示例代码 - 阅读 [API 参考](./api_reference.md)(待完善) --- ## 常见问题 ### Q: 如何设置窗口大小? ```cpp WindowModule windowModule; WindowConfigData windowConfig; windowConfig.width = 1920; windowConfig.height = 1080; windowConfig.title = "My Game"; windowModule.setWindowConfig(windowConfig); app.use(windowModule); ``` ### Q: 如何启用垂直同步? ```cpp RenderModule renderModule; RenderModuleConfig renderConfig; renderConfig.vsync = true; renderModule.setRenderConfig(renderConfig); app.use(renderModule); ``` ### Q: 如何处理窗口大小变化? ```cpp // 在场景中 void onEnter() override { Scene::onEnter(); addListener(EventType::WindowResize, [this](Event& e) { auto& resize = std::get(e.data); E2D_LOG_INFO("Window resized: {}x{}", resize.width, resize.height); // 更新视口 setViewportSize(resize.width, resize.height); }); } ``` ### Q: 如何使用计时器? ```cpp void onEnter() override { Scene::onEnter(); auto timerService = Application::get().timers(); // 延迟执行 timerService->addTimer(2.0f, []() { E2D_LOG_INFO("2 seconds passed!"); }); // 重复执行 timerService->addRepeatingTimer(1.0f, [](int count) { E2D_LOG_INFO("Count: {}", count); return true; // 返回 false 停止 }); } ``` --- ## 获取帮助 - GitHub Issues: https://github.com/ChestnutYueyue/extra2d/issues - 查看示例代码: `examples/` 目录