Node: Fix logic of has/get_node_and_resource and document it

Also document NodePath.
This commit is contained in:
Rémi Verschelde 2019-06-26 15:15:11 +02:00
parent cb8d95dd4b
commit 6e9272eea8
3 changed files with 63 additions and 16 deletions

View File

@ -268,6 +268,14 @@
<argument index="0" name="path" type="NodePath"> <argument index="0" name="path" type="NodePath">
</argument> </argument>
<description> <description>
Fetches a node and one of its resources as specified by the [NodePath]'s subname (e.g. [code]Area2D/CollisionShape2D:shape[/code]). If several nested resources are specified in the [NodePath], the last one will be fetched.
The return value is an array of size 3: the first index points to the [Node] (or [code]null[/code] if not found), the second index points to the [Resource] (or [code]null[/code] if not found), and the third index is the remaining [NodePath], if any.
For example, assuming that [code]Area2D/CollisionShape2D[/code] is a valid node and that its [code]shape[/code] property has been assigned a [RectangleShape2D] resource, one could have this kind of output:
[codeblock]
print(get_node_and_resource("Area2D/CollisionShape2D")) # [[CollisionShape2D:1161], Null, ]
print(get_node_and_resource("Area2D/CollisionShape2D:shape")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], ]
print(get_node_and_resource("Area2D/CollisionShape2D:shape:extents")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], :extents]
[/codeblock]
</description> </description>
</method> </method>
<method name="get_node_or_null" qualifiers="const"> <method name="get_node_or_null" qualifiers="const">
@ -359,6 +367,7 @@
<argument index="0" name="path" type="NodePath"> <argument index="0" name="path" type="NodePath">
</argument> </argument>
<description> <description>
Returns [code]true[/code] if the [NodePath] points to a valid node and its subname points to a valid resource, e.g. [code]Area2D/CollisionShape2D:shape[/code]. Properties with a non-[Resource] type (e.g. nodes or primitive math types) are not considered resources.
</description> </description>
</method> </method>
<method name="is_a_parent_of" qualifiers="const"> <method name="is_a_parent_of" qualifiers="const">

View File

@ -4,9 +4,9 @@
Pre-parsed scene tree path. Pre-parsed scene tree path.
</brief_description> </brief_description>
<description> <description>
A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, [code]"Path2D/PathFollow2D/Sprite:texture:size"[/code] would refer to the size property of the texture resource on the node named "Sprite" which is a child of the other named nodes in the path. Note that if you want to get a resource, you must end the path with a colon, otherwise the last element will be used as a property name. A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, [code]"Path2D/PathFollow2D/Sprite:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite"[/code] which is a child of the other named nodes in the path.
You will usually just pass a string to [method Node.get_node] and it will be automatically converted, but you may occasionally want to parse a path ahead of time with [NodePath] or the literal syntax [code]@"path"[/code]. Exporting a [NodePath] variable will give you a node selection widget in the properties panel of the editor, which can often be useful. You will usually just pass a string to [method Node.get_node] and it will be automatically converted, but you may occasionally want to parse a path ahead of time with [NodePath] or the literal syntax [code]@"path"[/code]. Exporting a [NodePath] variable will give you a node selection widget in the properties panel of the editor, which can often be useful.
A [NodePath] is made up of a list of node names, a list of "subnode" (resource) names, and the name of a property in the final node or resource. A [NodePath] is composed of a list of slash-separated node names (like a filesystem path) and an optional colon-separated list of "subnames" which can be resources or properties.
</description> </description>
<tutorials> <tutorials>
</tutorials> </tutorials>
@ -18,18 +18,46 @@
</argument> </argument>
<description> <description>
Create a NodePath from a string, e.g. "Path2D/PathFollow2D/Sprite:texture:size". A path is absolute if it starts with a slash. Absolute paths are only valid in the global scene tree, not within individual scenes. In a relative path, [code]"."[/code] and [code]".."[/code] indicate the current node and its parent. Create a NodePath from a string, e.g. "Path2D/PathFollow2D/Sprite:texture:size". A path is absolute if it starts with a slash. Absolute paths are only valid in the global scene tree, not within individual scenes. In a relative path, [code]"."[/code] and [code]".."[/code] indicate the current node and its parent.
The "subnames" optionally included after the path to the target node can point to resources or properties, and can also be nested.
Examples of valid NodePaths (assuming that those nodes exist and have the referenced resources or properties):
[codeblock]
# Points to the Sprite node
"Path2D/PathFollow2D/Sprite"
# Points to the Sprite node and its 'texture' resource.
# get_node() would retrieve "Sprite", while get_node_and_resource()
# would retrieve both the Sprite node and the 'texture' resource.
"Path2D/PathFollow2D/Sprite:texture"
# Points to the Sprite node and its 'position' property.
"Path2D/PathFollow2D/Sprite:position"
# Points to the Sprite node and the 'x' component of its 'position' property.
"Path2D/PathFollow2D/Sprite:position:x"
# Absolute path (from 'root')
"/root/Level/Path2D"
[/codeblock]
</description> </description>
</method> </method>
<method name="get_as_property_path"> <method name="get_as_property_path">
<return type="NodePath"> <return type="NodePath">
</return> </return>
<description> <description>
Returns a node path with a colon character ([code]:[/code]) prepended, transforming it to a pure property path with no node name (defaults to resolving from the current node).
[codeblock]
# This will be parsed as a node path to the 'x' property in the 'position' node
var node_path = NodePath("position:x")
# This will be parsed as a node path to the 'x' component of the 'position' property in the current node
var property_path = node_path.get_as_property_path()
print(property_path) # :position:x
</description> </description>
</method> </method>
<method name="get_concatenated_subnames"> <method name="get_concatenated_subnames">
<return type="String"> <return type="String">
</return> </return>
<description> <description>
Returns all subnames concatenated with a colon character ([code]:[/code]) as separator, i.e. the right side of the first colon in a node path.
[codeblock]
var nodepath = NodePath("Path2D/PathFollow2D/Sprite:texture:load_path")
print(nodepath.get_concatenated_subnames()) # texture:load_path
[/codeblock]
</description> </description>
</method> </method>
<method name="get_name"> <method name="get_name">
@ -38,14 +66,21 @@
<argument index="0" name="idx" type="int"> <argument index="0" name="idx" type="int">
</argument> </argument>
<description> <description>
Get the node name indicated by [code]idx[/code] (0 to [method get_name_count]) Get the node name indicated by [code]idx[/code] (0 to [method get_name_count]).
[codeblock]
var node_path = NodePath("Path2D/PathFollow2D/Sprite")
print(node_path.get_name(0)) # Path2D
print(node_path.get_name(1)) # PathFollow2D
print(node_path.get_name(2)) # Sprite
[/codeblock]
</description> </description>
</method> </method>
<method name="get_name_count"> <method name="get_name_count">
<return type="int"> <return type="int">
</return> </return>
<description> <description>
Get the number of node names which make up the path. Get the number of node names which make up the path. Subnames (see [method get_subname_count]) are not included.
For example, [code]"Path2D/PathFollow2D/Sprite"[code] has 3 names.
</description> </description>
</method> </method>
<method name="get_subname"> <method name="get_subname">
@ -54,21 +89,27 @@
<argument index="0" name="idx" type="int"> <argument index="0" name="idx" type="int">
</argument> </argument>
<description> <description>
Get the resource name indicated by [code]idx[/code] (0 to [method get_subname_count]) Get the resource or property name indicated by [code]idx[/code] (0 to [method get_subname_count]).
[codeblock]
var node_path = NodePath("Path2D/PathFollow2D/Sprite:texture:load_path")
print(node_path.get_subname(0)) # texture
print(node_path.get_subname(1)) # load_path
[/codeblock]
</description> </description>
</method> </method>
<method name="get_subname_count"> <method name="get_subname_count">
<return type="int"> <return type="int">
</return> </return>
<description> <description>
Get the number of resource names in the path. Get the number of resource or property names ("subnames") in the path. Each subname is listed after a colon character ([code]:[/code]) in the node path.
For example, [code]"Path2D/PathFollow2D/Sprite:texture:load_path"[/code] has 2 subnames.
</description> </description>
</method> </method>
<method name="is_absolute"> <method name="is_absolute">
<return type="bool"> <return type="bool">
</return> </return>
<description> <description>
Returns [code]true[/code] if the node path is absolute (not relative). Returns [code]true[/code] if the node path is absolute (as opposed to relative), which means that it starts with a slash character ([code]/[/code]). Absolute node paths can be used to access the root node ([code]"/root"[/code]) or autoloads (e.g. [code]"/global"[/code] if a "global" autoload was registered).
</description> </description>
</method> </method>
<method name="is_empty"> <method name="is_empty">

View File

@ -2477,21 +2477,18 @@ bool Node::has_node_and_resource(const NodePath &p_path) const {
if (!has_node(p_path)) if (!has_node(p_path))
return false; return false;
Node *node = get_node(p_path); RES res;
Vector<StringName> leftover_path;
Node *node = get_node_and_resource(p_path, res, leftover_path, false);
bool result = false; return (node && res.is_valid());
node->get_indexed(p_path.get_subnames(), &result);
return result;
} }
Array Node::_get_node_and_resource(const NodePath &p_path) { Array Node::_get_node_and_resource(const NodePath &p_path) {
Node *node;
RES res; RES res;
Vector<StringName> leftover_path; Vector<StringName> leftover_path;
node = get_node_and_resource(p_path, res, leftover_path); Node *node = get_node_and_resource(p_path, res, leftover_path, false);
Array result; Array result;
if (node) if (node)
@ -2521,7 +2518,7 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
int j = 0; int j = 0;
// If not p_last_is_property, we shouldn't consider the last one as part of the resource // If not p_last_is_property, we shouldn't consider the last one as part of the resource
for (; j < p_path.get_subname_count() - p_last_is_property; j++) { for (; j < p_path.get_subname_count() - (int)p_last_is_property; j++) {
RES new_res = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j)); RES new_res = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j));
if (new_res.is_null()) { if (new_res.is_null()) {