perf(scene): 使用哈希表优化节点添加和删除操作

优化 Scene 和 Node 类的子节点管理,通过引入 unordered_map 存储节点索引,将删除操作的时间复杂度从 O(n) 降低到 O(1)。同时防止重复添加相同节点。
This commit is contained in:
ChestnutYueyue 2026-03-16 19:16:00 +08:00
parent 95d9e7c5c4
commit 3df1703839
4 changed files with 34 additions and 12 deletions

View File

@ -6,6 +6,7 @@
#include <types/math/mat4.h>
#include <types/ptr/intrusive_ptr.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
@ -315,6 +316,7 @@ private:
bool visible_ = true;
Node* parent_ = nullptr;
std::vector<Ptr<Node>> children_;
std::unordered_map<Node*, size_t> childIndices_;
std::vector<Ptr<Component>> components_;
TransformComponent* transform_ = nullptr;
};

View File

@ -3,6 +3,7 @@
#include <scene/node.h>
#include <types/ptr/intrusive_ptr.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
@ -115,6 +116,7 @@ public:
protected:
std::vector<Ptr<Node>> rootNodes_;
std::unordered_map<Node*, size_t> rootNodeIndices_;
CameraComponent* mainCamera_ = nullptr;
bool entered_ = false;
};

View File

@ -29,6 +29,7 @@ Node::~Node() {
void Node::addChild(Ptr<Node> child) {
if (!child || child.get() == this) return;
if (childIndices_.find(child.get()) != childIndices_.end()) return;
// 从原父节点移除
if (child->parent_) {
@ -36,18 +37,25 @@ void Node::addChild(Ptr<Node> child) {
}
child->parent_ = this;
childIndices_[child.get()] = children_.size();
children_.push_back(child);
}
void Node::removeChild(Node* child) {
if (!child) return;
for (auto it = children_.begin(); it != children_.end(); ++it) {
if (it->get() == child) {
child->parent_ = nullptr;
children_.erase(it);
auto indexIt = childIndices_.find(child);
if (indexIt == childIndices_.end()) {
return;
}
const size_t removeIndex = indexIt->second;
child->parent_ = nullptr;
children_.erase(children_.begin() + removeIndex);
childIndices_.erase(indexIt);
for (size_t i = removeIndex; i < children_.size(); ++i) {
childIndices_[children_[i].get()] = i;
}
}
@ -62,6 +70,7 @@ void Node::removeAllChildren() {
child->parent_ = nullptr;
}
children_.clear();
childIndices_.clear();
}
// ========================================

View File

@ -16,21 +16,29 @@ Scene::~Scene() {
void Scene::addChild(Ptr<Node> node) {
if (!node) return;
if (rootNodeIndices_.find(node.get()) != rootNodeIndices_.end()) return;
node->removeFromParent();
node->onEnter();
rootNodeIndices_[node.get()] = rootNodes_.size();
rootNodes_.push_back(node);
}
void Scene::removeChild(Node* node) {
if (!node) return;
for (auto it = rootNodes_.begin(); it != rootNodes_.end(); ++it) {
if (it->get() == node) {
node->onExit();
rootNodes_.erase(it);
auto indexIt = rootNodeIndices_.find(node);
if (indexIt == rootNodeIndices_.end()) {
return;
}
const size_t removeIndex = indexIt->second;
node->onExit();
rootNodes_.erase(rootNodes_.begin() + removeIndex);
rootNodeIndices_.erase(indexIt);
for (size_t i = removeIndex; i < rootNodes_.size(); ++i) {
rootNodeIndices_[rootNodes_[i].get()] = i;
}
}
@ -39,6 +47,7 @@ void Scene::removeAllChildren() {
node->onExit();
}
rootNodes_.clear();
rootNodeIndices_.clear();
}
Node* Scene::findNode(const std::string& name) {