docs: 添加快速入门指南并更新文档索引
添加详细的快速入门指南文档,涵盖从安装到创建第一个游戏的完整流程 更新 README.md 中的文档索引部分以包含新指南链接
This commit is contained in:
parent
f8a7fab2e7
commit
d06c8735bd
|
|
@ -371,6 +371,7 @@ xmake run demo_hello_module
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
- [快速入门指南](./docs/quick_start.md) - 从安装到创建第一个游戏
|
||||||
- [模块系统文档](./docs/module_system.md) - 模块系统、服务系统、场景图、视口适配
|
- [模块系统文档](./docs/module_system.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 <extra2d/extra2d.h>
|
||||||
|
|
||||||
|
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<MyScene> create() {
|
||||||
|
return makeShared<MyScene>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Node> found = parent->findChild("nodeName");
|
||||||
|
Ptr<Node> foundByTag = parent->findChildByTag(1);
|
||||||
|
|
||||||
|
// 清除所有子节点
|
||||||
|
parent->clearChildren();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 变换继承
|
||||||
|
|
||||||
|
子节点会继承父节点的变换:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto parent = makeShared<Node>();
|
||||||
|
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<KeyEvent>(e.data);
|
||||||
|
|
||||||
|
if (key.keyCode == static_cast<int>(Key::Escape)) {
|
||||||
|
e.handled = true;
|
||||||
|
Application::get().quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.keyCode == static_cast<int>(Key::Space)) {
|
||||||
|
E2D_LOG_INFO("Space pressed!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标事件
|
||||||
|
addListener(EventType::MouseButtonPressed, [](Event& e) {
|
||||||
|
auto& mouse = std::get<MouseButtonEvent>(e.data);
|
||||||
|
E2D_LOG_INFO("Click at ({}, {})", mouse.position.x, mouse.position.y);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 手柄事件
|
||||||
|
addListener(EventType::GamepadButtonPressed, [](Event& e) {
|
||||||
|
auto& gamepad = std::get<GamepadButtonEvent>(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 <extra2d/core/module.h>
|
||||||
|
|
||||||
|
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 <extra2d/extra2d.h>
|
||||||
|
|
||||||
|
using namespace extra2d;
|
||||||
|
|
||||||
|
// 自定义场景
|
||||||
|
class GameScene : public Scene {
|
||||||
|
public:
|
||||||
|
static Ptr<GameScene> create() {
|
||||||
|
return makeShared<GameScene>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<KeyEvent>(e.data);
|
||||||
|
|
||||||
|
if (key.keyCode == static_cast<int>(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<ShapeNode> 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<WindowResizeEvent>(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/` 目录
|
||||||
Loading…
Reference in New Issue