Skip to content

Commit 4ffc007

Browse files
authored
Merge pull request godotengine#7640 from Calinou/update-best-practices
2 parents 064732b + dbcbceb commit 4ffc007

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)