前言
最近用了用Godot,发现里面的节点还是十分神奇的,所以写一个玩玩。
Node.hpp
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <iostream>
namespace Node
{
// 节点类
class Node
{
private:
// 节点名
std::string m_name;
// 子节点
// std::shared_ptr可以自动释放资源
std::vector<std::pair<std::string, std::shared_ptr<Node>>> m_childs;
// 该节点的父级,如果没有,会被设置为nullptr
// 没有父节点意味着它是根节点
Node *m_parent;
public:
// 构造函数
Node(std::string name) : m_name(name), m_parent(nullptr) {}
Node(Node *parent, std::string name) : m_name(name), m_parent(parent) {}
Node(const Node &from) { operator=(from); }
public:
Node &operator=(const Node &from)
{
m_name = from.m_name;
m_childs = from.m_childs;
m_parent = from.m_parent;
return *this;
}
// 通过索引获取子节点,有越界检查,因为std::vector::at有
Node *operator[](size_t index)
{
return m_childs.at(index).second.get();
}
public:
// “常数”,子节点没找到时被设置为此值
size_t CHILD_NOT_FOUND()
{
return m_childs.size();
}
// 挨个查找子节点
size_t find_child(std::string name)
{
for (size_t i = 0; i < m_childs.size(); i++)
{
if (m_childs.at(i).first == name)
{
return i;
}
}
return CHILD_NOT_FOUND();
}
// 获取子节点,没有返回nullptr
Node *get_child(std::string name)
{
size_t index = find_child(name);
if (index == CHILD_NOT_FOUND())
{
return nullptr;
}
else
{
return m_childs.at(index).second.get();
}
}
// 增加子节点
// 子节点为自己或者父级时不会添加(其实应该报错)
Node &add_child(std::string name, std::shared_ptr<Node> node)
{
if (node.get() == m_parent || node.get() == this)
{
std::cout << "Cannot set parent or self as child." << std::endl;
}
else
{
m_childs.push_back(std::pair<std::string, std::shared_ptr<Node>>(name, node));
}
return *this;
}
// 移除子节点
bool remove_child(std::string name)
{
size_t index = find_child(name);
if (index == CHILD_NOT_FOUND())
{
return false;
}
else
{
m_childs.erase(m_childs.begin() + index);
return true;
}
}
// 获取本节点名称
std::string get_name()
{
return m_name;
}
// 获取子节点数量
size_t get_child_count()
{
return m_childs.size();
}
// 判断本节点是否为根节点,也就是没有父级
bool is_root_node()
{
return (m_parent == nullptr);
}
// 获取父级
Node *get_parent()
{
return m_parent;
}
};
// 调试用,输出节点
// 输出缩进
void print_tab(size_t tab)
{
for (size_t i = 0; i < tab; i++)
{
std::cout << "\t";
}
}
// 输出节点名
void print_name(Node node)
{
std::cout << "\"" << node.get_name() << "\"" << std::endl;
}
// 递归遍历输出所有节点
void print_all(Node root, size_t tab = 0)
{
print_tab(tab);
print_name(root);
for (size_t i = 0; i < root.get_child_count(); i++)
{
print_all(*root[i], tab + 1);
}
}
} // namespace Node
测试
#include <iostream>
#include "Node.hpp"
int main()
{
Node::Node root("root");
root.add_child("root_child1",std::make_shared<Node::Node>("root->child1"));
root.add_child("root_child2",std::make_shared<Node::Node>("root->child2"));
//root.get_child("root_child1")->add_child("root_child1",std::shared_ptr<Node::Node>(root.get_child("root_child1")));
root.get_child("root_child1")->add_child("root_child1_child1",std::make_shared<Node::Node>("root->child1->child1"));
root.get_child("root_child1")->add_child("root_child1_child2",std::make_shared<Node::Node>("root->child1->child2"));
root.get_child("root_child2")->add_child("root_child2_child1",std::make_shared<Node::Node>("root->child2->child1"));
root.get_child("root_child2")->add_child("root_child2_child2",std::make_shared<Node::Node>("root->child2->child2"));
Node::print_all(root);
root.get_child("root_child1")->remove_child("root_child1_child2");
root.remove_child("root_child2");
std::cout << std::endl;
Node::print_all(root);
return 0;
}
输出
“root”
“root->child1”
“root->child1->child1”
“root->child1->child2”
“root->child2”
“root->child2->child1”
“root->child2->child2”“root”
“root->child1”
“root->child1->child1”