Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add get_descendants, get_descendant_count, get_ancestors and get_ancestor_count to Node #76674

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions doc/classes/Node.xml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,18 @@
[b]Note:[/b] As this method walks upwards in the scene tree, it can be slow in large, deeply nested scene trees. Whenever possible, consider using [method get_node] with unique names instead (see [member unique_name_in_owner]), or caching the node references into variable.
</description>
</method>
<method name="get_ancestor_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of ancestor nodes.
</description>
</method>
<method name="get_ancestors" qualifiers="const">
<return type="Node[]" />
<description>
Returns an array of references to node's ancestors.
</description>
</method>
<method name="get_child" qualifiers="const">
<return type="Node" />
<param index="0" name="idx" type="int" />
Expand Down Expand Up @@ -280,6 +292,22 @@
If [param include_internal] is [code]false[/code], the returned array won't include internal children (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
<method name="get_descendant_count" qualifiers="const">
<return type="int" />
<param index="0" name="include_internal" type="bool" default="false" />
<description>
Returns the number of descendant nodes.
If [param include_internal] is [code]false[/code], the returned array won't include internal descendants (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
<method name="get_descendants" qualifiers="const">
<return type="Node[]" />
<param index="0" name="include_internal" type="bool" default="false" />
<description>
Returns an array of references to node's descendants.
If [param include_internal] is [code]false[/code], the returned array won't include internal descendants (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
<method name="get_groups" qualifiers="const">
<return type="StringName[]" />
<description>
Expand Down
49 changes: 49 additions & 0 deletions scene/main/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,51 @@ Node *Node::_get_child_by_name(const StringName &p_name) const {
}
}

int Node::get_descendant_count(bool p_include_internal) const {
int count = 0;
TypedArray<Node> children = get_children(p_include_internal);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure using the "get_children" function is the best way to achieve this, none of the other functions use this and instead access the children directly, see the function itself for that, not sure what the performance difference would be but that would be my suggestion

count += children.size();
for (int i = 0; i < children.size(); i++) {
Node *node = Object::cast_to<Node>(children[i]);
if (node->get_child_count(p_include_internal) > 0) {
count += node->get_descendant_count(p_include_internal);
}
}
return count;
}

TypedArray<Node> Node::get_descendants(bool p_include_internal) const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For style there should be a line between these two functions, to make it easier to navigate and read

TypedArray<Node> res = get_children(p_include_internal);
TypedArray<Node> children = get_children(p_include_internal);
for (int i = 0; i < children.size(); i++) {
Node *node = Object::cast_to<Node>(children[i]);
if (node->get_child_count(p_include_internal) > 0) {
res.append_array(node->get_descendants(p_include_internal));
}
}
return res;
}

int Node::get_ancestor_count() const {
int count = 0;
const Node* current_node = this;
while (current_node->get_parent() != nullptr){
count++;
current_node = current_node->get_parent();
}
return count;
}

TypedArray<Node> Node::get_ancestors() const {
TypedArray<Node> res;
const Node* current_node = this;
while (current_node->get_parent() != nullptr){
res.append(current_node);
current_node = current_node->get_parent();
}
return res;
}

Node *Node::get_node_or_null(const NodePath &p_path) const {
if (p_path.is_empty()) {
return nullptr;
Expand Down Expand Up @@ -2857,6 +2902,10 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::get_children, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_child", "idx", "include_internal"), &Node::get_child, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_descendants", "include_internal"), &Node::get_descendants, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_descendant_count", "include_internal"), &Node::get_descendant_count, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_ancestors"), &Node::get_ancestors);
ClassDB::bind_method(D_METHOD("get_ancestor_count"), &Node::get_ancestor_count);
ClassDB::bind_method(D_METHOD("has_node", "path"), &Node::has_node);
ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node);
ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null);
Expand Down
4 changes: 4 additions & 0 deletions scene/main/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ class Node : public Object {
int get_child_count(bool p_include_internal = true) const;
Node *get_child(int p_index, bool p_include_internal = true) const;
TypedArray<Node> get_children(bool p_include_internal = true) const;
TypedArray<Node> get_descendants(bool p_include_internal = true) const;
int get_descendant_count(bool p_include_internal = true) const;
TypedArray<Node> get_ancestors() const;
int get_ancestor_count() const;
bool has_node(const NodePath &p_path) const;
Node *get_node(const NodePath &p_path) const;
Node *get_node_or_null(const NodePath &p_path) const;
Expand Down