Les scripts

Introduction

Avant Godot 3.0, le seul choix pour scripter un jeu était d’utiliser GDScript. À présent, Godot a quatre (oui, quatre !) langages officiels et la possibilité d’ajouter dynamiquement des langages de script supplémentaires !

Ceci est formidable, surtout en raison de la grande flexibilité offerte, mais cela rend aussi notre travail de support des langages plus difficile.

Les langages « principaux » de Godot sont GDScript et VisualScript. La principale raison de les choisir est leur niveau d’intégration avec Godot, qui rend l’expérience plus fluide ; tous les deux ont une intégration dans l’éditeur très bien huilée, tandis que le C# et C++ doivent être édités dans un IDE séparé. Si vous êtes un adepte des langages à typage statique, optez plutôt pour le C# et le C++.

GDScript

GDScript est, comme indiqué ci-dessus, le langage principal utilisé dans Godot. Son utilisation a quelques points positifs par rapport à d’autres langues en raison de sa forte intégration avec Godot :

  • Il est simple, élégant et conçu pour être familier aux utilisateurs d’autres langages telles que Lua, Python, Squirrel, Squirrel, etc.
  • Charge et compile avec une rapidité fulgurante.
  • L’intégration de l’éditeur est un plaisir à travailler avec, avec une complétion de code pour les nœuds, les signaux et de nombreux autres éléments relatifs à la scène en cours d’édition.
  • Possède des types vectoriels intégrés (tels que vecteurs, transformations, etc.), ce qui le rend efficace pour l’utilisation intensive de l’algèbre linéaire.
  • Supporte plusieurs threads aussi efficacement que les langages à typage statique - une des limitations qui nous a fait éviter les VMs comme Lua, Squirrel, etc.
  • N’utilise pas de ramasse-miettes, usant donc d’un petit peu d’automatisation (la plupart des objets sont de toute façon comptés par référence), par déterminisme.
  • Sa nature dynamique facilite l’optimisation de sections de code en C++ (via GDNative) si plus de performance est requise, le tout sans recompiler le moteur.

Si vous êtes indécis et que vous avez de l’expérience en programmation, en particulier dans les langages à typage dynamique, optez pour GDScript !

VisualScript

À partir de la version 3.0, Godot propose le Visual Scripting. Il s’agit d’une implémentation typique d’un langage de « blocs et connexions », mais adapté au fonctionnement de Godot.

Le Visual Scripting est un excellent outil pour les non-programmeurs, ou même pour les développeurs expérimentés qui veulent rendre certaines parties du code plus accessibles à d’autres, comme les concepteurs de jeux ou les artistes.

Il peut également être utilisé par les programmeurs pour construire des machines à états ou des systèmes de nœuds visuels personnalisés - par exemple, un système de dialogue.

.NET / C#

Comme le C# de Microsoft est populaire parmi les développeurs de jeux, nous en avons ajouté le support officiel. C# est un langage mature avec des tonnes de code écrit pour lui, et son support a été ajouté grâce à un généreux don de Microsoft.

Il a un excellent compromis entre la performance et la facilité d’utilisation, bien que l’on doit être conscient de son ramasse-miettes.

Puisque Godot utilise les runtime .NET de Mono, en théorie, n’importe quelle bibliothèque ou framework .NET tiers peut être utilisé pour scripter dans Godot, ainsi que n’importe quel langage de programmation compatible avec l’infrastructure de langage commun (CLI), comme F#, Boo ou ClojureCLR. En pratique, cependant, C# est la seule option .NET officiellement supportée.

GDNative / C++

Enfin, l’un de nos plus brillants ajouts pour la version 3.0 : GDNative permet de scripter en C++ sans avoir besoin de recompiler (ou même de redémarrer) Godot.

N’importe quelle version de C++ peut être utilisée, et mélanger des compilateurs de divers éditeurs et versions pour les bibliothèques partagées générées fonctionne parfaitement, grâce à l’utilisation d’un bridge interne d’API en C.

Ce langage est le meilleur choix pour la performance et n’a pas besoin d’être utilisé tout au long d’un jeu, car d’autres parties peuvent être écrites en GDScript ou en Visual Script. Cependant, l’API est claire et facile à utiliser car elle ressemble, pour la plupart, à l’API C++ de Godot.

D’autres langages peuvent être rendues disponibles via l’interface GDNative, mais gardez à l’esprit que nous n’avons pas de support officiel pour eux.

Scripter une scène

Pour le reste de ce tutoriel, nous allons mettre en place une scène GUI composée d’un bouton et d’un label, où le fait d’appuyer sur le bouton mettra à jour le label. Cela démontrera :

  • Écrire un script et l’attacher à un nœud.
  • Raccordement des éléments de l’UI via des signaux.
  • Écrire un script qui peut accéder à d’autres nœuds de la scène.

Avant de continuer, assurez-vous de lire la référence GDScript. C’est un langage conçu pour être simple, et la référence est courte, de sorte qu’il ne faudra pas plus de quelques minutes pour obtenir une vue d’ensemble des concepts.

Configuration de la scène

Utilisez la boîte de dialogue « Ajouter un nœud enfant » accessible depuis l’onglet Scène (ou en appuyant sur Ctrl+A) pour créer une hiérarchie avec les nœuds suivants :

  • Panneau
    • Label
    • Bouton

L’arbre de scène devrait ressembler à ceci :

../../_images/scripting_scene_tree.png

Utilisez l’éditeur 2D pour positionner et redimensionner le bouton et le label afin qu’ils ressemblent à l’image ci-dessous. Vous pouvez définir le texte à partir de l’onglet Inspecteur.

../../_images/label_button_example.png

Enfin, sauvegardez la scène avec un nom tel que sayhello.tscn.

Ajouter un script

Cliquez avec le bouton droit sur le nœud Panel, puis sélectionnez « Attacher un script » dans le menu contextuel :

../../_images/add_script.png

La boîte de dialogue de création de script apparaîtra. Cette boîte de dialogue vous permet de définir le langage du script, le nom de la classe et d’autres options.

Dans GDScript, le fichier lui-même représente la classe, ce qui rend le nom de la classe non modifiable.

Le nœud auquel nous attachons le script est un panneau, donc le champ « hérite » sera automatiquement rempli avec « Panneau ». C’est ce que nous voulons, car le but du script est d’étendre la fonctionnalité de notre nœud panneau.

Enfin, saisissez un nom de chemin pour le script et sélectionnez Créer :

../../_images/script_create.png

Le script sera alors créé et ajouté au nœud. Vous pouvez voir ceci par une icône « Ouvrir le script » à côté du nœud dans l’onglet Scène, ainsi que dans la propriété script dans l’Inspecteur :

../../_images/script_added.png

Pour éditer le script, sélectionnez l’un ou l’autre de ces boutons, qui sont tous deux surlignés dans l’image ci-dessus. Cela vous emmenera vers l’éditeur de script, où un modèle par défaut sera inclus :

../../_images/script_template.png

Il n’y a pas grand-chose. La fonction _ready() est appelée lorsque le nœud et tous ses enfants entrent dans la scène active. Note : _ready() n’est pas le constructeur ; le constructeur est _init().

Le rôle du script

Un script ajoute un comportement à un nœud. Il est utilisé pour contrôler le fonctionnement du nœud ainsi que son interaction avec d’autres nœuds : enfants, parents, frères, etc. La portée locale du script est le nœud. En d’autres termes, le script hérite des fonctions fournies par ce nœud.

../../_images/brainslug.jpg

Traitement d’un signal

Les signaux sont « émis » lorsqu’une action spécifique se produit, et ils peuvent être connectés à n’importe quelle fonction de n’importe quelle instance de script. Les signaux sont surtout utilisés dans les nœuds de l’interface graphique, bien que d’autres nœuds en aient aussi, et vous pouvez même définir des signaux personnalisés dans vos propres scripts.

Dans cette étape, nous allons connecter le signal « pressed » à une fonction personnalisée. Créer les connexions constitue la première partie, et définir la fonction la seconde. Pour la première partie, Godot fournit deux moyens de créer des connexions : au travers d’une interface visuelle incluse dans l’éditeur, ou au travers du code.

Bien que nous utiliserons la méthode du code pour le reste de cette série de tutoriels, voyons comment l’interface de l’éditeur fonctionne pour future référence.

Sélectionnez le node Button dans l’arbre de scène puis l’onglet « Node ». Assurez-vous ensuite que « Signaux » est sélectionné.

../../_images/signals.png

Si vous sélectionnez ensuite « pressed() » sous « BaseButton » et cliquez sur le boutton « Connecter… » en bas à droite, vous allez ouvrir la fenêtre de création de connexion.

../../_images/connect_dialogue.png

En bas à gauche se situent les éléments importants dont vous avez besoin pour créer une connexion : un noeud qui implémente la méthode que vous voulez déclencher (représenté ici par un NodePath) et le nom de la méthode à déclencher.

La section en haut à gauche affiche une liste des nœuds de votre scène avec le nom du nœud émetteur surligné en rouge. Sélectionnez ici le nœud « Panel ». Quand vous sélectionnez un nœud, le NodePath en bas se mettra à jour automatiquement pour pointer vers un chemin relatif du nœud émetteur au nœud sélectionné.

By default, the method name will contain the emitting node’s name (« Button » in this case), resulting in _on_[EmitterNode]_[signal_name]. If you do have the « Make Function » check button checked, then the editor will generate the function for you before setting up the connection.

Ainsi se conclut notre guide sur l’utilisation de l’interface visuelle. Cependant, il s’agit d’un tutoriel de scripting, donc, à titre d’apprentissage, penchons-nous sur la méthode manuelle !

Pour accomplir cela, nous allons introduire une fonction qui est probablement la plus utilisée par les programmeurs Godot : Node.get_node(). Cette fonction utilise des chemins pour récupérer des nœuds n’importe où dans la scène, de manière relative au nœud qui possède le script.

Par souci de praticité, supprimez tout en dessous de extends Panel. Vous remplirez le reste du script manuellement.

Puisque les noeuds Button et Label sont jumelés sous le Panel où est attaché le script, vous pouvez récupérer le Button en tapant ceci sous la fonction _ready() :

func _ready():
    get_node("Button")
public override void _Ready()
{
    GetNode("Button");
}

Ensuite, écrivez une fonction qui sera appelée quand le bouton est pressé :

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
public void _OnButtonPressed()
{
    GetNode<Label>("Label").Text = "HELLO!";
}

Pour terminer, connectez le signal « pressed » du bouton à _ready() en utilisant Object.connect().

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")
public override void _Ready()
{
    GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
}

Le script final devrait ressembler à ça :

extends Panel

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
using Godot;

// IMPORTANT: the name of the class MUST match the filename exactly.
// this is case sensitive!
public class sayhello : Panel
{
    public override void _Ready()
    {
        GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
    }

    public void _OnButtonPressed()
    {
        GetNode<Label>("Label").Text = "HELLO!";
    }
}

Lancez la scène et appuyez sur le bouton. Vous devriez obtenir le résultat suivant :

../../_images/scripting_hello.png

Eh bien ! Félicitations, vous venez de scripter votre première scène.

Note

Une incompréhension fréquente vis-à-vis de ce tutoriel est comment get_node(path) marche. Pour un noeud donné, get_node(path) cherche dans ses enfants directs. Dans le code ci-dessus, cela signifie que Button doit être un enfant de Panel. Si Button était plutôt un enfant de Label, le code pour le récupérer serait :

# Not for this case,
# but just in case.
get_node("Label/Button")
// Not for this case,
// but just in case.
GetNode("Label/Button")

Souvenez-vous aussi que les noeuds sont référencés par nom, pas par type.

Note

Le panneau de droite de la fenêtre de connexion sert à lier des valeurs spécifiques aux paramètres de la fonction connectée. Vous pouvez ajouter et enlever des valeurs de différents types.

La méthode par le code permet aussi cela avec un 4ème paramètre de type Array qui est vide par défaut. N’hésitez pas à vous renseigner sur la méthode Object.connect pour plus d’informations.