Skip to content

Commit dbcbceb

Browse files
committed
Update Best practices documentation for Godot 4.1
Note that the Data preferences page is still marked as outdated, as the internal implementation of Dictionary/HashMap has changed in Godot 4.0.
1 parent 87dbe4a commit dbcbceb

14 files changed

+202
-178
lines changed

tutorials/best_practices/autoloads_versus_internal_nodes.rst

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
:article_outdated: True
2-
31
.. _doc_autoloads_versus_internal_nodes:
42

53
Autoloads versus regular nodes
64
==============================
75

86
Godot offers a feature to automatically load nodes at the root of your project,
97
allowing you to access them globally, that can fulfill the role of a Singleton:
10-
:ref:`doc_singletons_autoload`. These auto-loaded nodes are not freed when you
8+
:ref:`doc_singletons_autoload`. These autoloaded nodes are not freed when you
119
change the scene from code with :ref:`SceneTree.change_scene_to_file <class_SceneTree_method_change_scene_to_file>`.
1210

1311
In this guide, you will learn when to use the Autoload feature, and techniques
@@ -25,7 +23,7 @@ that play a sound effect. There's a node for that: the :ref:`AudioStreamPlayer
2523
<class_AudioStreamPlayer>`. But if we call the ``AudioStreamPlayer`` while it is
2624
already playing a sound, the new sound interrupts the first.
2725

28-
A solution is to code a global, auto-loaded sound manager class. It generates a
26+
A solution is to code a global, autoloaded sound manager class. It generates a
2927
pool of ``AudioStreamPlayer`` nodes that cycle through as each new request for
3028
sound effects comes in. Say we call that class ``Sound``, you can use it from
3129
anywhere in your project by calling ``Sound.play("coin_pickup.ogg")``. This
@@ -44,7 +42,7 @@ solves the problem in the short term but causes more problems:
4442

4543
.. note::
4644

47-
About global access, the problem is that Any code anywhere could pass wrong
45+
About global access, the problem is that any code anywhere could pass wrong
4846
data to the ``Sound`` autoload in our example. As a result, the domain to
4947
explore to fix the bug spans the entire project.
5048

@@ -82,30 +80,28 @@ When it comes to data, you can either:
8280
When you should use an Autoload
8381
-------------------------------
8482

85-
Auto-loaded nodes can simplify your code in some cases:
86-
87-
- **Static Data**: if you need data that is exclusive to one class, like a
88-
database, then an autoload can be a good tool. There is no scripting API in
89-
Godot to create and manage static data otherwise.
90-
91-
- **Static functions**: creating a library of functions that only return values.
83+
GDScript supports the creation of ``static`` functions using ``static func``.
84+
When combined with ``class_name``, this makes it possible to create libraries of
85+
helper functions without having to create an instance to call them. The
86+
limitation of static functions is that they can't reference member variables,
87+
non-static functions or ``self``.
9288

93-
- **Systems with a wide scope**: If the singleton is managing its own
94-
information and not invading the data of other objects, then it's a great way to
95-
create systems that handle broad-scoped tasks. For example, a quest or a
96-
dialogue system.
89+
Since Godot 4.1, GDScript also supports ``static`` variables using ``static var``.
90+
This means you can now share a variables across instances of a class without
91+
having to create a separate autoload.
9792

98-
Until Godot 3.1, another use was just for convenience: autoloads have a global
99-
variable for their name generated in GDScript, allowing you to call them from
100-
any script file in your project. But now, you can use the ``class_name`` keyword
101-
instead to get auto-completion for a type in your entire project.
93+
Still, autoloaded nodes can simplify your code for systems with a wide scope. If
94+
the autoload is managing its own information and not invading the data of other
95+
objects, then it's a great way to create systems that handle broad-scoped tasks.
96+
For example, a quest or a dialogue system.
10297

10398
.. note::
10499

105-
Autoload is not exactly a Singleton. Nothing prevents you from instantiating
106-
copies of an auto-loaded node. It is only a tool that makes a node load
107-
automatically as a child of the root of your scene tree, regardless of your
108-
game's node structure or which scene you run, e.g. by pressing :kbd:`F6` key.
100+
An autoload is *not* necessarily a singleton. Nothing prevents you from
101+
instantiating copies of an autoloaded node. An autoload is only a tool that
102+
makes a node load automatically as a child of the root of your scene tree,
103+
regardless of your game's node structure or which scene you run, e.g. by
104+
pressing the :kbd:`F6` key.
109105

110-
As a result, you can get the auto-loaded node, for example an autoload called
106+
As a result, you can get the autoloaded node, for example an autoload called
111107
``Sound``, by calling ``get_node("/root/Sound")``.

tutorials/best_practices/data_preferences.rst

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,33 @@ Y or Z? This article covers a variety of topics related to these dilemmas.
1010

1111
.. note::
1212

13-
This article makes references to "[something]-time" operations. This
14-
terminology comes from algorithm analysis'
15-
`Big O Notation <https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/>`_.
16-
17-
Long-story short, it describes the worst-case scenario of runtime length.
18-
In laymen's terms:
19-
20-
"As the size of a problem domain increases, the runtime length of the
21-
algorithm..."
22-
23-
- Constant-time, ``O(1)``: "...does not increase."
24-
- Logarithmic-time, ``O(log n)``: "...increases at a slow rate."
25-
- Linear-time, ``O(n)``: "...increases at the same rate."
26-
- Etc.
27-
28-
Imagine if one had to process 3 million data points within a single frame. It
29-
would be impossible to craft the feature with a linear-time algorithm since
30-
the sheer size of the data would increase the runtime far beyond the time allotted.
31-
In comparison, using a constant-time algorithm could handle the operation without
32-
issue.
33-
34-
By and large, developers want to avoid engaging in linear-time operations as
35-
much as possible. But, if one keeps the scale of a linear-time operation
36-
small, and if one does not need to perform the operation often, then it may
37-
be acceptable. Balancing these requirements and choosing the right
38-
algorithm / data structure for the job is part of what makes programmers'
39-
skills valuable.
13+
This article makes references to "[something]-time" operations. This
14+
terminology comes from algorithm analysis'
15+
`Big O Notation <https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/>`_.
16+
17+
Long-story short, it describes the worst-case scenario of runtime length.
18+
In laymen's terms:
19+
20+
"As the size of a problem domain increases, the runtime length of the
21+
algorithm..."
22+
23+
- Constant-time, ``O(1)``: "...does not increase."
24+
- Logarithmic-time, ``O(log n)``: "...increases at a slow rate."
25+
- Linear-time, ``O(n)``: "...increases at the same rate."
26+
- Etc.
27+
28+
Imagine if one had to process 3 million data points within a single frame. It
29+
would be impossible to craft the feature with a linear-time algorithm since
30+
the sheer size of the data would increase the runtime far beyond the time allotted.
31+
In comparison, using a constant-time algorithm could handle the operation without
32+
issue.
33+
34+
By and large, developers want to avoid engaging in linear-time operations as
35+
much as possible. But, if one keeps the scale of a linear-time operation
36+
small, and if one does not need to perform the operation often, then it may
37+
be acceptable. Balancing these requirements and choosing the right
38+
algorithm / data structure for the job is part of what makes programmers'
39+
skills valuable.
4040

4141
Array vs. Dictionary vs. Object
4242
-------------------------------
@@ -52,12 +52,13 @@ contents in a contiguous section of memory, i.e. they are in a row adjacent
5252
to each other.
5353

5454
.. note::
55-
For those unfamiliar with C++, a Vector is the name of the
56-
array object in traditional C++ libraries. It is a "templated"
57-
type, meaning that its records can only contain a particular type (denoted
58-
by angled brackets). So, for example, a
59-
:ref:`PackedStringArray <class_PackedStringArray>` would be something like
60-
a ``Vector<String>``.
55+
56+
For those unfamiliar with C++, a Vector is the name of the
57+
array object in traditional C++ libraries. It is a "templated"
58+
type, meaning that its records can only contain a particular type (denoted
59+
by angled brackets). So, for example, a
60+
:ref:`PackedStringArray <class_PackedStringArray>` would be something like
61+
a ``Vector<String>``.
6162

6263
Contiguous memory stores imply the following operation performance:
6364

@@ -294,7 +295,7 @@ faster than string comparisons (linear-time). If one wants to keep
294295
up other languages' conventions though, then one should use integers.
295296

296297
The primary issue with using integers comes up when one wants to *print*
297-
an enum value. As integers, attempting to print MY_ENUM will print
298+
an enum value. As integers, attempting to print ``MY_ENUM`` will print
298299
``5`` or what-have-you, rather than something like ``"MyEnum"``. To
299300
print an integer enum, one would have to write a Dictionary that maps the
300301
corresponding string value for each enum.
@@ -314,7 +315,7 @@ The answer may not be immediately clear to new Godot users.
314315
the engine draws as an animated loop rather than a static image.
315316
Users can manipulate...
316317

317-
1. the rate at which it moves across each section of the texture (fps).
318+
1. the rate at which it moves across each section of the texture (FPS).
318319

319320
2. the number of regions contained within the texture (frames).
320321

@@ -346,7 +347,7 @@ the AnimatedSprite2D.
346347
AnimationPlayers are also the tool one will need to use if they wish to design
347348
more complex 2D animation systems, such as...
348349

349-
1. **Cut-Out animations:** editing sprites' transforms at runtime.
350+
1. **Cut-out animations:** editing sprites' transforms at runtime.
350351

351352
2. **2D Mesh animations:** defining a region for the sprite's texture and
352353
rigging a skeleton to it. Then one animates the bones which

tutorials/best_practices/godot_interfaces.rst

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
:article_outdated: True
2-
31
.. _doc_godot_interfaces:
42

53
Godot interfaces
@@ -41,32 +39,36 @@ access.
4139
.. tabs::
4240
.. code-tab:: gdscript GDScript
4341

44-
var preres = preload(path) # Load resource during scene load
45-
var res = load(path) # Load resource when program reaches statement
42+
# If you need an "export const var" (which doesn't exist), use a conditional
43+
# setter for a tool script that checks if it's executing in the editor.
44+
# The `@tool` annotation must be placed at the top of the script.
45+
@tool
46+
47+
# Load resource during scene load.
48+
var preres = preload(path)
49+
# Load resource when program reaches statement.
50+
var res = load(path)
4651

4752
# Note that users load scenes and scripts, by convention, with PascalCase
4853
# names (like typenames), often into constants.
49-
const MyScene : = preload("my_scene.tscn") as PackedScene # Static load
50-
const MyScript : = preload("my_script.gd") as Script
54+
const MyScene = preload("my_scene.tscn") # Static load
55+
const MyScript = preload("my_script.gd")
5156

5257
# This type's value varies, i.e. it is a variable, so it uses snake_case.
53-
export(Script) var script_type: Script
54-
55-
# If need an "export const var" (which doesn't exist), use a conditional
56-
# setter for a tool script that checks if it's executing in the editor.
57-
tool # Must place at top of file.
58+
@export var script_type: Script
5859

5960
# Must configure from the editor, defaults to null.
60-
export(Script) var const_script setget set_const_script
61-
func set_const_script(value):
62-
if Engine.is_editor_hint():
63-
const_script = value
61+
export var const_script: Script:
62+
set(value):
63+
if Engine.is_editor_hint():
64+
const_script = value
6465

6566
# Warn users if the value hasn't been set.
66-
func _get_configuration_warning():
67+
func _get_configuration_warnings():
6768
if not const_script:
68-
return "Must initialize property 'const_script'."
69-
return ""
69+
return ["Must initialize property 'const_script'."]
70+
71+
return []
7072

7173
.. code-tab:: csharp
7274

@@ -106,7 +108,7 @@ access.
106108
};
107109

108110
// Warn users if the value hasn't been set.
109-
public String _GetConfigurationWarning()
111+
public String _GetConfigurationWarnings()
110112
{
111113
if (EnemyScn == null)
112114
return "Must initialize property 'EnemyScn'.";
@@ -142,7 +144,7 @@ Nodes likewise have an alternative access point: the SceneTree.
142144
print($Child)
143145

144146
# Fastest. Doesn't break if node moves later.
145-
# Note that `@onready` annotation is GDScript only.
147+
# Note that `@onready` annotation is GDScript-only.
146148
# Other languages must do...
147149
# var child
148150
# func _ready():
@@ -151,6 +153,12 @@ Nodes likewise have an alternative access point: the SceneTree.
151153
func lookup_and_cache_for_future_access():
152154
print(child)
153155

156+
# Fastest. Doesn't break if node is moved in the Scene tree dock.
157+
# Node must be selected in the inspector as it's an exported property.
158+
@export var child: Node
159+
func lookup_and_cache_for_future_access():
160+
print(child)
161+
154162
# Delegate reference assignment to an external source.
155163
# Con: need to perform a validation check.
156164
# Pro: node makes no requirements of its external structure.
@@ -169,8 +177,7 @@ Nodes likewise have an alternative access point: the SceneTree.
169177
return
170178

171179
# Fail and terminate.
172-
# Note: Scripts run from a release export template don't
173-
# run `assert` statements.
180+
# NOTE: Scripts run from a release export template don't run `assert`s.
174181
assert(prop, "'prop' wasn't initialized")
175182

176183
# Use an autoload.
@@ -236,8 +243,7 @@ Nodes likewise have an alternative access point: the SceneTree.
236243
}
237244

238245
// Fail and terminate.
239-
// Note: Scripts run from a release export template don't
240-
// run `Debug.Assert` statements.
246+
// Note: Scripts run from a release export template don't run `Debug.Assert`s.
241247
Debug.Assert(Prop, "'Prop' wasn't initialized");
242248
}
243249

@@ -287,10 +293,8 @@ following checks, in order:
287293
execute logic that gives the impression that the Object has a property. This
288294
is also the case with the ``_get_property_list`` method.
289295

290-
- Note that this happens even for non-legal symbol names such as in the
291-
case of :ref:`TileSet <class_TileSet>`'s "1/tile_name" property. This
292-
refers to the name of the tile with ID 1, i.e.
293-
``TileSet.tile_get_name(1)``.
296+
- Note that this happens even for non-legal symbol names, such as names
297+
starting with a digit or containing a slash.
294298

295299
As a result, this duck-typed system can locate a property either in the script,
296300
the object's class, or any class that object inherits, but only for things

0 commit comments

Comments
 (0)