From d06c8735bda3c52a6d8bb3ba2400620f726b7a1b Mon Sep 17 00:00:00 2001 From: ChestnutYueyue <952134128@qq.com> Date: Sun, 15 Feb 2026 20:15:59 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E5=85=A5=E9=97=A8=E6=8C=87=E5=8D=97=E5=B9=B6=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E7=B4=A2=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加详细的快速入门指南文档,涵盖从安装到创建第一个游戏的完整流程 更新 README.md 中的文档索引部分以包含新指南链接 --- README.md | 1 + docs/quick_start.md | 610 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 611 insertions(+) create mode 100644 docs/quick_start.md diff --git a/README.md b/README.md index cb3156f..dee3cb6 100644 --- a/README.md +++ b/README.md @@ -371,6 +371,7 @@ xmake run demo_hello_module ## 文档 +- [快速入门指南](./docs/quick_start.md) - 从安装到创建第一个游戏 - [模块系统文档](./docs/module_system.md) - 模块系统、服务系统、场景图、视口适配 --- diff --git a/docs/quick_start.md b/docs/quick_start.md new file mode 100644 index 0000000..f6eaed2 --- /dev/null +++ b/docs/quick_start.md @@ -0,0 +1,610 @@ +# 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::KeyPressed, [](Event& e) { + auto& key = std::get(e.data); + + if (key.keyCode == static_cast(Key::Escape)) { + e.handled = true; + Application::get().quit(); + } + + if (key.keyCode == static_cast(Key::Space)) { + E2D_LOG_INFO("Space pressed!"); + } + }); + + // 鼠标事件 + addListener(EventType::MouseButtonPressed, [](Event& e) { + auto& mouse = std::get(e.data); + E2D_LOG_INFO("Click at ({}, {})", mouse.position.x, mouse.position.y); + }); + + // 手柄事件 + addListener(EventType::GamepadButtonPressed, [](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/` 目录