#include #include #include #include #include #include #include namespace extra2d { Node::Node() = default; Node::~Node() { removeAllChildren(); } void Node::addChild(Ptr child) { if (!child || child.get() == this) { return; } child->removeFromParent(); child->parent_ = weak_from_this(); children_.push_back(child); childrenOrderDirty_ = true; // 更新索引 if (!child->name().empty()) { nameIndex_[child->name()] = child; } if (child->tag() != -1) { tagIndex_[child->tag()] = child; } if (running_) { child->onEnter(); if (scene_) { child->onAttachToScene(scene_); } } } void Node::addChildren(std::vector> &&children) { // 预留空间,避免多次扩容 size_t newSize = children_.size() + children.size(); if (newSize > children_.capacity()) { children_.reserve(newSize); } for (auto &child : children) { if (!child || child.get() == this) { continue; } child->removeFromParent(); child->parent_ = weak_from_this(); children_.push_back(child); // 更新索引 if (!child->name().empty()) { nameIndex_[child->name()] = child; } if (child->tag() != -1) { tagIndex_[child->tag()] = child; } if (running_) { child->onEnter(); if (scene_) { child->onAttachToScene(scene_); } } } if (!children.empty()) { childrenOrderDirty_ = true; } } void Node::removeChild(Ptr child) { if (!child) return; auto it = std::find(children_.begin(), children_.end(), child); if (it != children_.end()) { // 始终从空间索引中移除(无论 running_ 状态) // 这确保节点被正确清理 (*it)->onDetachFromScene(); if (running_) { (*it)->onExit(); } // 从索引中移除 if (!(*it)->name().empty()) { nameIndex_.erase((*it)->name()); } if ((*it)->tag() != -1) { tagIndex_.erase((*it)->tag()); } (*it)->parent_.reset(); children_.erase(it); } } void Node::removeChildByName(const std::string &name) { auto child = childByName(name); if (child) { removeChild(child); } } void Node::removeFromParent() { auto p = parent_.lock(); if (p) { // 安全获取 shared_ptr,避免在对象未由 shared_ptr 管理时崩溃 Ptr self; try { self = shared_from_this(); } catch (const std::bad_weak_ptr &) { // 对象不是由 shared_ptr 管理的,直接重置父节点引用 parent_.reset(); return; } p->removeChild(self); } } void Node::removeAllChildren() { for (auto &child : children_) { if (running_) { child->onDetachFromScene(); child->onExit(); } child->parent_.reset(); } children_.clear(); nameIndex_.clear(); tagIndex_.clear(); } Ptr Node::childByName(const std::string &name) const { // 使用哈希索引,O(1) 查找 auto it = nameIndex_.find(name); if (it != nameIndex_.end()) { return it->second.lock(); } return nullptr; } Ptr Node::childByTag(int tag) const { // 使用哈希索引,O(1) 查找 auto it = tagIndex_.find(tag); if (it != tagIndex_.end()) { return it->second.lock(); } return nullptr; } void Node::setPosition(const Vec2 &pos) { position_ = pos; markTransformDirty(); updateSpatialIndex(); } void Node::setPosition(float x, float y) { setPosition(Vec2(x, y)); } void Node::setRotation(float degrees) { rotation_ = degrees; markTransformDirty(); updateSpatialIndex(); } void Node::setScale(const Vec2 &scale) { scale_ = scale; markTransformDirty(); updateSpatialIndex(); } void Node::setScale(float scale) { setScale(Vec2(scale, scale)); } void Node::setScale(float x, float y) { setScale(Vec2(x, y)); } void Node::setAnchor(const Vec2 &anchor) { anchor_ = anchor; markTransformDirty(); } void Node::setAnchor(float x, float y) { setAnchor(Vec2(x, y)); } void Node::setSkew(const Vec2 &skew) { skew_ = skew; markTransformDirty(); } void Node::setSkew(float x, float y) { setSkew(Vec2(x, y)); } void Node::setOpacity(float opacity) { opacity_ = std::clamp(opacity, 0.0f, 1.0f); } void Node::setVisible(bool visible) { visible_ = visible; } void Node::setColor(const Color3B &color) { color_ = color; } void Node::setFlipX(bool flipX) { flipX_ = flipX; } void Node::setFlipY(bool flipY) { flipY_ = flipY; } void Node::setZOrder(int zOrder) { if (zOrder_ != zOrder) { zOrder_ = zOrder; childrenOrderDirty_ = true; } } Vec2 Node::convertToWorldSpace(const Vec2 &localPos) const { glm::vec4 worldPos = getWorldTransform() * glm::vec4(localPos.x, localPos.y, 0.0f, 1.0f); return Vec2(worldPos.x, worldPos.y); } Vec2 Node::convertToNodeSpace(const Vec2 &worldPos) const { glm::mat4 invWorld = glm::inverse(getWorldTransform()); glm::vec4 localPos = invWorld * glm::vec4(worldPos.x, worldPos.y, 0.0f, 1.0f); return Vec2(localPos.x, localPos.y); } glm::mat4 Node::getLocalTransform() const { if (transformDirty_) { localTransform_ = glm::mat4(1.0f); // T - R - S order localTransform_ = glm::translate(localTransform_, glm::vec3(position_.x, position_.y, 0.0f)); if (rotation_ != 0.0f) { localTransform_ = glm::rotate(localTransform_, rotation_ * DEG_TO_RAD, glm::vec3(0.0f, 0.0f, 1.0f)); } if (skew_.x != 0.0f || skew_.y != 0.0f) { glm::mat4 skewMatrix(1.0f); skewMatrix[1][0] = std::tan(skew_.x * DEG_TO_RAD); skewMatrix[0][1] = std::tan(skew_.y * DEG_TO_RAD); localTransform_ *= skewMatrix; } localTransform_ = glm::scale(localTransform_, glm::vec3(scale_.x, scale_.y, 1.0f)); // 注意:锚点偏移在渲染时处理,不在本地变换中处理 // 这样可以避免锚点偏移被父节点的缩放影响 transformDirty_ = false; } return localTransform_; } glm::mat4 Node::getWorldTransform() const { if (worldTransformDirty_) { // 使用线程局部存储的固定数组,避免每帧内存分配 // 限制最大深度为 256 层,足以覆盖绝大多数场景 thread_local std::array nodeChainCache; thread_local size_t chainCount = 0; chainCount = 0; const Node *current = this; while (current && chainCount < nodeChainCache.size()) { nodeChainCache[chainCount++] = current; auto p = current->parent_.lock(); current = p.get(); } // 从根节点开始计算 glm::mat4 transform = glm::mat4(1.0f); for (size_t i = chainCount; i > 0; --i) { transform = transform * nodeChainCache[i - 1]->getLocalTransform(); } worldTransform_ = transform; worldTransformDirty_ = false; } return worldTransform_; } void Node::markTransformDirty() { // 避免重复标记,提高性能 if (!transformDirty_ || !worldTransformDirty_) { transformDirty_ = true; worldTransformDirty_ = true; // 递归标记所有子节点 for (auto &child : children_) { child->markTransformDirty(); } } } void Node::batchUpdateTransforms() { // 如果本地变换脏了,先计算本地变换 if (transformDirty_) { (void)getLocalTransform(); // 这会计算并缓存本地变换 } // 如果世界变换脏了,需要重新计算 if (worldTransformDirty_) { auto parent = parent_.lock(); if (parent) { // 使用父节点的世界变换(确保父节点已经更新) worldTransform_ = parent->getWorldTransform() * localTransform_; } else { // 根节点 worldTransform_ = localTransform_; } worldTransformDirty_ = false; } // 递归更新子节点 for (auto &child : children_) { child->batchUpdateTransforms(); } } void Node::onEnter() { running_ = true; for (auto &child : children_) { child->onEnter(); } } void Node::onExit() { running_ = false; for (auto &child : children_) { child->onExit(); } } void Node::onUpdate(float dt) { updateTweens(dt); onUpdateNode(dt); // Update children for (auto &child : children_) { child->onUpdate(dt); } } void Node::onRender(Renderer &renderer) { if (!visible_) return; onDraw(renderer); for (auto &child : children_) { child->onRender(renderer); } } void Node::onAttachToScene(Scene *scene) { scene_ = scene; // 添加到场景的空间索引 if (spatialIndexed_ && scene_) { lastSpatialBounds_ = Rect(); updateSpatialIndex(); } for (auto &child : children_) { child->onAttachToScene(scene); } } void Node::onDetachFromScene() { // 从场景的空间索引移除 // 注意:即使 lastSpatialBounds_ 为空也要尝试移除, // 因为节点可能通过其他方式被插入到空间索引中 if (spatialIndexed_ && scene_) { scene_->removeNodeFromSpatialIndex(this); lastSpatialBounds_ = Rect(); } scene_ = nullptr; for (auto &child : children_) { child->onDetachFromScene(); } } Rect Node::boundingBox() const { // 默认返回一个以位置为中心的点矩形 return Rect(position_.x, position_.y, 0, 0); } void Node::updateSpatialIndex() { if (!spatialIndexed_ || !scene_) { return; } Rect newBounds = boundingBox(); if (newBounds != lastSpatialBounds_) { scene_->updateNodeInSpatialIndex(this, lastSpatialBounds_, newBounds); lastSpatialBounds_ = newBounds; } } void Node::update(float dt) { onUpdate(dt); } void Node::render(Renderer &renderer) { if (childrenOrderDirty_) { sortChildren(); } onRender(renderer); } void Node::sortChildren() { // 使用插入排序优化小范围更新场景 // 插入排序在大部分已有序的情况下性能接近O(n) size_t n = children_.size(); if (n <= 1) { childrenOrderDirty_ = false; return; } // 小数组使用插入排序,大数组使用std::sort if (n < 32) { // 插入排序 for (size_t i = 1; i < n; ++i) { auto key = children_[i]; int keyZOrder = key->zOrder(); int j = static_cast(i) - 1; while (j >= 0 && children_[j]->zOrder() > keyZOrder) { children_[j + 1] = children_[j]; --j; } children_[j + 1] = key; } } else { // 大数组使用标准排序 std::sort(children_.begin(), children_.end(), [](const Ptr &a, const Ptr &b) { return a->zOrder() < b->zOrder(); }); } childrenOrderDirty_ = false; } void Node::collectRenderCommands(std::vector &commands, int parentZOrder) { if (!visible_) return; // 计算累积 Z 序 int accumulatedZOrder = parentZOrder + zOrder_; // 生成当前节点的渲染命令 generateRenderCommand(commands, accumulatedZOrder); // 递归收集子节点的渲染命令 // 注意:这里假设子节点已经按 Z 序排序 for (auto &child : children_) { child->collectRenderCommands(commands, accumulatedZOrder); } } Tween &Node::tween() { auto tw = std::make_shared(this); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::tween(const std::string &name) { auto tw = std::make_shared(this, name); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::moveTo(const Vec2 &pos, float duration, TweenEasing easing) { TweenProperty props; props.position = pos; TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->to(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::moveBy(const Vec2 &delta, float duration, TweenEasing easing) { TweenProperty props; props.position = delta; TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->by(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::scaleTo(float scale, float duration, TweenEasing easing) { TweenProperty props; props.scale = Vec2(scale, scale); TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->to(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::scaleBy(float delta, float duration, TweenEasing easing) { TweenProperty props; props.scale = Vec2(delta, delta); TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->by(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::rotateTo(float degrees, float duration, TweenEasing easing) { TweenProperty props; props.rotation = degrees; TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->to(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::rotateBy(float degrees, float duration, TweenEasing easing) { TweenProperty props; props.rotation = degrees; TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->by(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::fadeIn(float duration, TweenEasing easing) { TweenProperty props; props.opacity = 1.0f; TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->to(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::fadeOut(float duration, TweenEasing easing) { TweenProperty props; props.opacity = 0.0f; TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->to(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } Tween &Node::fadeTo(float opacity, float duration, TweenEasing easing) { TweenProperty props; props.opacity = opacity; TweenOptions options; options.easing = easing; auto tw = std::make_shared(this); tw->to(duration, props, options); tw->start(); tweens_.push_back(tw); return *tweens_.back(); } void Node::stopAllTweens() { for (auto &tw : tweens_) { tw->stop(); } tweens_.clear(); } void Node::updateTweens(float dt) { for (auto it = tweens_.begin(); it != tweens_.end();) { (*it)->update(dt); if ((*it)->isFinished()) { it = tweens_.erase(it); } else { ++it; } } } } // namespace extra2d