mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-01-05 22:09:56 +03:00
384 lines
11 KiB
ReStructuredText
384 lines
11 KiB
ReStructuredText
.. _doc_scripting_continued:
|
|
|
|
Scripting (continued)
|
|
=====================
|
|
|
|
Processing
|
|
----------
|
|
|
|
Several actions in Godot are triggered by callbacks or virtual functions,
|
|
so there is no need to write code that runs all the time.
|
|
|
|
However, it is still common to need a script to be processed on every
|
|
frame. There are two types of processing: idle processing and physics
|
|
processing.
|
|
|
|
Idle processing is activated when the method :ref:`Node._process() <class_Node__process>`
|
|
is found in a script. It can be turned off and on with the
|
|
:ref:`Node.set_process() <class_Node_set_process>` function.
|
|
|
|
This method will be called every time a frame is drawn, so it's fully dependent on
|
|
how many frames per second (FPS) the application is running at:
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
func _process(delta):
|
|
# do something...
|
|
pass
|
|
|
|
.. code-tab:: csharp
|
|
|
|
public override void _Process(float delta)
|
|
{
|
|
// do something...
|
|
}
|
|
|
|
The delta parameter contains the time elapsed in seconds, as a
|
|
floating point, since the previous call to ``_process()``.
|
|
|
|
This parameter can be used to make sure things always take the same
|
|
amount of time, regardless of the game's FPS.
|
|
|
|
For example, movement is often multiplied with a time delta to make movement
|
|
speed both constant and independent from the frame rate.
|
|
|
|
Physics processing with ``_physics_process()`` is similar, but it should be used for processes that
|
|
must happen before each physics step, such as controlling a character.
|
|
It always runs before a physics step and it is called at fixed time intervals:
|
|
60 times per second by default. You can change the interval from the Project Settings, under
|
|
Physics -> Common -> Physics Fps.
|
|
|
|
The function ``_process()``, however, is not synced with physics. Its frame rate is not constant and is dependent
|
|
on hardware and game optimization. Its execution is done after the physics step on single-threaded games.
|
|
|
|
A simple way to test this is to create a scene with a single Label node,
|
|
with the following script:
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
extends Label
|
|
|
|
var accum = 0
|
|
|
|
func _process(delta):
|
|
accum += delta
|
|
text = str(accum) # text is a built-in label property
|
|
|
|
.. code-tab:: csharp
|
|
|
|
public class CustomLabel : Label
|
|
{
|
|
private float _accum;
|
|
|
|
public override void _Process(float delta)
|
|
{
|
|
_accum += delta;
|
|
Text = _accum.ToString();
|
|
}
|
|
}
|
|
|
|
Which will show a counter increasing each frame.
|
|
|
|
Groups
|
|
------
|
|
|
|
Nodes can be added to groups, as many as desired per node, and is a useful feature for organizing large scenes.
|
|
There are two ways to do this. The first is from the UI, from the Groups button under the Node panel:
|
|
|
|
.. image:: img/groups_in_nodes.png
|
|
|
|
And the second way is from code. One example would be to tag scenes
|
|
which are enemies:
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
func _ready():
|
|
add_to_group("enemies")
|
|
|
|
.. code-tab:: csharp
|
|
|
|
public override void _Ready()
|
|
{
|
|
base._Ready();
|
|
|
|
AddToGroup("enemies");
|
|
}
|
|
|
|
This way, if the player is discovered sneaking into a secret base,
|
|
all enemies can be notified about its alarm sounding by using
|
|
:ref:`SceneTree.call_group() <class_SceneTree_call_group>`:
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
func _on_discovered(): # this is a purely illustrative function
|
|
get_tree().call_group("enemies", "player_was_discovered")
|
|
|
|
.. code-tab:: csharp
|
|
|
|
public void _OnDiscovered() // this is a fictional function
|
|
{
|
|
GetTree().CallGroup("enemies", "player_was_discovered");
|
|
}
|
|
|
|
The above code calls the function ``player_was_discovered`` on every
|
|
member of the group ``enemies``.
|
|
|
|
It is also possible to get the full list of ``enemies`` nodes by
|
|
calling
|
|
:ref:`SceneTree.get_nodes_in_group() <class_SceneTree_get_nodes_in_group>`:
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
var enemies = get_tree().get_nodes_in_group("enemies")
|
|
|
|
.. code-tab:: csharp
|
|
|
|
var enemies = GetTree().GetNodesInGroup("enemies");
|
|
|
|
The :ref:`SceneTree <class_SceneTree>` class provides many useful methods,
|
|
like interacting with scenes, their node hierarchy and groups of nodes.
|
|
It allows you to easily switch scenes or reload them,
|
|
to quit the game or pause and unpause it.
|
|
It even comes with interesting signals.
|
|
So check it out if you got some time!
|
|
|
|
Notifications
|
|
-------------
|
|
|
|
Godot has a system of notifications. These are usually not needed for
|
|
scripting, as it's too low-level and virtual functions are provided for
|
|
most of them. It's just good to know they exist. For example,
|
|
you may add an
|
|
:ref:`Object._notification() <class_Object__notification>`
|
|
function in your script:
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
func _notification(what):
|
|
match what:
|
|
NOTIFICATION_READY:
|
|
print("This is the same as overriding _ready()...")
|
|
NOTIFICATION_PROCESS:
|
|
print("This is the same as overriding _process()...")
|
|
|
|
.. code-tab:: csharp
|
|
|
|
public override void _Notification(int what)
|
|
{
|
|
base._Notification(what);
|
|
|
|
switch (what)
|
|
{
|
|
case NotificationReady:
|
|
GD.Print("This is the same as overriding _Ready()...");
|
|
break;
|
|
case NotificationProcess:
|
|
var delta = GetProcessDeltaTime();
|
|
GD.Print("This is the same as overriding _Process()...");
|
|
break;
|
|
}
|
|
}
|
|
|
|
The documentation of each class in the :ref:`Class Reference <toc-class-ref>`
|
|
shows the notifications it can receive. However, in most cases GDScript
|
|
provides simpler overrideable functions.
|
|
|
|
Overrideable functions
|
|
----------------------
|
|
|
|
Such overrideable functions, which are described as
|
|
follows, can be applied to nodes:
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
func _enter_tree():
|
|
# When the node enters the _Scene Tree_, it becomes active
|
|
# and this function is called. Children nodes have not entered
|
|
# the active scene yet. In general, it's better to use _ready()
|
|
# for most cases.
|
|
pass
|
|
|
|
func _ready():
|
|
# This function is called after _enter_tree, but it ensures
|
|
# that all children nodes have also entered the _Scene Tree_,
|
|
# and became active.
|
|
pass
|
|
|
|
func _exit_tree():
|
|
# When the node exits the _Scene Tree_, this function is called.
|
|
# Children nodes have all exited the _Scene Tree_ at this point
|
|
# and all became inactive.
|
|
pass
|
|
|
|
func _process(delta):
|
|
# This function is called every frame.
|
|
pass
|
|
|
|
func _physics_process(delta):
|
|
# This is called every physics frame.
|
|
pass
|
|
|
|
.. code-tab:: csharp
|
|
|
|
public override void _EnterTree()
|
|
{
|
|
// When the node enters the _Scene Tree_, it becomes active
|
|
// and this function is called. Children nodes have not entered
|
|
// the active scene yet. In general, it's better to use _ready()
|
|
// for most cases.
|
|
base._EnterTree();
|
|
}
|
|
|
|
public override void _Ready()
|
|
{
|
|
// This function is called after _enter_tree, but it ensures
|
|
// that all children nodes have also entered the _Scene Tree_,
|
|
// and became active.
|
|
base._Ready();
|
|
}
|
|
|
|
public override void _ExitTree()
|
|
{
|
|
// When the node exits the _Scene Tree_, this function is called.
|
|
// Children nodes have all exited the _Scene Tree_ at this point
|
|
// and all became inactive.
|
|
base._ExitTree();
|
|
}
|
|
|
|
public override void _Process(float delta)
|
|
{
|
|
// This function is called every frame.
|
|
base._Process(delta);
|
|
}
|
|
|
|
public override void _PhysicsProcess(float delta)
|
|
{
|
|
// This is called every physics frame.
|
|
base._PhysicsProcess(delta);
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
When a node is freed, it also frees all its children 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_queue_free>`.
|
|
This erases the node safely during idle.
|
|
|
|
.. tabs::
|
|
.. code-tab:: gdscript GDScript
|
|
|
|
func _someaction():
|
|
s.queue_free() # immediately removes the node from the scene and queues it to be freed at idle time
|
|
|
|
.. code-tab:: csharp
|
|
|
|
public void _SomeAction()
|
|
{
|
|
_sprite.QueueFree(); // immediately removes the node from the scene and queues it to be freed at idle time
|
|
}
|
|
|
|
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 = (PackedScene)ResourceLoader.Load("res://myscene.tscn"); // will load when the script is instanced
|
|
|
|
|
|
Preloading it can be more convenient, as it happens at parse
|
|
time:
|
|
|
|
::
|
|
|
|
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_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.
|