Chargements automatiques par rapport aux nœuds internes

D’autres moteurs pourraient encourager l’utilisation de la création de classes « manager » qui organisent un grand nombre de fonctionnalités en une entité globalement accessible. Godot se distingue en fournissant les moyens de réduire la taille de ces objets. Il déplace autant que possible le contenu dans des nœuds individuels.

Par exemple, que se passe-t-il si un développeur construit un platformer et qu’il veut collectionner des pièces qui jouent un effet sonore ? Eh bien, il y a un nœud pour cela : le AudioStreamPlayer. Mais ils remarquent pendant leur test que s’ils « jouent » un AudioStreamPlayer alors qu’il joue déjà le son, alors le nouveau son interrompt le premier son, le terminant avant qu’il puisse finir de jouer.

Les utilisateurs ont tendance à penser que la meilleure solution est de rendre l’ensemble du système plus intelligent en créant un nœud de chargement automatique SoundManager. Il génère un groupe de lecteurs AudioStreamPlayers qui passent d’un lecteur à l’autre à chaque nouvelle demande d’effets sonores. Ils font alors de ce SoundManager un autoload de sorte qu’ils puissent y accéder de n’importe où avec SFX.play(« coin_pickup.ogg »). Ils ne savent pas qu” ils ont invité beaucoup de complications dans leur code.

  • état global : Un seul objet est maintenant responsable des données de tous les objets. Si le SFX a des erreurs ou n’a pas d’AudioStreamPlayer disponible, tout va dysfonctionner.
  • accès global : Maintenant que n’importe quel objet peut appeler `SFX.play(sound_path)`de n’importe où, il n’y a plus de moyen facile de suivre où un bug SFX a commencé.
  • allocation globale des ressources : Si les données et le traitement de tous les objets sont centralisés dès le départ, alors il faut soit….
    1. le risque de sous-affectation des ressources, ce qui pourrait conduire à des comportements erronés.
      • Ex : Avoir trop peu de AudioStreamPlayers dans le pool d’objets. Le son ne joue pas ou interrompt un autre son.
    2. surallouer les ressources et utiliser plus de mémoire et de traitement qu’il n’en faut.
      • Ex : Avoir un nombre arbitrairement grand de AudioStreamPlayers, avec beaucoup d’entre eux qui tournent au ralenti et ne font rien.
    3. a chaque objet qu’a besoin un AudioStreamPlayer s’inscrire nombreux exactement comment il a besoin et pour qui sonne. Il défait le but d’utiliser une 3ème partie cependant ; Il est maintenant couplé à chaque objet, comme un nœud enfant aurait été. Celui-ci a ajouté un intermédiaire inutile à l’équation.

Chaque scène conserve autant de nœuds AudioStreamPlayer qu’elle en a besoin et tous ces problèmes disparaissent.

  • Chaque scène gère ses propres informations d’état. S’il y a un problème avec les données, cela ne causera des problèmes que dans une seule scène.
  • Chaque scène n’accède qu’à ses propres nœuds. Maintenant, s’il y a un bogue, tracer quel nœud est responsable (probablement le nœud racine de la scène), et où dans le code est fait l’appel problématique (localiser où le code référence le nœud donné) va être beaucoup plus facile.
  • Chaque scène sait exactement de combien de ressources elle a besoin pour la tâche qu’elle exécute. Aucun gaspillage de mémoire ou de traitement dû à un manque d’information.

Les justifications typiques de l’Autoload sont : « J’ai X communs qui impliquent de nombreux nœuds sur plusieurs scènes, et je veux que chaque scène ait X. »

Si X est une fonction, alors la solution est de créer un nouveau type de Node qui s’occupe de fournir cette fonctionnalité pour une scène individuelle ou un sous-arbre de nœud.

Si X est une donnée, alors la solution est soit 1) de créer un nouveau type de Resource pour partager les données, soit 2) de stocker les données dans un objet auquel chaque nœud a accès (les nœuds dans une scène peuvent utiliser `get_owner()” pour récupérer la racine de la scène par exemple).

Alors, quand devrait-on utiliser un auto-chargement ?

  • Données statiques : si vous avez besoin de données statiques, c’est-à-dire de données qui doivent être associées à une classe (il n’y a donc toujours qu’une seule copie des données), alors les chargements automatiques sont de bonnes opportunités pour cela. Les données statiques n’existent pas dans l’API de script de Godot, donc les chargements automatiques singletons sont la meilleure chose à faire. Si l’on crée une classe en tant que chargement automatique, et que l’on ne crée jamais une autre copie de cette classe dans une scène, alors elle fonctionnera à la place d’une API singleton formelle.
  • Commodité : les nœuds chargés automatiquement ont une variable globale pour leur nom générée en GDScript. Ceci peut être très pratique pour définir des objets qui doivent toujours exister, mais qui ont besoin d’informations d’instance d’objet. L’alternative est de créer un script d’espace de noms : un script dont le but est seulement de charger et de créer des constantes pour accéder à d’autres ressources Script ou PackedScene, résultant en quelque chose comme MyAutoload.MyNode.new().
    • Notez que l’introduction des classes de script dans Godot 3.1 remet en question la validité de cette raison. Avec elles, on peut accéder aux scripts en utilisant un nom explicite depuis GDScript. L’utilisation d’un chargement automatique pour accéder à un script d’espace de noms devient inutile, par exemple MyScriptClass.MyPreloadedScript.new().

Si le singleton gère ses propres informations et n’envahit pas les données d’autres objets, alors il est un excellent moyen de créer une classe « système » qui gère une tâche de grande portée. Par exemple, un système de ciblage, système de quête, ou système de dialogue seraient des cas d’utilisation d’implémentations de singleton.