Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Quand utiliser des scènes ou des scripts

Nous avons déjà expliqué en quoi les scènes et les scénarios sont différents. Les scripts définissent une extension de classe du moteur avec code impératif, les scènes avec code déclaratif.

Each system's capabilities are different as a result. Scenes can define how an extended class initializes, but not what its behavior actually is. Scenes are often used in conjunction with a script, the scene declaring a composition of nodes, and the script adding behaviour with imperative code.

Types anonymes

Il est possible de définir complètement le contenu des scènes à l’aide d’un seul script. Il s’agit, en substance, ce que fait l’éditeur Godot, uniquement dans le constructeur de C++ de ses objets.

Mais, choisir lequel utiliser peut être un dilemme. La création d'instances de script est identique à la création de classes dans le moteur alors que la gestion des scènes nécessite un changement dans l'API :

const MyNode = preload("my_node.gd")
const MyScene = preload("my_scene.tscn")
var node = Node.new()
var my_node = MyNode.new() # Same method call.
var my_scene = MyScene.instantiate() # Different method call.
var my_inherited_scene = MyScene.instantiate(PackedScene.GEN_EDIT_STATE_MAIN) # Create scene inheriting from MyScene.

Aussi, les scripts fonctionnent un peu plus lentement que les scènes en raison de la différence de vitesse entre le moteur et le code de script. Plus grand et complexe est le nœud, plus il y a de raison de le construire comme une scène.

Types nommés

Scripts can be registered as a new type within the editor itself. This displays it as a new type in the node or resource creation dialog with an optional icon. This way, the user's ability to use the script is much more streamlined. Rather than having to...

  1. Connaître le type de base du script qu'ils aimeraient utiliser.

  2. Créez une instance de ce type de base.

  3. Ajoutez le script au nœud.

With a registered script, the scripted type instead becomes a creation option like the other nodes and resources in the system. The creation dialog even has a search bar to look up the type by name.

Il y a deux systèmes d’enregistrement des types :

  • Types personnalisés

    • Éditeur seulement. Les noms de types ne sont pas accessibles au moment de l'exécution.

    • Ne prend pas en charge les types personnalisés hérités.

    • Un outil d'initialisation. Crée le nœud avec le script. Rien de plus.

    • L'éditeur n'est pas conscient du type du script ou de sa relation avec d'autres types du moteurs ou scripts.

    • Permet aux utilisateurs de définir une icône.

    • Fonctionne pour tous les langages de script parce qu'il traite des ressources de script dans l'abstrait.

    • Configurer avec EditorPlugin.add_custom_type.

  • Classes Script

    • Editeur et runtime accessibles.

    • Affiche l'intégralité des relations d'héritage.

    • Crée le nœud avec le script, mais peut aussi changer de type ou étendre le type depuis l'éditeur.

    • L'éditeur est conscient des relations d'héritage entre les scripts, les classes de script et les classes C++ du moteur.

    • Permet aux utilisateurs de définir une icône.

    • Les développeurs du moteur doivent ajouter le support pour les langues manuellement (à la fois le nom de l'exposition et l'exécution de l'accessibilité).

    • Godot 3.1+ uniquement.

    • L'éditeur analyse les dossiers de projet et enregistre tous les noms exposés pour tous les langages de script. Chaque langage de script doit implémenter son propre support pour exposer ces informations.

Les deux méthodologies ajoutent des noms au dialogue de création, mais les classes de script, en particulier, permettent également aux utilisateurs d'accéder au nom de type sans charger la ressource script. Créer des instances et accéder à des constantes ou à des méthodes statiques est viable de n'importe où.

Avec de telles fonctionnalités, on peut souhaiter que leur type soit un script sans scène en raison de la facilité d'utilisation qu'il offre aux utilisateurs. Ceux qui développent des plugins ou qui créent des outils internes pour les concepteurs trouveront les choses plus faciles de cette façon.

Le revers de la médaille, est que cela signifie aussi avoir à utiliser largement la programmation impérative.

Performances de Script vs PackedScene

Un dernier aspect à considérer lors du choix des scènes et des scripts est la vitesse d'exécution.

Au fur et à mesure que la taille des objets augmente, la taille des scripts nécessaire pour les créer et les initialiser s'agrandit beaucoup. La création de hiérarchies de nœuds en est la preuve. La logique de chaque nœud peut comporter plusieurs centaines de lignes de code.

L'exemple de code ci-dessous crée un nouveau Node, change son nom, lui attribue un script, définit son futur parent comme propriétaire afin qu'il soit enregistré sur le disque en même temps que lui, et enfin l'ajoute comme enfant du noeud Main :

# main.gd
extends Node

func _init():
    var child = Node.new()
    child.name = "Child"
    child.script = preload("child.gd")
    add_child(child)
    child.owner = self

Un code de script comme celui-ci est beaucoup plus lent que le code C ++ côté moteur. Chaque instruction fait un appel à l'API de script qui conduit à de nombreuses "recherches" sur le back-end pour trouver la logique à exécuter.

Les scènes aident à éviter ce problème de performances. PackedScene, le type de base dont les scènes héritent, définit les ressources qui utilisent des données sérialisées pour créer des objets. Le moteur peut traiter les scènes par lots sur le back-end et offrir de bien meilleures performances que les scripts.

Conclusion

En fin de compte, la meilleure approche consiste à tenir compte de ce qui suit :

  • Si l'on souhaite créer un outil de base qui sera réutilisé dans plusieurs projets différents et que les gens de tous les niveaux de compétence utiliseront probablement (y compris ceux qui ne se qualifient pas de "programmeurs"), alors il y a de fortes chances pour que ce soit un script, probablement avec un nom/un icône personnalisé.

  • Si l'on souhaite créer un concept propre à son jeu, il doit toujours s'agir d'une scène. Les scènes sont plus faciles à suivre/modifier et offrent plus de sécurité que les scripts.

  • If one would like to give a name to a scene, then they can still sort of do this by declaring a script class and giving it a scene as a constant. The script becomes, in effect, a namespace:

    # game.gd
    class_name Game # extends RefCounted, so it won't show up in the node creation dialog.
    extends RefCounted
    
    const MyScene = preload("my_scene.tscn")
    
    # main.gd
    extends Node
    func _ready():
        add_child(Game.MyScene.instantiate())