Extra2D/Extra2D/include/extra2d/scene/node.h

615 lines
14 KiB
C++
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.

#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