ソースを参照

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.
Hugo Locurcio 2 年 前
コミット
dbcbceb4bc

+ 21 - 25
tutorials/best_practices/autoloads_versus_internal_nodes.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_autoloads_versus_internal_nodes:
 .. _doc_autoloads_versus_internal_nodes:
 
 
 Autoloads versus regular nodes
 Autoloads versus regular nodes
@@ -7,7 +5,7 @@ Autoloads versus regular nodes
 
 
 Godot offers a feature to automatically load nodes at the root of your project,
 Godot offers a feature to automatically load nodes at the root of your project,
 allowing you to access them globally, that can fulfill the role of a Singleton:
 allowing you to access them globally, that can fulfill the role of a Singleton:
-:ref:`doc_singletons_autoload`. These auto-loaded nodes are not freed when you
+:ref:`doc_singletons_autoload`. These autoloaded nodes are not freed when you
 change the scene from code with :ref:`SceneTree.change_scene_to_file <class_SceneTree_method_change_scene_to_file>`.
 change the scene from code with :ref:`SceneTree.change_scene_to_file <class_SceneTree_method_change_scene_to_file>`.
 
 
 In this guide, you will learn when to use the Autoload feature, and techniques
 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
 <class_AudioStreamPlayer>`. But if we call the ``AudioStreamPlayer`` while it is
 <class_AudioStreamPlayer>`. But if we call the ``AudioStreamPlayer`` while it is
 already playing a sound, the new sound interrupts the first.
 already playing a sound, the new sound interrupts the first.
 
 
-A solution is to code a global, auto-loaded sound manager class. It generates a
+A solution is to code a global, autoloaded sound manager class. It generates a
 pool of ``AudioStreamPlayer`` nodes that cycle through as each new request for
 pool of ``AudioStreamPlayer`` nodes that cycle through as each new request for
 sound effects comes in. Say we call that class ``Sound``, you can use it from
 sound effects comes in. Say we call that class ``Sound``, you can use it from
 anywhere in your project by calling ``Sound.play("coin_pickup.ogg")``. This
 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:
 
 
 .. note::
 .. note::
 
 
-   About global access, the problem is that Any code anywhere could pass wrong
+   About global access, the problem is that any code anywhere could pass wrong
    data to the ``Sound`` autoload in our example. As a result, the domain to
    data to the ``Sound`` autoload in our example. As a result, the domain to
    explore to fix the bug spans the entire project.
    explore to fix the bug spans the entire project.
 
 
@@ -82,30 +80,28 @@ When it comes to data, you can either:
 When you should use an Autoload
 When you should use an Autoload
 -------------------------------
 -------------------------------
 
 
-Auto-loaded nodes can simplify your code in some cases:
-
-- **Static Data**: if you need data that is exclusive to one class, like a
-  database, then an autoload can be a good tool. There is no scripting API in
-  Godot to create and manage static data otherwise.
-
-- **Static functions**: creating a library of functions that only return values.
+GDScript supports the creation of ``static`` functions using ``static func``.
+When combined with ``class_name``, this makes it possible to create libraries of
+helper functions without having to create an instance to call them. The
+limitation of static functions is that they can't reference member variables,
+non-static functions or ``self``.
 
 
-- **Systems with a wide scope**: If the singleton is managing its own
-  information and not invading the data of other objects, then it's a great way to
-  create systems that handle broad-scoped tasks. For example, a quest or a
-  dialogue system.
+Since Godot 4.1, GDScript also supports ``static`` variables using ``static var``.
+This means you can now share a variables across instances of a class without
+having to create a separate autoload.
 
 
-Until Godot 3.1, another use was just for convenience: autoloads have a global
-variable for their name generated in GDScript, allowing you to call them from
-any script file in your project. But now, you can use the ``class_name`` keyword
-instead to get auto-completion for a type in your entire project.
+Still, autoloaded nodes can simplify your code for systems with a wide scope. If
+the autoload is managing its own information and not invading the data of other
+objects, then it's a great way to create systems that handle broad-scoped tasks.
+For example, a quest or a dialogue system.
 
 
 .. note::
 .. note::
 
 
-   Autoload is not exactly a Singleton. Nothing prevents you from instantiating
-   copies of an auto-loaded node. It is only a tool that makes a node load
-   automatically as a child of the root of your scene tree, regardless of your
-   game's node structure or which scene you run, e.g. by pressing :kbd:`F6` key.
+   An autoload is *not* necessarily a singleton. Nothing prevents you from
+   instantiating copies of an autoloaded node. An autoload is only a tool that
+   makes a node load automatically as a child of the root of your scene tree,
+   regardless of your game's node structure or which scene you run, e.g. by
+   pressing the :kbd:`F6` key.
 
 
-   As a result, you can get the auto-loaded node, for example an autoload called
+   As a result, you can get the autoloaded node, for example an autoload called
    ``Sound``, by calling ``get_node("/root/Sound")``.
    ``Sound``, by calling ``get_node("/root/Sound")``.

+ 37 - 36
tutorials/best_practices/data_preferences.rst

@@ -10,33 +10,33 @@ Y or Z? This article covers a variety of topics related to these dilemmas.
 
 
 .. note::
 .. note::
 
 
-  This article makes references to "[something]-time" operations. This
-  terminology comes from algorithm analysis'
-  `Big O Notation <https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/>`_.
-
-  Long-story short, it describes the worst-case scenario of runtime length.
-  In laymen's terms:
-
-  "As the size of a problem domain increases, the runtime length of the
-  algorithm..."
-
-  - Constant-time, ``O(1)``: "...does not increase."
-  - Logarithmic-time, ``O(log n)``: "...increases at a slow rate."
-  - Linear-time, ``O(n)``: "...increases at the same rate."
-  - Etc.
-
-  Imagine if one had to process 3 million data points within a single frame. It
-  would be impossible to craft the feature with a linear-time algorithm since
-  the sheer size of the data would increase the runtime far beyond the time allotted.
-  In comparison, using a constant-time algorithm could handle the operation without
-  issue.
-
-  By and large, developers want to avoid engaging in linear-time operations as
-  much as possible. But, if one keeps the scale of a linear-time operation
-  small, and if one does not need to perform the operation often, then it may
-  be acceptable. Balancing these requirements and choosing the right
-  algorithm / data structure for the job is part of what makes programmers'
-  skills valuable.
+    This article makes references to "[something]-time" operations. This
+    terminology comes from algorithm analysis'
+    `Big O Notation <https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/>`_.
+
+    Long-story short, it describes the worst-case scenario of runtime length.
+    In laymen's terms:
+
+    "As the size of a problem domain increases, the runtime length of the
+    algorithm..."
+
+    - Constant-time, ``O(1)``: "...does not increase."
+    - Logarithmic-time, ``O(log n)``: "...increases at a slow rate."
+    - Linear-time, ``O(n)``: "...increases at the same rate."
+    - Etc.
+
+    Imagine if one had to process 3 million data points within a single frame. It
+    would be impossible to craft the feature with a linear-time algorithm since
+    the sheer size of the data would increase the runtime far beyond the time allotted.
+    In comparison, using a constant-time algorithm could handle the operation without
+    issue.
+
+    By and large, developers want to avoid engaging in linear-time operations as
+    much as possible. But, if one keeps the scale of a linear-time operation
+    small, and if one does not need to perform the operation often, then it may
+    be acceptable. Balancing these requirements and choosing the right
+    algorithm / data structure for the job is part of what makes programmers'
+    skills valuable.
 
 
 Array vs. Dictionary vs. Object
 Array vs. Dictionary vs. Object
 -------------------------------
 -------------------------------
@@ -52,12 +52,13 @@ contents in a contiguous section of memory, i.e. they are in a row adjacent
 to each other.
 to each other.
 
 
 .. note::
 .. note::
-  For those unfamiliar with C++, a Vector is the name of the
-  array object in traditional C++ libraries. It is a "templated"
-  type, meaning that its records can only contain a particular type (denoted
-  by angled brackets). So, for example, a
-  :ref:`PackedStringArray <class_PackedStringArray>` would be something like
-  a ``Vector<String>``.
+
+    For those unfamiliar with C++, a Vector is the name of the
+    array object in traditional C++ libraries. It is a "templated"
+    type, meaning that its records can only contain a particular type (denoted
+    by angled brackets). So, for example, a
+    :ref:`PackedStringArray <class_PackedStringArray>` would be something like
+    a ``Vector<String>``.
 
 
 Contiguous memory stores imply the following operation performance:
 Contiguous memory stores imply the following operation performance:
 
 
@@ -294,7 +295,7 @@ faster than string comparisons (linear-time). If one wants to keep
 up other languages' conventions though, then one should use integers.
 up other languages' conventions though, then one should use integers.
 
 
 The primary issue with using integers comes up when one wants to *print*
 The primary issue with using integers comes up when one wants to *print*
-an enum value. As integers, attempting to print MY_ENUM will print
+an enum value. As integers, attempting to print ``MY_ENUM`` will print
 ``5`` or what-have-you, rather than something like ``"MyEnum"``. To
 ``5`` or what-have-you, rather than something like ``"MyEnum"``. To
 print an integer enum, one would have to write a Dictionary that maps the
 print an integer enum, one would have to write a Dictionary that maps the
 corresponding string value for each enum.
 corresponding string value for each enum.
@@ -314,7 +315,7 @@ The answer may not be immediately clear to new Godot users.
 the engine draws as an animated loop rather than a static image.
 the engine draws as an animated loop rather than a static image.
 Users can manipulate...
 Users can manipulate...
 
 
-1. the rate at which it moves across each section of the texture (fps).
+1. the rate at which it moves across each section of the texture (FPS).
 
 
 2. the number of regions contained within the texture (frames).
 2. the number of regions contained within the texture (frames).
 
 
@@ -346,7 +347,7 @@ the AnimatedSprite2D.
 AnimationPlayers are also the tool one will need to use if they wish to design
 AnimationPlayers are also the tool one will need to use if they wish to design
 more complex 2D animation systems, such as...
 more complex 2D animation systems, such as...
 
 
-1. **Cut-Out animations:** editing sprites' transforms at runtime.
+1. **Cut-out animations:** editing sprites' transforms at runtime.
 
 
 2. **2D Mesh animations:** defining a region for the sprite's texture and
 2. **2D Mesh animations:** defining a region for the sprite's texture and
    rigging a skeleton to it. Then one animates the bones which
    rigging a skeleton to it. Then one animates the bones which

+ 32 - 28
tutorials/best_practices/godot_interfaces.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_godot_interfaces:
 .. _doc_godot_interfaces:
 
 
 Godot interfaces
 Godot interfaces
@@ -41,32 +39,36 @@ access.
 .. tabs::
 .. tabs::
   .. code-tab:: gdscript GDScript
   .. code-tab:: gdscript GDScript
 
 
-    var preres = preload(path) # Load resource during scene load
-    var res = load(path) # Load resource when program reaches statement
+    # If you need an "export const var" (which doesn't exist), use a conditional
+    # setter for a tool script that checks if it's executing in the editor.
+    # The `@tool` annotation must be placed at the top of the script.
+    @tool
+
+    # Load resource during scene load.
+    var preres = preload(path)
+    # Load resource when program reaches statement.
+    var res = load(path)
 
 
     # Note that users load scenes and scripts, by convention, with PascalCase
     # Note that users load scenes and scripts, by convention, with PascalCase
     # names (like typenames), often into constants.
     # names (like typenames), often into constants.
-    const MyScene : = preload("my_scene.tscn") as PackedScene # Static load
-    const MyScript : = preload("my_script.gd") as Script
+    const MyScene = preload("my_scene.tscn") # Static load
+    const MyScript = preload("my_script.gd")
 
 
     # This type's value varies, i.e. it is a variable, so it uses snake_case.
     # This type's value varies, i.e. it is a variable, so it uses snake_case.
-    export(Script) var script_type: Script
-
-    # If need an "export const var" (which doesn't exist), use a conditional
-    # setter for a tool script that checks if it's executing in the editor.
-    tool # Must place at top of file.
+    @export var script_type: Script
 
 
     # Must configure from the editor, defaults to null.
     # Must configure from the editor, defaults to null.
-    export(Script) var const_script setget set_const_script
-    func set_const_script(value):
-        if Engine.is_editor_hint():
-            const_script = value
+    export var const_script: Script:
+        set(value):
+            if Engine.is_editor_hint():
+                const_script = value
 
 
     # Warn users if the value hasn't been set.
     # Warn users if the value hasn't been set.
-    func _get_configuration_warning():
+    func _get_configuration_warnings():
         if not const_script:
         if not const_script:
-            return "Must initialize property 'const_script'."
-        return ""
+            return ["Must initialize property 'const_script'."]
+
+        return []
 
 
   .. code-tab:: csharp
   .. code-tab:: csharp
 
 
@@ -106,7 +108,7 @@ access.
         };
         };
 
 
         // Warn users if the value hasn't been set.
         // Warn users if the value hasn't been set.
-        public String _GetConfigurationWarning()
+        public String _GetConfigurationWarnings()
         {
         {
             if (EnemyScn == null)
             if (EnemyScn == null)
                 return "Must initialize property 'EnemyScn'.";
                 return "Must initialize property 'EnemyScn'.";
@@ -142,7 +144,7 @@ Nodes likewise have an alternative access point: the SceneTree.
         print($Child)
         print($Child)
 
 
     # Fastest. Doesn't break if node moves later.
     # Fastest. Doesn't break if node moves later.
-    # Note that `@onready` annotation is GDScript only.
+    # Note that `@onready` annotation is GDScript-only.
     # Other languages must do...
     # Other languages must do...
     #     var child
     #     var child
     #     func _ready():
     #     func _ready():
@@ -151,6 +153,12 @@ Nodes likewise have an alternative access point: the SceneTree.
     func lookup_and_cache_for_future_access():
     func lookup_and_cache_for_future_access():
         print(child)
         print(child)
 
 
+    # Fastest. Doesn't break if node is moved in the Scene tree dock.
+    # Node must be selected in the inspector as it's an exported property.
+    @export var child: Node
+    func lookup_and_cache_for_future_access():
+        print(child)
+
     # Delegate reference assignment to an external source.
     # Delegate reference assignment to an external source.
     # Con: need to perform a validation check.
     # Con: need to perform a validation check.
     # Pro: node makes no requirements of its external structure.
     # Pro: node makes no requirements of its external structure.
@@ -169,8 +177,7 @@ Nodes likewise have an alternative access point: the SceneTree.
             return
             return
 
 
         # Fail and terminate.
         # Fail and terminate.
-        # Note: Scripts run from a release export template don't
-        # run `assert` statements.
+        # NOTE: Scripts run from a release export template don't run `assert`s.
         assert(prop, "'prop' wasn't initialized")
         assert(prop, "'prop' wasn't initialized")
 
 
     # Use an autoload.
     # Use an autoload.
@@ -236,8 +243,7 @@ Nodes likewise have an alternative access point: the SceneTree.
             }
             }
 
 
             // Fail and terminate.
             // Fail and terminate.
-            // Note: Scripts run from a release export template don't
-            // run `Debug.Assert` statements.
+            // Note: Scripts run from a release export template don't run `Debug.Assert`s.
             Debug.Assert(Prop, "'Prop' wasn't initialized");
             Debug.Assert(Prop, "'Prop' wasn't initialized");
         }
         }
 
 
@@ -287,10 +293,8 @@ following checks, in order:
   execute logic that gives the impression that the Object has a property. This
   execute logic that gives the impression that the Object has a property. This
   is also the case with the ``_get_property_list`` method.
   is also the case with the ``_get_property_list`` method.
 
 
-  - Note that this happens even for non-legal symbol names such as in the
-    case of :ref:`TileSet <class_TileSet>`'s "1/tile_name" property. This
-    refers to the name of the tile with ID 1, i.e.
-    ``TileSet.tile_get_name(1)``.
+  - Note that this happens even for non-legal symbol names, such as names
+    starting with a digit or containing a slash.
 
 
 As a result, this duck-typed system can locate a property either in the script,
 As a result, this duck-typed system can locate a property either in the script,
 the object's class, or any class that object inherits, but only for things
 the object's class, or any class that object inherits, but only for things

+ 31 - 30
tutorials/best_practices/godot_notifications.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_godot_notifications:
 .. _doc_godot_notifications:
 
 
 Godot notifications
 Godot notifications
@@ -15,17 +13,17 @@ relate to it. For example, if the engine tells a
 Some of these notifications, like draw, are useful to override in scripts. So
 Some of these notifications, like draw, are useful to override in scripts. So
 much so that Godot exposes many of them with dedicated functions:
 much so that Godot exposes many of them with dedicated functions:
 
 
-- ``_ready()`` : NOTIFICATION_READY
+- ``_ready()``: ``NOTIFICATION_READY``
 
 
-- ``_enter_tree()`` : NOTIFICATION_ENTER_TREE
+- ``_enter_tree()``: ``NOTIFICATION_ENTER_TREE``
 
 
-- ``_exit_tree()`` : NOTIFICATION_EXIT_TREE
+- ``_exit_tree()``: ``NOTIFICATION_EXIT_TREE``
 
 
-- ``_process(delta)`` : NOTIFICATION_PROCESS
+- ``_process(delta)``: ``NOTIFICATION_PROCESS``
 
 
-- ``_physics_process(delta)`` : NOTIFICATION_PHYSICS_PROCESS
+- ``_physics_process(delta)``: ``NOTIFICATION_PHYSICS_PROCESS``
 
 
-- ``_draw()`` : NOTIFICATION_DRAW
+- ``_draw()``: ``NOTIFICATION_DRAW``
 
 
 What users might *not* realize is that notifications exist for types other
 What users might *not* realize is that notifications exist for types other
 than Node alone, for example:
 than Node alone, for example:
@@ -35,7 +33,7 @@ than Node alone, for example:
 
 
 - :ref:`Object::NOTIFICATION_PREDELETE <class_Object_constant_NOTIFICATION_PREDELETE>`:
 - :ref:`Object::NOTIFICATION_PREDELETE <class_Object_constant_NOTIFICATION_PREDELETE>`:
   a callback that triggers before the engine deletes an Object, i.e. a
   a callback that triggers before the engine deletes an Object, i.e. a
-  'destructor'.
+  "destructor".
 
 
 And many of the callbacks that *do* exist in Nodes don't have any dedicated
 And many of the callbacks that *do* exist in Nodes don't have any dedicated
 methods, but are still quite useful.
 methods, but are still quite useful.
@@ -48,7 +46,7 @@ methods, but are still quite useful.
   node.
   node.
 
 
 One can access all these custom notifications from the universal
 One can access all these custom notifications from the universal
-``_notification`` method.
+``_notification()`` method.
 
 
 .. note::
 .. note::
   Methods in the documentation labeled as "virtual" are also intended to be
   Methods in the documentation labeled as "virtual" are also intended to be
@@ -65,38 +63,41 @@ virtual functions?
 _process vs. _physics_process vs. \*_input
 _process vs. _physics_process vs. \*_input
 ------------------------------------------
 ------------------------------------------
 
 
-Use ``_process`` when one needs a framerate-dependent deltatime between
+Use ``_process()`` when one needs a framerate-dependent delta time between
 frames. If code that updates object data needs to update as often as
 frames. If code that updates object data needs to update as often as
 possible, this is the right place. Recurring logic checks and data caching
 possible, this is the right place. Recurring logic checks and data caching
 often execute here, but it comes down to the frequency at which one needs
 often execute here, but it comes down to the frequency at which one needs
 the evaluations to update. If they don't need to execute every frame, then
 the evaluations to update. If they don't need to execute every frame, then
-implementing a Timer-yield-timeout loop is another option.
+implementing a Timer-timeout loop is another option.
 
 
 .. tabs::
 .. tabs::
  .. code-tab:: gdscript GDScript
  .. code-tab:: gdscript GDScript
 
 
-    # Infinitely loop, but only execute whenever the Timer fires.
     # Allows for recurring operations that don't trigger script logic
     # Allows for recurring operations that don't trigger script logic
     # every frame (or even every fixed frame).
     # every frame (or even every fixed frame).
-    while true:
-        my_method()
-        $Timer.start()
-        yield($Timer, "timeout")
-
-Use ``_physics_process`` when one needs a framerate-independent deltatime
+    func _ready():
+        var timer = Timer.new()
+        timer.autostart = true
+        timer.wait_time = 0.5
+        add_child(timer)
+        timer.timeout.connect(func():
+            print("This block runs every 0.5 seconds")
+        )
+
+Use ``_physics_process()`` when one needs a framerate-independent delta time
 between frames. If code needs consistent updates over time, regardless
 between frames. If code needs consistent updates over time, regardless
 of how fast or slow time advances, this is the right place.
 of how fast or slow time advances, this is the right place.
 Recurring kinematic and object transform operations should execute here.
 Recurring kinematic and object transform operations should execute here.
 
 
 While it is possible, to achieve the best performance, one should avoid
 While it is possible, to achieve the best performance, one should avoid
-making input checks during these callbacks. ``_process`` and
-``_physics_process`` will trigger at every opportunity (they do not "rest" by
-default). In contrast, ``*_input`` callbacks will trigger only on frames in
+making input checks during these callbacks. ``_process()`` and
+``_physics_process()`` will trigger at every opportunity (they do not "rest" by
+default). In contrast, ``*_input()`` callbacks will trigger only on frames in
 which the engine has actually detected the input.
 which the engine has actually detected the input.
 
 
 One can check for input actions within the input callbacks just the same.
 One can check for input actions within the input callbacks just the same.
 If one wants to use delta time, one can fetch it from the related
 If one wants to use delta time, one can fetch it from the related
-deltatime methods as needed.
+delta time methods as needed.
 
 
 .. tabs::
 .. tabs::
   .. code-tab:: gdscript GDScript
   .. code-tab:: gdscript GDScript
@@ -146,8 +147,8 @@ _init vs. initialization vs. export
 
 
 If the script initializes its own node subtree, without a scene,
 If the script initializes its own node subtree, without a scene,
 that code should execute here. Other property or SceneTree-independent
 that code should execute here. Other property or SceneTree-independent
-initializations should also run here. This triggers before ``_ready`` or
-``_enter_tree``, but after a script creates and initializes its properties.
+initializations should also run here. This triggers before ``_ready()`` or
+``_enter_tree()``, but after a script creates and initializes its properties.
 
 
 Scripts have three types of property assignments that can occur during
 Scripts have three types of property assignments that can occur during
 instantiation:
 instantiation:
@@ -216,16 +217,16 @@ _ready vs. _enter_tree vs. NOTIFICATION_PARENTED
 ------------------------------------------------
 ------------------------------------------------
 
 
 When instantiating a scene connected to the first executed scene, Godot will
 When instantiating a scene connected to the first executed scene, Godot will
-instantiate nodes down the tree (making ``_init`` calls) and build the tree
-going downwards from the root. This causes ``_enter_tree`` calls to cascade
+instantiate nodes down the tree (making ``_init()`` calls) and build the tree
+going downwards from the root. This causes ``_enter_tree()`` calls to cascade
 down the tree. Once the tree is complete, leaf nodes call ``_ready``. A node
 down the tree. Once the tree is complete, leaf nodes call ``_ready``. A node
 will call this method once all child nodes have finished calling theirs. This
 will call this method once all child nodes have finished calling theirs. This
 then causes a reverse cascade going up back to the tree's root.
 then causes a reverse cascade going up back to the tree's root.
 
 
 When instantiating a script or a standalone scene, nodes are not
 When instantiating a script or a standalone scene, nodes are not
-added to the SceneTree upon creation, so no ``_enter_tree`` callbacks
-trigger. Instead, only the ``_init`` call occurs. When the scene is added
-to the SceneTree, the ``_enter_tree`` and ``_ready`` calls occur.
+added to the SceneTree upon creation, so no ``_enter_tree()`` callbacks
+trigger. Instead, only the ``_init()`` call occurs. When the scene is added
+to the SceneTree, the ``_enter_tree()`` and ``_ready()`` calls occur.
 
 
 If one needs to trigger behavior that occurs as nodes parent to another,
 If one needs to trigger behavior that occurs as nodes parent to another,
 regardless of whether it occurs as part of the main/active scene or not, one
 regardless of whether it occurs as part of the main/active scene or not, one

BIN
tutorials/best_practices/img/version_control_menu.png


BIN
tutorials/best_practices/img/version_control_systems_generate_metadata.webp


+ 0 - 2
tutorials/best_practices/index.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 Best practices
 Best practices
 ==============
 ==============
 
 

+ 0 - 2
tutorials/best_practices/introduction_best_practices.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_introduction_best_practices:
 .. _doc_introduction_best_practices:
 
 
 Introduction
 Introduction

+ 2 - 4
tutorials/best_practices/logic_preferences.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_logic_preferences:
 .. _doc_logic_preferences:
 
 
 Logic preferences
 Logic preferences
@@ -35,7 +33,7 @@ resources while in the middle of performance-sensitive code.
 Its counterpart, the :ref:`load <class_@GDScript_method_load>` method, loads a
 Its counterpart, the :ref:`load <class_@GDScript_method_load>` method, loads a
 resource only when it reaches the load statement. That is, it will load a
 resource only when it reaches the load statement. That is, it will load a
 resource in-place which can cause slowdowns when it occurs in the middle of
 resource in-place which can cause slowdowns when it occurs in the middle of
-sensitive processes. The ``load`` function is also an alias for
+sensitive processes. The ``load()`` function is also an alias for
 :ref:`ResourceLoader.load(path) <class_ResourceLoader_method_load>` which is
 :ref:`ResourceLoader.load(path) <class_ResourceLoader_method_load>` which is
 accessible to *all* scripting languages.
 accessible to *all* scripting languages.
 
 
@@ -121,7 +119,7 @@ consider:
    in exceptional cases, one may wish not to do this:
    in exceptional cases, one may wish not to do this:
 
 
    1. If the 'imported' class is liable to change, then it should be a property
    1. If the 'imported' class is liable to change, then it should be a property
-      instead, initialized either using an ``export`` or a ``load`` (and
+      instead, initialized either using an ``export`` or a ``load()`` (and
       perhaps not even initialized until later).
       perhaps not even initialized until later).
 
 
    2. If the script requires a great many dependencies, and one does not wish
    2. If the script requires a great many dependencies, and one does not wish

+ 6 - 7
tutorials/best_practices/node_alternatives.rst

@@ -1,11 +1,8 @@
-:article_outdated: True
-
 .. _doc_node_alternatives:
 .. _doc_node_alternatives:
 
 
 When and how to avoid using nodes for everything
 When and how to avoid using nodes for everything
 ================================================
 ================================================
 
 
-
 Nodes are cheap to produce, but even they have their limits. A project may
 Nodes are cheap to produce, but even they have their limits. A project may
 have tens of thousands of nodes all doing things. The more complex their
 have tens of thousands of nodes all doing things. The more complex their
 behavior though, the larger the strain each one adds to a project's
 behavior though, the larger the strain each one adds to a project's
@@ -30,10 +27,12 @@ your project's features.
      entire Node library, one creates an abbreviated set of Objects from which
      entire Node library, one creates an abbreviated set of Objects from which
      a node can generate and manage the appropriate sub-nodes.
      a node can generate and manage the appropriate sub-nodes.
 
 
-   .. note:: One should be careful when handling them. One can store an Object
-     into a variable, but these references can become invalid without warning.
-     For example, if the object's creator decides to delete it out of nowhere,
-     this would trigger an error state when one next accesses it.
+   .. note::
+
+       One should be careful when handling them. One can store an Object
+       into a variable, but these references can become invalid without warning.
+       For example, if the object's creator decides to delete it out of nowhere,
+       this would trigger an error state when one next accesses it.
 
 
 2. :ref:`RefCounted <class_RefCounted>`: Only a little more complex than Object.
 2. :ref:`RefCounted <class_RefCounted>`: Only a little more complex than Object.
    They track references to themselves, only deleting loaded memory when no
    They track references to themselves, only deleting loaded memory when no

+ 4 - 6
tutorials/best_practices/scene_organization.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_scene_organization:
 .. _doc_scene_organization:
 
 
 Scene organization
 Scene organization
@@ -52,7 +50,7 @@ To do this, one must expose data and then rely on a parent context to
 initialize it:
 initialize it:
 
 
 1. Connect to a signal. Extremely safe, but should be used only to "respond" to
 1. Connect to a signal. Extremely safe, but should be used only to "respond" to
-   behavior, not start it. Note that signal names are usually past-tense verbs
+   behavior, not start it. By convention, signal names are usually past-tense verbs
    like "entered", "skill_activated", or "item_collected".
    like "entered", "skill_activated", or "item_collected".
 
 
    .. tabs::
    .. tabs::
@@ -219,9 +217,9 @@ in another context without any extra changes to its API.
 
 
   To avoid creating and maintaining such documentation, one converts the
   To avoid creating and maintaining such documentation, one converts the
   dependent node ("child" above) into a tool script that implements
   dependent node ("child" above) into a tool script that implements
-  ``_get_configuration_warning()``.
-  Returning a non-empty string from it will make the Scene dock generate a
-  warning icon with the string as a tooltip by the node. This is the same icon
+  ``_get_configuration_warnings()``.
+  Returning a non-empty PackedStringArray from it will make the Scene dock generate a
+  warning icon with the string(s) as a tooltip by the node. This is the same icon
   that appears for nodes such as the
   that appears for nodes such as the
   :ref:`Area2D <class_Area2D>` node when it has no child
   :ref:`Area2D <class_Area2D>` node when it has no child
   :ref:`CollisionShape2D <class_CollisionShape2D>` nodes defined. The editor
   :ref:`CollisionShape2D <class_CollisionShape2D>` nodes defined. The editor

+ 1 - 3
tutorials/best_practices/scenes_versus_scripts.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_scenes_versus_scripts:
 .. _doc_scenes_versus_scripts:
 
 
 When to use scenes versus scripts
 When to use scenes versus scripts
@@ -202,7 +200,7 @@ In the end, the best approach is to consider the following:
   security than scripts.
   security than scripts.
 
 
 - If one would like to give a name to a scene, then they can still sort of do
 - If one would like to give a name to a scene, then they can still sort of do
-  this in 3.1 by declaring a script class and giving it a scene as a constant.
+  this by declaring a script class and giving it a scene as a constant.
   The script becomes, in effect, a namespace:
   The script becomes, in effect, a namespace:
 
 
   .. tabs::
   .. tabs::

+ 63 - 28
tutorials/best_practices/version_control_systems.rst

@@ -1,54 +1,89 @@
-:article_outdated: True
-
 .. _doc_version_control_systems:
 .. _doc_version_control_systems:
 
 
-Version Control Systems
+Version control systems
 =======================
 =======================
 
 
 Introduction
 Introduction
 ------------
 ------------
 
 
-Godot aims to be VCS friendly and generate mostly readable and mergeable files.
+Godot aims to be VCS-friendly and generate mostly readable and mergeable files.
+
+Version control plugins
+-----------------------
+
 Godot also supports the use of version control systems in the editor itself.
 Godot also supports the use of version control systems in the editor itself.
-However, VCS in the editor requires a plugin for the specific VCS you are using.
-VCS can be setup or shut down in the editor under **Project > Version Control**.
+However, version control in the editor requires a plugin for the specific VCS
+you're using.
 
 
-.. image:: img/version_control_menu.png
+As of July 2023, there is only a Git plugin available, but the community may
+create additional VCS plugins.
 
 
 Official Git plugin
 Official Git plugin
--------------------
+^^^^^^^^^^^^^^^^^^^
+
+.. warning::
+
+    As of July 2023, the Git plugin hasn't been updated to work with Godot 4.1
+    and later yet.
 
 
 Using Git from inside the editor is supported with an official plugin.
 Using Git from inside the editor is supported with an official plugin.
-You can find the latest releases
-`here <https://github.com/godotengine/godot-git-plugin/releases>`__. Documentation on how to use the Git
-plugin can be found
-`here <https://github.com/godotengine/godot-git-plugin/wiki>`__.
+You can find the latest releases on
+`GitHub <https://github.com/godotengine/godot-git-plugin/releases>`__.
+
+Documentation on how to use the Git plugin can be found on its
+`wiki <https://github.com/godotengine/godot-git-plugin/wiki>`__.
 
 
 Files to exclude from VCS
 Files to exclude from VCS
 -------------------------
 -------------------------
 
 
-There are some files and folders Godot automatically creates. You should add them to your VCS ignore:
+.. note::
+
+    This lists files and folders that should be ignored from version control in
+    Godot 4.1 and later.
+
+    The list of files of folders that should be ignored from version control in
+    Godot 3.x and Godot 4.0 is **entirely** different. This is important, as Godot
+    3.x and 4.0 may store sensitive credentials in ``export_presets.cfg`` (unlike Godot
+    4.1 and later).
 
 
-- ``.godot/``: This folder stores various project cache data. ``.godot/imported/`` stores
-  all the files the engine imports automatically based on your source assets and their
-  import flags. ``.godot/editor/`` holds data regarding the editor state, such as currently
-  opened script files, and recently used nodes.
-- ``*.translation``: These files are binary imported translations generated from CSV files.
-- ``export_presets.cfg``: This file contains all the export presets for the
-  project, including sensitive information such as Android keystore credentials.
-- ``.mono/``: This folder stores automatically-generated Mono files. It only exists
-  in projects that use the Mono version of Godot.
+    If you are using Godot 3, check the ``3.5`` version of this documentation page
+    instead.
 
 
-.. tip::
+There are some files and folders Godot automatically creates when opening a
+project in the editor for the first time. To avoid bloating your version control
+repository with generated data, you should add them to your VCS ignore:
 
 
-    Save `this .gitignore file <https://raw.githubusercontent.com/github/gitignore/master/Godot.gitignore>`__
-    in your project's root folder to set up file exclusions automatically.
+- ``.godot/``: This folder stores various project cache data.
+- ``*.translation``: These files are binary imported
+  :ref:`translations <doc_internationalizing_games>` generated from CSV files.
+
+You can make the Godot project manager generate version control metadata for you
+automatically when creating a project. When choosing the **Git** option, this
+creates ``.gitignore`` and ``.gitattributes`` files in the project root:
+
+.. figure:: img/version_control_systems_generate_metadata.webp
+   :align: center
+   :alt: Creating version control metadata in the project manager's New Project dialog
+
+   Creating version control metadata in the project manager's **New Project** dialog
+
+In existing projects, select the **Project** menu at the top of the editor, then
+choose **Version Control > Generate Version Control Metadata**. This creates the
+same files as if the operation was performed in the project manager.
 
 
 Working with Git on Windows
 Working with Git on Windows
 ---------------------------
 ---------------------------
 
 
-Most Git for Windows clients are configured with the ``core.autocrlf`` set to ``true``.
-This can lead to files unnecessarily being marked as modified by Git due to their line endings being converted automatically.
-It is better to set this option as::
+Most Git for Windows clients are configured with the ``core.autocrlf`` set to
+``true``. This can lead to files unnecessarily being marked as modified by Git
+due to their line endings being converted from LF to CRLF automatically.
+
+It is better to set this option as:
+
+::
 
 
     git config --global core.autocrlf input
     git config --global core.autocrlf input
+
+Creating version control metadata using the project manager or editor will
+automatically enforce LF line endings using the ``.gitattributes`` file.
+In this case, you don't need to change your Git configuration.

+ 5 - 7
tutorials/best_practices/what_are_godot_classes.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_what_are_godot_classes:
 .. _doc_what_are_godot_classes:
 
 
 Applying object-oriented principles in Godot
 Applying object-oriented principles in Godot
@@ -54,15 +52,15 @@ The behavior of scenes has many similarities to classes, so it can make sense to
 a class. Scenes are reusable, instantiable, and inheritable groups of nodes. Creating a scene is
 a class. Scenes are reusable, instantiable, and inheritable groups of nodes. Creating a scene is
 similar to having a script that creates nodes and adds them as children using ``add_child()``.
 similar to having a script that creates nodes and adds them as children using ``add_child()``.
 
 
-We often pair a scene with a scripted root node that makes use of the scene's nodes. As such, 
+We often pair a scene with a scripted root node that makes use of the scene's nodes. As such,
 the script extends the scene by adding behavior through imperative code.
 the script extends the scene by adding behavior through imperative code.
 
 
 The content of a scene helps to define:
 The content of a scene helps to define:
 
 
-- What nodes are available to the script
-- How they are organized
-- How they are initialized
-- What signal connections they have with each other
+- What nodes are available to the script.
+- How they are organized.
+- How they are initialized.
+- What signal connections they have with each other.
 
 
 Why is any of this important to scene organization? Because instances of scenes *are* objects. As a
 Why is any of this important to scene organization? Because instances of scenes *are* objects. As a
 result, many object-oriented principles that apply to written code also apply to scenes: single
 result, many object-oriented principles that apply to written code also apply to scenes: single