Extra2D/docs/API_Tutorial/03_Node_System.md

220 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Extra2D API 教程 - 03. 节点系统
## 节点基础
节点(Node)是游戏对象的基本单位,可以包含子节点,形成树形结构。
### 创建节点
```cpp
#include <extra2d/extra2d.h>
using namespace extra2d;
class MyNode : public Node {
public:
MyNode() {
// 设置位置
setPosition(Vec2(100.0f, 200.0f));
// 设置旋转(度)
setRotation(45.0f);
// 设置缩放
setScale(Vec2(2.0f, 2.0f));
// 设置锚点0-1范围默认0.5是中心)
setAnchor(0.5f, 0.5f);
// 设置可见性
setVisible(true);
}
// 每帧更新
void onUpdate(float dt) override {
Node::onUpdate(dt);
// 自定义更新逻辑
}
// 渲染
void onRender(RenderBackend &renderer) override {
Node::onRender(renderer);
// 自定义渲染
}
};
```
## 节点层级
### 添加子节点
```cpp
void onEnter() override {
Scene::onEnter();
// 创建子节点
auto child = makePtr<MyNode>();
// 添加到场景
addChild(child);
// 在指定位置添加
addChild(child, 0); // z-order = 0
}
```
### 移除子节点
```cpp
// 移除指定子节点
removeChild(child);
// 移除所有子节点
removeAllChildren();
// 通过名称移除
removeChildByName("myNode");
```
### 获取子节点
```cpp
// 获取子节点数量
size_t count = getChildren().size();
// 通过名称查找
auto node = getChildByName("myNode");
// 遍历子节点
for (auto &child : getChildren()) {
// 处理子节点
}
```
## 空间索引
### 启用空间索引
```cpp
class PhysicsNode : public Node {
public:
PhysicsNode() {
// 启用空间索引(用于碰撞检测)
setSpatialIndexed(true);
}
// 必须实现 getBoundingBox()
Rect getBoundingBox() const override {
Vec2 pos = getPosition();
return Rect(pos.x - 25.0f, pos.y - 25.0f, 50.0f, 50.0f);
}
};
```
### 边界框
```cpp
// 获取节点边界框
Rect bounds = node->getBoundingBox();
// 检查点是否在边界框内
if (bounds.contains(Vec2(x, y))) {
// 点在边界框内
}
// 检查两个边界框是否相交
if (bounds.intersects(otherBounds)) {
// 边界框相交
}
```
## 精灵节点
### 创建精灵
```cpp
// 加载纹理
auto texture = resources.loadTexture("assets/player.png");
// 创建精灵
auto sprite = Sprite::create(texture);
// 设置位置
sprite->setPosition(Vec2(640.0f, 360.0f));
// 设置锚点(中心)
sprite->setAnchor(0.5f, 0.5f);
// 添加到场景
addChild(sprite);
```
### 精灵动画
```cpp
// 创建动画
auto animation = Animation::create("walk", 0.1f);
animation->addFrame(resources.loadTexture("assets/walk1.png"));
animation->addFrame(resources.loadTexture("assets/walk2.png"));
animation->addFrame(resources.loadTexture("assets/walk3.png"));
// 播放动画
sprite->playAnimation(animation, true); // true = 循环播放
// 停止动画
sprite->stopAnimation();
```
## 完整示例
```cpp
class Player : public Node {
public:
Player() {
setSpatialIndexed(true);
// 加载精灵
auto &resources = Application::instance().resources();
auto texture = resources.loadTexture("assets/player.png");
sprite_ = Sprite::create(texture);
sprite_->setAnchor(0.5f, 0.5f);
addChild(sprite_);
}
void onUpdate(float dt) override {
Node::onUpdate(dt);
// 移动
Vec2 pos = getPosition();
pos = pos + velocity_ * dt;
setPosition(pos);
// 边界检查
auto &app = Application::instance();
float width = static_cast<float>(app.getConfig().width);
float height = static_cast<float>(app.getConfig().height);
if (pos.x < 0 || pos.x > width) {
velocity_.x = -velocity_.x;
}
if (pos.y < 0 || pos.y > height) {
velocity_.y = -velocity_.y;
}
}
Rect getBoundingBox() const override {
Vec2 pos = getPosition();
return Rect(pos.x - 25.0f, pos.y - 25.0f, 50.0f, 50.0f);
}
private:
Ptr<Sprite> sprite_;
Vec2 velocity_{100.0f, 100.0f};
};
```
## 下一步
- [04. 资源管理](04_Resource_Management.md)
- [05. 输入处理](05_Input_Handling.md)