Write nodes_and_scene_instances.rst from scripting_continued.rst

Rewrote the docs
Added an intro section about getting nodes and syntactic sugar
This commit is contained in:
Nathan Lovato
2020-11-07 23:11:29 -06:00
parent 61863b181f
commit 9927bfbb71
5 changed files with 206 additions and 116 deletions

View File

@@ -122,122 +122,6 @@ follows, can be applied to nodes:
As mentioned before, it's better to use these functions instead of
the notification system.
Creating nodes
--------------
To create a node from code, call the ``.new()`` method, like for any
other class-based datatype. For example:
.. tabs::
.. code-tab:: gdscript GDScript
var s
func _ready():
s = Sprite.new() # Create a new sprite!
add_child(s) # Add it as a child of this node.
.. code-tab:: csharp
private Sprite _sprite;
public override void _Ready()
{
base._Ready();
_sprite = new Sprite(); // Create a new sprite!
AddChild(_sprite); // Add it as a child of this node.
}
To delete a node, be it inside or outside the scene, ``free()`` must be
used:
.. tabs::
.. code-tab:: gdscript GDScript
func _someaction():
s.free() # Immediately removes the node from the scene and frees it.
.. code-tab:: csharp
public void _SomeAction()
{
_sprite.Free(); // Immediately removes the node from the scene and frees it.
}
When a node is freed, it also frees all its child nodes. Because of
this, manually deleting nodes is much simpler than it appears. Free
the base node and everything else in the subtree goes away with it.
A situation might occur where we want to delete a node that
is currently "blocked", because it is emitting a signal or calling a
function. This will crash the game. Running Godot
with the debugger will often catch this case and warn you about it.
The safest way to delete a node is by using
:ref:`Node.queue_free() <class_Node_method_queue_free>`.
This erases the node safely during idle.
.. tabs::
.. code-tab:: gdscript GDScript
func _someaction():
s.queue_free() # Removes the node from the scene and frees it when it becomes safe to do so.
.. code-tab:: csharp
public void _SomeAction()
{
_sprite.QueueFree(); // Removes the node from the scene and frees it when it becomes safe to do so.
}
Instancing scenes
-----------------
Instancing a scene from code is done in two steps. The
first one is to load the scene from your hard drive:
.. tabs::
.. code-tab:: gdscript GDScript
var scene = load("res://myscene.tscn") # Will load when the script is instanced.
.. code-tab:: csharp
var scene = GD.Load<PackedScene>("res://myscene.tscn"); // Will load when the script is instanced.
Preloading it can be more convenient, as it happens at parse
time (GDScript only):
.. tabs::
.. code-tab:: gdscript GDScript
var scene = preload("res://myscene.tscn") # Will load when parsing the script.
But ``scene`` is not yet a node. It's packed in a
special resource called :ref:`PackedScene <class_PackedScene>`.
To create the actual node, the function
:ref:`PackedScene.instance() <class_PackedScene_method_instance>`
must be called. This will return the tree of nodes that can be added to
the active scene:
.. tabs::
.. code-tab:: gdscript GDScript
var node = scene.instance()
add_child(node)
.. code-tab:: csharp
var node = scene.Instance();
AddChild(node);
The advantage of this two-step process is that a packed scene may be
kept loaded and ready to use so that you can create as many
instances as desired. This is especially useful to quickly instance
several enemies, bullets, and other entities in the active scene.
.. _doc_scripting_continued_class_name:
Register scripts as classes

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -37,6 +37,7 @@ below will help you make the most of Godot.
debug/index
idle_and_physics_processing
groups
nodes_and_scene_instances
cross_language_scripting
creating_script_templates
change_scenes_manually

View File

@@ -0,0 +1,205 @@
.. _doc_nodes_and_scene_instances:
Nodes and scene instances
=========================
This guide explains how to get nodes, create nodes, add them as a child, and
instantiate scenes from code.
Getting nodes
-------------
You can get a reference to a node by calling the :ref:`Node.get_node()
<class_Node_method_get_node>` method. For this to work, the child node must be
present in the scene tree. Getting it in the parent node's ``_ready()`` function
guarantees that.
Say you have a scene tree like this, and you want to get a reference to the
Sprite and Camera2D nodes to access them in your script.
.. image:: img/nodes_and_scene_instances_player_scene_example.png
To do so, you can use the following code.
.. tabs::
.. code-tab:: gdscript GDScript
var sprite
var camera2d
func _ready():
sprite = get_node("Sprite")
camera2d = get_node("Camera2D")
.. code-tab:: csharp
private Sprite _sprite;
private Camera2D _camera2d;
public override void _Ready()
{
base._Ready();
_sprite = GetNode<Sprite>("Sprite");
_camera2d = GetNode<Camera2D>("Camera2D");
}
Note that you get nodes by their name. For example, if you rename the Sprite
node into Skin, the call to get it would have to be ``get_node("Skin")``.
Node paths
----------
You're not limited to getting a direct child. The ``get_node()`` function
supports paths, a bit like when working with a file browser. Add a slash to
separate nodes.
Take the following example scene, with the script attached to the UserInterface
node.
.. image:: img/nodes_and_scene_instances_ui_scene_example.png
To get the Tween node, you would use the following code.
.. tabs::
.. code-tab:: gdscript GDScript
var tween
func _ready():
tween = get_node("ShieldBar/Tween")
.. code-tab:: csharp
private Tween _tween;
public override void _Ready()
{
base._Ready();
_tween = GetNode<Tween>("ShieldBar/Tween");
}
.. note:: As with file paths, you can use ".." to get a parent node. The best
practice is to avoid doing that though not to break encapsulation and
keep your code organized. You can also start the path with a forward
slash to make it absolute, in which case your topmost node would be
"/root", the application's predefined root viewport.
Syntactic sugar
~~~~~~~~~~~~~~~
You can use two shorthands to shorten your code in GDScript: putting the
``onready`` keyword before a member variable makes it initialize right before
the ``_ready()`` callback.
.. code-block:: gdscript
onready var sprite = get_node("Sprite")
There is also a short notation for ``get_node()``: the dollar sign, "$". You
place it before the name or path of the node you want to get.
.. code-block:: gdscript
onready var sprite = $Sprite
onready var tween = $ShieldBar/Tween
Creating nodes
--------------
To create a node from code, call its ``new()`` method like for any other
class-based datatype.
You can store the newly created node's reference in a variable and call
``add_child()`` to add it as a child of the node to which you attached the
script.
.. tabs::
.. code-tab:: gdscript GDScript
var sprite
func _ready():
var sprite = Sprite.new() # Create a new Sprite.
add_child(sprite) # Add it as a child of this node.
.. code-tab:: csharp
private Sprite _sprite;
public override void _Ready()
{
base._Ready();
_sprite = new Sprite(); // Create a new Sprite.
AddChild(_sprite); // Add it as a child of this node.
}
To delete a node and free it from memory, you can call its ``queue_free()``
method. Doing so queues the node for deletion at the end of the current frame
after it finished processing. At that point, the engine removes the node from
the scene and frees the object in memory.
.. tabs::
.. code-tab:: gdscript GDScript
sprite.queue_free()
.. code-tab:: csharp
_sprite.QueueFree();
You can alternatively call ``free()`` to immediately destroy the node. You
should do this with care as any reference to it will instantly become ``null``.
We recommend using ``queue_free()`` unless you know what you're doing.
When you free a node, it also frees all its children. Thanks to this, to delete
an entire branch of the scene tree, you only have to free the topmost parent
node.
Instancing scenes
-----------------
Instancing a scene from code happens in two steps:
1. Loading the scene from the hard drive.
2. Creating an instance of the loaded :ref:`PackedScene <class_PackedScene>`
resource.
.. tabs::
.. code-tab:: gdscript GDScript
var scene = load("res://MyScene.tscn")
.. code-tab:: csharp
var scene = GD.Load<PackedScene>("res://MyScene.tscn");
Preloading it can improve the user's experience as it happens when parsing the
script. This feature is only available with GDScript.
.. tabs::
.. code-tab:: gdscript GDScript
var scene = preload("res://MyScene.tscn")
At that point, ``scene`` is a packed scene resource, not a node. To create the
actual node, you need to call :ref:`PackedScene.instance()
<class_PackedScene_method_instance>`. It returns a tree of nodes that you can
add as a child.
.. tabs::
.. code-tab:: gdscript GDScript
var instance = scene.instance()
add_child(instance)
.. code-tab:: csharp
var instance = scene.();
AddChild(instance);
The advantage of this two-step process is you can keep a packed scene loaded and
create new instances on the fly. For example, to quickly instance several
enemies or bullets.