12 KiB
12 KiB
Extra2D 快速入门指南
本指南将帮助您快速上手 Extra2D 游戏引擎,从安装到创建您的第一个游戏。
目录
环境准备
安装 xmake
Windows (PowerShell):
Invoke-Expression (Invoke-WebRequest 'https://xmake.io/psget.text' -UseBasicParsing).Content
macOS:
brew install xmake
Linux:
sudo add-apt-repository ppa:xmake-io/xmake
sudo apt update
sudo apt install xmake
克隆项目
git clone https://github.com/ChestnutYueyue/extra2d.git
cd extra2d
构建项目
# 配置项目
xmake f -p mingw -a x86_64 -m release -y
# 构建
xmake build
# 运行示例
xmake run demo_basic
创建项目
最小示例
创建一个 main.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() 注册模块:
// 内置模块会自动注册,您也可以自定义
MyModule myModule;
app.use(myModule);
内置模块优先级:
| 模块 | 优先级 | 说明 |
|---|---|---|
| Logger | -1 | 日志系统 |
| Config | 0 | 配置管理 |
| Platform | 10 | 平台检测 |
| Window | 20 | 窗口管理 |
| Input | 30 | 输入系统 |
| Render | 40 | 渲染系统 |
服务系统
服务提供运行时功能,通过 Application 的便捷方法访问:
auto sceneService = app.scenes(); // 场景管理
auto timerService = app.timers(); // 计时器
auto eventService = app.events(); // 事件分发
auto cameraService = app.camera(); // 相机系统
场景图
场景图是一个树形结构,由 Scene 和 Node 组成:
Scene (根节点)
├── Node (父节点)
│ ├── Node (子节点)
│ └── ShapeNode (形状节点)
└── Sprite (精灵)
创建场景
基本场景
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);
// 每帧更新逻辑
}
};
使用场景
auto scene = MyScene::create();
app.enterScene(scene);
添加节点
创建形状节点
// 矩形
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);
节点变换
// 位置
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);
节点层级
// 添加子节点
parent->addChild(child);
// 移除子节点
parent->removeChild(child);
// 从父节点分离
child->detach();
// 查找子节点
Ptr<Node> found = parent->findChild("nodeName");
Ptr<Node> foundByTag = parent->findChildByTag(1);
// 清除所有子节点
parent->clearChildren();
变换继承
子节点会继承父节点的变换:
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)
处理输入
在场景中处理事件
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);
});
}
};
实时输入查询
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);
}
}
自定义模块
创建模块
#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(); // 继续下一个模块
}
};
注册模块
int main() {
Application& app = Application::get();
GameModule gameModule;
app.use(gameModule);
app.init();
app.run();
return 0;
}
完整示例
下面是一个完整的游戏示例,展示如何创建一个简单的交互式场景:
#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;
}
下一步
常见问题
Q: 如何设置窗口大小?
WindowModule windowModule;
WindowConfigData windowConfig;
windowConfig.width = 1920;
windowConfig.height = 1080;
windowConfig.title = "My Game";
windowModule.setWindowConfig(windowConfig);
app.use(windowModule);
Q: 如何启用垂直同步?
RenderModule renderModule;
RenderModuleConfig renderConfig;
renderConfig.vsync = true;
renderModule.setRenderConfig(renderConfig);
app.use(renderModule);
Q: 如何处理窗口大小变化?
// 在场景中
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: 如何使用计时器?
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/目录