615 lines
14 KiB
C++
615 lines
14 KiB
C++
#pragma once
|
||
|
||
#include <extra2d/core/color.h>
|
||
#include <extra2d/core/math_types.h>
|
||
#include <extra2d/core/types.h>
|
||
#include <extra2d/event/event_dispatcher.h>
|
||
#include <extra2d/render/core/render_backend.h>
|
||
#include <extra2d/scene/component.h>
|
||
#include <extra2d/scene/components/transform_component.h>
|
||
#include <memory>
|
||
#include <string>
|
||
#include <unordered_map>
|
||
#include <vector>
|
||
|
||
namespace extra2d {
|
||
|
||
class Scene;
|
||
class RenderBackend;
|
||
struct RenderCommand;
|
||
class RenderQueue;
|
||
|
||
/**
|
||
* @brief 节点基类 - 场景图的基础
|
||
*
|
||
* 节点是场景图的基本单元,支持层级管理、变换继承和组件系统
|
||
*/
|
||
class Node : public std::enable_shared_from_this<Node> {
|
||
public:
|
||
/**
|
||
* @brief 创建节点
|
||
* @param name 节点名称
|
||
* @return 创建的节点智能指针
|
||
*/
|
||
static Ptr<Node> create(const std::string &name = "");
|
||
|
||
Node();
|
||
virtual ~Node();
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 层级管理
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 添加子节点
|
||
* @param child 要添加的子节点智能指针
|
||
*/
|
||
void addChild(Ptr<Node> child);
|
||
|
||
/**
|
||
* @brief 批量添加子节点
|
||
* @param children 子节点列表
|
||
*/
|
||
void addChildren(std::vector<Ptr<Node>> &&children);
|
||
|
||
/**
|
||
* @brief 移除子节点
|
||
* @param child 要移除的子节点智能指针
|
||
*/
|
||
void removeChild(Ptr<Node> child);
|
||
|
||
/**
|
||
* @brief 通过名称移除子节点
|
||
* @param name 子节点的名称
|
||
*/
|
||
void removeChildByName(const std::string &name);
|
||
|
||
/**
|
||
* @brief 从父节点分离
|
||
*/
|
||
void detach();
|
||
|
||
/**
|
||
* @brief 清除所有子节点
|
||
*/
|
||
void clearChildren();
|
||
|
||
/**
|
||
* @brief 获取父节点
|
||
* @return 父节点智能指针
|
||
*/
|
||
Ptr<Node> getParent() const { return parent_.lock(); }
|
||
|
||
/**
|
||
* @brief 获取所有子节点
|
||
* @return 子节点列表的常量引用
|
||
*/
|
||
const std::vector<Ptr<Node>> &getChildren() const { return children_; }
|
||
|
||
/**
|
||
* @brief 通过名称查找子节点
|
||
* @param name 子节点的名称
|
||
* @return 找到的子节点智能指针,未找到返回nullptr
|
||
*/
|
||
Ptr<Node> findChild(const std::string &name) const;
|
||
|
||
/**
|
||
* @brief 通过标签查找子节点
|
||
* @param tag 子节点的标签值
|
||
* @return 找到的子节点智能指针,未找到返回nullptr
|
||
*/
|
||
Ptr<Node> findChildByTag(int tag) const;
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 组件系统
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 添加组件
|
||
* @tparam T 组件类型
|
||
* @tparam Args 构造函数参数类型
|
||
* @param args 构造函数参数
|
||
* @return 创建的组件指针
|
||
*/
|
||
template <typename T, typename... Args> T *addComponent(Args &&...args) {
|
||
static_assert(std::is_base_of<Component, T>::value,
|
||
"T must derive from Component");
|
||
|
||
uint32_t typeId = T::getStaticTypeId();
|
||
|
||
// 检查是否已存在相同类型的组件
|
||
auto it = components_.find(typeId);
|
||
if (it != components_.end()) {
|
||
return static_cast<T *>(it->second.get());
|
||
}
|
||
|
||
// 创建新组件
|
||
auto component = makePtr<T>(std::forward<Args>(args)...);
|
||
component->setNode(this);
|
||
component->init();
|
||
component->setInitialized(true);
|
||
|
||
components_[typeId] = component;
|
||
|
||
return component.get();
|
||
}
|
||
|
||
/**
|
||
* @brief 获取组件
|
||
* @tparam T 组件类型
|
||
* @return 组件指针,不存在返回nullptr
|
||
*/
|
||
template <typename T> T *getComponent() const {
|
||
static_assert(std::is_base_of<Component, T>::value,
|
||
"T must derive from Component");
|
||
|
||
uint32_t typeId = T::getStaticTypeId();
|
||
auto it = components_.find(typeId);
|
||
if (it != components_.end()) {
|
||
return static_cast<T *>(it->second.get());
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
/**
|
||
* @brief 检查是否有组件
|
||
* @tparam T 组件类型
|
||
* @return 如果存在返回true
|
||
*/
|
||
template <typename T> bool hasComponent() const {
|
||
return getComponent<T>() != nullptr;
|
||
}
|
||
|
||
/**
|
||
* @brief 移除组件
|
||
* @tparam T 组件类型
|
||
*/
|
||
template <typename T> void removeComponent() {
|
||
static_assert(std::is_base_of<Component, T>::value,
|
||
"T must derive from Component");
|
||
|
||
uint32_t typeId = T::getStaticTypeId();
|
||
auto it = components_.find(typeId);
|
||
if (it != components_.end()) {
|
||
it->second->destroy();
|
||
it->second->setInitialized(false);
|
||
it->second->setNode(nullptr);
|
||
components_.erase(it);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取变换组件
|
||
* @return 变换组件指针
|
||
*/
|
||
TransformComponent *getTransform() const { return transform_; }
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 变换属性(便捷方法,委托给TransformComponent)
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 设置节点位置
|
||
* @param pos 新的位置坐标
|
||
*/
|
||
void setPos(const Vec2 &pos);
|
||
|
||
/**
|
||
* @brief 设置节点位置
|
||
* @param x X坐标
|
||
* @param y Y坐标
|
||
*/
|
||
void setPos(float x, float y);
|
||
|
||
/**
|
||
* @brief 获取节点位置
|
||
* @return 位置坐标
|
||
*/
|
||
Vec2 getPosition() const;
|
||
|
||
/**
|
||
* @brief 设置节点旋转角度
|
||
* @param degrees 旋转角度(度数)
|
||
*/
|
||
void setRotation(float degrees);
|
||
|
||
/**
|
||
* @brief 获取节点旋转角度
|
||
* @return 旋转角度(度数)
|
||
*/
|
||
float getRotation() const;
|
||
|
||
/**
|
||
* @brief 设置节点缩放
|
||
* @param scale 缩放向量
|
||
*/
|
||
void setScale(const Vec2 &scale);
|
||
|
||
/**
|
||
* @brief 设置节点统一缩放
|
||
* @param scale 统一缩放值
|
||
*/
|
||
void setScale(float scale);
|
||
|
||
/**
|
||
* @brief 设置节点缩放
|
||
* @param x X轴缩放值
|
||
* @param y Y轴缩放值
|
||
*/
|
||
void setScale(float x, float y);
|
||
|
||
/**
|
||
* @brief 获取节点缩放
|
||
* @return 缩放向量
|
||
*/
|
||
Vec2 getScale() const;
|
||
|
||
/**
|
||
* @brief 设置节点锚点
|
||
* @param anchor 锚点位置(0-1范围)
|
||
*/
|
||
void setAnchor(const Vec2 &anchor);
|
||
|
||
/**
|
||
* @brief 设置节点锚点
|
||
* @param x 锚点X坐标(0-1范围)
|
||
* @param y 锚点Y坐标(0-1范围)
|
||
*/
|
||
void setAnchor(float x, float y);
|
||
|
||
/**
|
||
* @brief 获取节点锚点
|
||
* @return 锚点位置
|
||
*/
|
||
Vec2 getAnchor() const;
|
||
|
||
/**
|
||
* @brief 设置节点斜切
|
||
* @param skew 斜切角度向量
|
||
*/
|
||
void setSkew(const Vec2 &skew);
|
||
|
||
/**
|
||
* @brief 设置节点斜切
|
||
* @param x X轴斜切角度
|
||
* @param y Y轴斜切角度
|
||
*/
|
||
void setSkew(float x, float y);
|
||
|
||
/**
|
||
* @brief 获取节点斜切
|
||
* @return 斜切角度向量
|
||
*/
|
||
Vec2 getSkew() const;
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 世界变换
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 将本地坐标转换为世界坐标
|
||
* @param localPos 本地坐标位置
|
||
* @return 世界坐标位置
|
||
*/
|
||
Vec2 toWorld(const Vec2 &localPos) const;
|
||
|
||
/**
|
||
* @brief 将世界坐标转换为本地坐标
|
||
* @param worldPos 世界坐标位置
|
||
* @return 本地坐标位置
|
||
*/
|
||
Vec2 toLocal(const Vec2 &worldPos) const;
|
||
|
||
/**
|
||
* @brief 获取本地变换矩阵
|
||
* @return 本地变换矩阵
|
||
*/
|
||
glm::mat4 getLocalTransform() const;
|
||
|
||
/**
|
||
* @brief 获取世界变换矩阵
|
||
* @return 世界变换矩阵
|
||
*/
|
||
glm::mat4 getWorldTransform() const;
|
||
|
||
/**
|
||
* @brief 标记变换矩阵为脏状态,并传播到所有子节点
|
||
*/
|
||
void markTransformDirty();
|
||
|
||
/**
|
||
* @brief 批量更新变换矩阵
|
||
*/
|
||
void batchTransforms();
|
||
|
||
/**
|
||
* @brief 获取变换脏标记状态
|
||
*/
|
||
bool isTransformDirty() const;
|
||
bool isWorldTransformDirty() const;
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 可见性和外观
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 设置透明度
|
||
* @param opacity 透明度值(0.0-1.0范围)
|
||
*/
|
||
void setOpacity(float opacity);
|
||
|
||
/**
|
||
* @brief 获取透明度
|
||
* @return 透明度值
|
||
*/
|
||
float getOpacity() const { return opacity_; }
|
||
|
||
/**
|
||
* @brief 设置可见性
|
||
* @param visible 是否可见
|
||
*/
|
||
void setVisible(bool visible);
|
||
|
||
/**
|
||
* @brief 获取可见性
|
||
* @return 是否可见
|
||
*/
|
||
bool isVisible() const { return visible_; }
|
||
|
||
/**
|
||
* @brief 设置颜色
|
||
* @param color RGB颜色
|
||
*/
|
||
void setColor(const Color3B &color);
|
||
|
||
/**
|
||
* @brief 获取颜色
|
||
* @return RGB颜色
|
||
*/
|
||
Color3B getColor() const { return color_; }
|
||
|
||
/**
|
||
* @brief 设置X轴翻转
|
||
*/
|
||
void setFlipX(bool flipX);
|
||
|
||
/**
|
||
* @brief 获取X轴翻转状态
|
||
*/
|
||
bool isFlipX() const { return flipX_; }
|
||
|
||
/**
|
||
* @brief 设置Y轴翻转
|
||
*/
|
||
void setFlipY(bool flipY);
|
||
|
||
/**
|
||
* @brief 获取Y轴翻转状态
|
||
*/
|
||
bool isFlipY() const { return flipY_; }
|
||
|
||
/**
|
||
* @brief 设置Z序
|
||
* @param zOrder 渲染层级顺序
|
||
*/
|
||
void setZOrder(int zOrder);
|
||
|
||
/**
|
||
* @brief 获取Z序
|
||
* @return 渲染层级顺序
|
||
*/
|
||
int getZOrder() const { return zOrder_; }
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 名称和标签
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 设置名称
|
||
* @param name 节点名称
|
||
*/
|
||
void setName(const std::string &name) { name_ = name; }
|
||
|
||
/**
|
||
* @brief 获取名称
|
||
* @return 节点名称
|
||
*/
|
||
const std::string &getName() const { return name_; }
|
||
|
||
/**
|
||
* @brief 设置标签
|
||
* @param tag 标签值
|
||
*/
|
||
void setTag(int tag) { tag_ = tag; }
|
||
|
||
/**
|
||
* @brief 获取标签
|
||
* @return 标签值
|
||
*/
|
||
int getTag() const { return tag_; }
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 生命周期回调
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 节点进入时的回调
|
||
*/
|
||
virtual void onEnter();
|
||
|
||
/**
|
||
* @brief 节点退出时的回调
|
||
*/
|
||
virtual void onExit();
|
||
|
||
/**
|
||
* @brief 更新回调
|
||
* @param dt 帧间隔时间(秒)
|
||
*/
|
||
virtual void onUpdate(float dt);
|
||
|
||
/**
|
||
* @brief 渲染回调
|
||
* @param renderer 渲染后端引用
|
||
*/
|
||
virtual void onRender(RenderBackend &renderer);
|
||
|
||
/**
|
||
* @brief 附加到场景时的回调
|
||
* @param scene 所属场景指针
|
||
*/
|
||
virtual void onAttachToScene(Scene *scene);
|
||
|
||
/**
|
||
* @brief 从场景分离时的回调
|
||
*/
|
||
virtual void onDetachFromScene();
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 边界框
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 获取节点边界矩形
|
||
* @return 节点的边界矩形
|
||
*/
|
||
virtual Rect getBounds() const;
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 事件系统
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 获取事件分发器
|
||
* @return 事件分发器引用
|
||
*/
|
||
EventDispatcher &getEventDispatcher() { return eventDispatcher_; }
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 内部方法
|
||
// -------------------------------------------------------------------------
|
||
|
||
/**
|
||
* @brief 更新节点
|
||
* @param dt 帧间隔时间(秒)
|
||
*/
|
||
void update(float dt);
|
||
|
||
/**
|
||
* @brief 渲染节点
|
||
* @param renderer 渲染后端引用
|
||
*/
|
||
void render(RenderBackend &renderer);
|
||
|
||
/**
|
||
* @brief 对子节点排序
|
||
*/
|
||
void sortChildren();
|
||
|
||
/**
|
||
* @brief 检查是否正在运行
|
||
* @return 是否正在运行
|
||
*/
|
||
bool isRunning() const { return running_; }
|
||
|
||
/**
|
||
* @brief 获取所属场景
|
||
* @return 所属场景指针
|
||
*/
|
||
Scene *getScene() const { return scene_; }
|
||
|
||
/**
|
||
* @brief 收集渲染命令
|
||
* @param commands 渲染命令输出向量
|
||
* @param parentZOrder 父节点的Z序
|
||
*/
|
||
virtual void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||
int parentZOrder = 0);
|
||
|
||
/**
|
||
* @brief 收集渲染命令到队列
|
||
* @param queue 渲染队列引用
|
||
*/
|
||
virtual void collectRenderCommandsToQueue(RenderQueue &queue);
|
||
|
||
protected:
|
||
/**
|
||
* @brief 绘制回调(子类重写)
|
||
* @param renderer 渲染后端引用
|
||
*/
|
||
virtual void onDraw(RenderBackend &renderer) {}
|
||
|
||
/**
|
||
* @brief 节点更新回调(子类重写)
|
||
* @param dt 帧间隔时间(秒)
|
||
*/
|
||
virtual void onUpdateNode(float dt) {}
|
||
|
||
/**
|
||
* @brief 生成渲染命令(子类重写)
|
||
* @param commands 渲染命令输出向量
|
||
* @param zOrder Z序
|
||
*/
|
||
virtual void generateRenderCommand(std::vector<RenderCommand> &commands,
|
||
int zOrder) {}
|
||
|
||
/**
|
||
* @brief 生成渲染命令到队列(子类重写)
|
||
* @param queue 渲染队列引用
|
||
*/
|
||
virtual void generateRenderCommandToQueue(RenderQueue &queue) { (void)queue; }
|
||
|
||
private:
|
||
// ==========================================================================
|
||
// 成员变量按类型大小降序排列,减少内存对齐填充
|
||
// ==========================================================================
|
||
|
||
// 1. 大块内存(64字节)
|
||
mutable glm::mat4 localTransform_ = glm::mat4(1.0f);
|
||
mutable glm::mat4 worldTransform_ = glm::mat4(1.0f);
|
||
|
||
// 2. 字符串和容器(24-32字节)
|
||
std::string name_;
|
||
std::vector<Ptr<Node>> children_;
|
||
std::unordered_map<uint32_t, Ptr<Component>> components_;
|
||
|
||
// 3. 子节点索引(加速查找)
|
||
std::unordered_map<std::string, WeakPtr<Node>> nameIndex_;
|
||
std::unordered_map<int, WeakPtr<Node>> tagIndex_;
|
||
|
||
// 4. 事件分发器
|
||
EventDispatcher eventDispatcher_;
|
||
|
||
// 5. 父节点引用
|
||
WeakPtr<Node> parent_;
|
||
|
||
// 6. 变换组件(内置)
|
||
TransformComponent *transform_ = nullptr;
|
||
|
||
// 7. 浮点属性
|
||
float opacity_ = 1.0f;
|
||
|
||
// 8. 颜色属性
|
||
Color3B color_ = Color3B(255, 255, 255);
|
||
|
||
// 9. 整数属性
|
||
int zOrder_ = 0;
|
||
int tag_ = -1;
|
||
|
||
// 10. 布尔属性
|
||
bool flipX_ = false;
|
||
bool flipY_ = false;
|
||
|
||
// 11. 场景指针
|
||
Scene *scene_ = nullptr;
|
||
|
||
// 12. 布尔标志(打包在一起)
|
||
mutable bool transformDirty_ = true;
|
||
mutable bool worldTransformDirty_ = true;
|
||
bool childrenOrderDirty_ = false;
|
||
bool visible_ = true;
|
||
bool running_ = false;
|
||
};
|
||
|
||
} // namespace extra2d
|