Up to date

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

Guide de style GDScript

Ce guide de style liste les standards pour écrire du GDScript élégant. Le but est d'encourager l'écriture de code propre et lisible ainsi que de promouvoir l'uniformité au travers des projets, les discussions et les tutoriels. Nous espérons que cela encouragera le développement d'outil d'auto-formatage.

Puisque GDScript ressemble à Python, ce guide est inspiré par le guide de style de programmation de Python PEP 8 .

Les guides de style ne sont pas conçus comme des livres de règles rigides. Parfois, il se peut que vous ne puissiez pas appliquer certaines des règles ci-dessous. Lorsque cela se produit, utilisez votre jugement et demandez à vos collègues développeurs de vous donner leur avis.

En général, garder votre code consistant dans vos projets et au sein de votre équipe est plus important que de suivre ce guide à la lettre.

Note

L'éditeur de script intégré dans Godot utilise beaucoup de ces standards par défaut. Laissez-le vous aider.

Voici un exemple de classe complet basé sur ces lignes directrices :

class_name StateMachine
extends Node
## Hierarchical State machine for the player.
##
## Initializes states and delegates engine callbacks ([method Node._physics_process],
## [method Node._unhandled_input]) to the state.

signal state_changed(previous, new)

@export var initial_state: Node
var is_active = true:
    set = set_is_active

@onready var _state = initial_state:
    set = set_state
@onready var _state_name = _state.name


func _init():
    add_to_group("state_machine")


func _enter_tree():
    print("this happens before the ready method!")


func _ready():
    state_changed.connect(_on_state_changed)
    _state.enter()


func _unhandled_input(event):
    _state.unhandled_input(event)


func _physics_process(delta):
    _state.physics_process(delta)


func transition_to(target_state_path, msg={}):
    if not has_node(target_state_path):
        return

    var target_state = get_node(target_state_path)
    assert(target_state.is_composite == false)

    _state.exit()
    self._state = target_state
    _state.enter(msg)
    Events.player_state_changed.emit(_state.name)


func set_is_active(value):
    is_active = value
    set_physics_process(value)
    set_process_unhandled_input(value)
    set_block_signals(not value)


func set_state(value):
    _state = value
    _state_name = _state.name


func _on_state_changed(previous, new):
    print("state changed")
    state_changed.emit()


class State:
    var foo = 0

    func _init():
        print("Hello!")

Formatage

Encodage et caractères spéciaux

  • Utilisez le saut de ligne (LF) pour terminer les lignes, et non CRLF ou CR. (éditeur par défaut)

  • Utilisez un caractère de saut de ligne à la fin de chaque fichier. (éditeur par défaut)

  • Utilisez l'encodage UTF-8 sans indicateur d'ordre d'octet. (éditeur par défaut)

  • Utilisez Tabs au lieu d'espaces pour l'indentation. (éditeur par défaut)

Indentation

Chaque niveau d'indentation doit être supérieur d'une unité au bloc qui le contient.

Bon :

for i in range(10):
    print("hello")

Mauvais :

for i in range(10):
  print("hello")

for i in range(10):
        print("hello")

Utiliser 2 niveaux d'indentations pour distinguer les suites de lignes des blocs de code réguliers.

Bon :

effect.interpolate_property(sprite, "transform/scale",
        sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
        Tween.TRANS_QUAD, Tween.EASE_OUT)

Mauvais :

effect.interpolate_property(sprite, "transform/scale",
    sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
    Tween.TRANS_QUAD, Tween.EASE_OUT)

Les exceptions à cette règle sont les tableaux, les dictionnaires et les énumérations. Utilisez un seul niveau d'indentation pour distinguer les lignes de continuation :

Bon :

var party = [
    "Godot",
    "Godette",
    "Steve",
]

var character_dict = {
    "Name": "Bob",
    "Age": 27,
    "Job": "Mechanic",
}

enum Tiles {
    TILE_BRICK,
    TILE_FLOOR,
    TILE_SPIKE,
    TILE_TELEPORT,
}

Mauvais :

var party = [
        "Godot",
        "Godette",
        "Steve",
]

var character_dict = {
        "Name": "Bob",
        "Age": 27,
        "Job": "Mechanic",
}

enum Tiles {
        TILE_BRICK,
        TILE_FLOOR,
        TILE_SPIKE,
        TILE_TELEPORT,
}

Virgule de fin

Utilisez une virgule de fin de ligne sur la dernière ligne des tableaux, dictionnaires et énumérations. Ceci a pour résultat un refactoring plus facile et de meilleures différences dans le contrôle de version car la dernière ligne n'a pas besoin d'être modifiée lors de l'ajout de nouveaux éléments.

Bon :

var array = [
    1,
    2,
    3,
]

Mauvais :

var array = [
    1,
    2,
    3
]

Les virgules de fin de ligne sont inutiles dans les listes en une ligne, alors ne les ajoutez pas dans ce cas.

Bon :

var array = [1, 2, 3]

Mauvais :

var array = [1, 2, 3,]

Lignes vides

Encadrer les fonctions et les définitions de classes par deux ligne vide :

func heal(amount):
    health += amount
    health = min(health, max_health)
    health_changed.emit(health)


func take_damage(amount, effect=null):
    health -= amount
    health = max(0, health)
    health_changed.emit(health)

Utiliser une ligne vide à l'intérieur des fonctions pour séparer les sections logiques.

Note

Nous utilisons une seule ligne entre les classes et les définitions de fonctions dans la référence de la classe et dans les courts extraits de code de cette documentation.

Longueur de la ligne

Gardez chaque ligne de code en dessous de 100 caractères.

Si vous le pouvez, essayez de ne pas dépasser 80 caractères par ligne. Cela permet de lire le code sur de petits écrans et avec deux scripts ouverts côte à côte dans un éditeur de texte externe. Par exemple, lorsqu'il s'agit d'une révision différentielle.

Une Instruction par ligne

Évitez de combiner plusieurs instructions sur une seule ligne, y compris les instructions conditionnelles, pour respecter les directives de style GDScript pour plus de lisibilité.

Bon :

if position.x > width:
    position.x = 0

if flag:
    print("flagged")

Mauvais :

if position.x > width: position.x = 0

if flag: print("flagged")

La seule exception à cette règle est l'opérateur ternaire :

next_state = "idle" if is_on_floor() else "fall"

Formatez les instructions sur plusieurs lignes pour la lisibilité

Quand vous avez des instructions if particulièrement longues ou des expressions ternaires imbriquées, les séparer en plusieurs lignes améliore la lisibilité. Comme les lignes suivantes font parties de la même expression, 2 niveaux d'indentation devraient être utilisés au lieu d'un.

GDScript permet d'écrire des instructions sur plusieurs lignes à l'aide de parenthèses ou d'antislashs. Les parenthèses sont privilégiées dans ce guide de style car elles permettent une refactorisation plus simple. Avec les antislashs, vous devez vous assurer que la dernière ligne ne contient pas un antislash à la fin. Avec les parenthèses, vous n'avez pas à vous soucier d'un antislash à la fin de la dernière ligne.

Quand vous séparez une expression conditionnelle en plusieurs lignes, les mots-clés and/or devraient être placé en début de ligne, et non à la fin de la ligne précédente.

Bon :

var angle_degrees = 135
var quadrant = (
        "northeast" if angle_degrees <= 90
        else "southeast" if angle_degrees <= 180
        else "southwest" if angle_degrees <= 270
        else "northwest"
)

var position = Vector2(250, 350)
if (
        position.x > 200 and position.x < 400
        and position.y > 300 and position.y < 400
):
    pass

Mauvais :

var angle_degrees = 135
var quadrant = "northeast" if angle_degrees <= 90 else "southeast" if angle_degrees <= 180 else "southwest" if angle_degrees <= 270 else "northwest"

var position = Vector2(250, 350)
if position.x > 200 and position.x < 400 and position.y > 300 and position.y < 400:
    pass

Évitez les parenthèses inutiles

Évitez les parenthèses dans les expressions et les déclarations conditionnelles. À moins qu'elles ne soient nécessaires pour l'ordre des opérations ou qu'elles s'étendent sur plusieurs lignes, elles ne font que réduire la lisibilité.

Bon :

if is_colliding():
    queue_free()

Mauvais :

if (is_colliding()):
    queue_free()

Opérateurs booléens

Préférez les versions en anglais des opérateurs booléens, car elles sont les plus accessibles :

  • Utilisez and au lieu de &&.

  • Utilisez or au lieu de ||.

  • Use not instead of !.

Vous pouvez également utiliser des parenthèses autour des opérateurs booléens pour éviter toute ambiguïté. Cela peut améliorer la lisibilité des longues expressions.

Bon :

if (foo and bar) or not baz:
    print("condition is true")

Mauvais :

if foo && bar || !baz:
    print("condition is true")

Espace de commentaires

Les commentaires classiques (#) et les commentaires de documentation (##) doivent commencer par un espace, mais pas le code que vous commentez. De plus, les commentaires de région de code (#region/#endregion) doivent suivre cette syntaxe précise, ils ne doivent donc pas commencer par un espace.

L'utilisation d'un espace pour les commentaires classiques et de documentation permet de différencier les commentaires de texte du code désactivé.

Bon :

# This is a comment.
#print("This is disabled code")

Mauvais :

#This is a comment.
# print("This is disabled code")

Note

Dans l'éditeur de script, pour activer ou désactiver les commentaires sur le code sélectionné, appuyez sur Ctrl + K. Cette fonction ajoute/supprime un seul signe # avant le code sur les lignes sélectionnées.

Espaces

Utilisez toujours un espace autour des opérateurs et après les virgules. Évitez également les espaces supplémentaires dans les références de dictionnaire et les appels de fonction. Une exception à cette règle concerne les déclarations de dictionnaire sur une seule ligne, où un espace doit être ajouté après l'accolade ouvrante et avant l'accolade fermante. Cela permet de distinguer plus facilement visuellement le dictionnaire d'un tableau, car les caractères [] et {} se ressemblent dans la plupart des polices.

Bon :

position.x = 5
position.y = target_position.y + 10
dict["key"] = 5
my_array = [4, 5, 6]
my_dictionary = { key = "value" }
print("foo")

Mauvais :

position.x=5
position.y = mpos.y+10
dict ["key"] = 5
myarray = [4,5,6]
my_dictionary = {key = "value"}
print ("foo")

Ne pas utiliser d'espaces pour aligner verticalement les expressions :

x        = 100
y        = 100
velocity = 500

Guillemets

Utilisez des guillemets doubles dans la mesure du possible, sauf si les guillemets simples peuvent réduire le nombre de caractères à échapper dans une chaîne de caractères donnée. Voir l'exemple ci-dessous :

# Normal string.
print("hello world")

# Use double quotes as usual to avoid escapes.
print("hello 'world'")

# Use single quotes as an exception to the rule to avoid escapes.
print('hello "world"')

# Both quote styles would require 2 escapes; prefer double quotes if it's a tie.
print("'hello' \"world\"")

Nombres

N'omettez pas le zéro de tête ou de queue dans les nombres à virgule flottante. Sinon, cela les rend moins lisibles et plus difficiles à distinguer des nombres entiers d'un seul coup d'œil.

Bon :

var float_number = 0.234
var other_float_number = 13.0

Mauvais :

var float_number = .234
var other_float_number = 13.

Utilisez des minuscules pour les lettres des nombres hexadécimaux, car leur hauteur réduite rend le nombre plus facile à lire.

Bon :

var hex_number = 0xfb8c0b

Mauvais :

var hex_number = 0xFB8C0B

Profitez des underscores de GDScript dans les littéraux pour rendre les grands nombres plus lisibles.

Bon :

var large_number = 1_234_567_890
var large_hex_number = 0xffff_f8f8_0000
var large_bin_number = 0b1101_0010_1010
# Numbers lower than 1000000 generally don't need separators.
var small_number = 12345

Mauvais :

var large_number = 1234567890
var large_hex_number = 0xfffff8f80000
var large_bin_number = 0b110100101010
# Numbers lower than 1000000 generally don't need separators.
var small_number = 12_345

Conventions de nommage

These naming conventions follow the Godot Engine style. Breaking these will make your code clash with the built-in naming conventions, leading to inconsistent code. As a summary table:

Type

Convention

Exemple

Nom de fichier

snake_case

yaml_parser.gd

Class names

PascalCase

class_name YAMLParser

Node names

PascalCase

Camera3D, Player

Fonctions

snake_case

func load_level():

Variables

snake_case

var particle_effect

Signaux

snake_case

signal door_opened

Constantes

CONSTANT_CASE

const MAX_SPEED = 200

Enum names

PascalCase

enum Element

Enum members

CONSTANT_CASE

{EARTH, WATER, AIR, FIRE}

Nom de fichier

Utilisez snake_case pour les noms de fichiers. Pour les classes nommées, convertissez le nom de la classe de PascalCase en snake_case :

# This file should be saved as `weapon.gd`.
class_name Weapon
extends Node
# This file should be saved as `yaml_parser.gd`.
class_name YAMLParser
extends Object

Cela correspond à la façon dont les fichiers C++ sont nommés dans le code source de Godot. Cela permet également d'éviter les problèmes de sensibilité à la casse qui peuvent survenir lors de l'exportation d'un projet de Windows vers d'autres plateformes.

Classes et Nœuds

Utiliser le PascalCase pour les noms des classes et des nœuds :

extends CharacterBody3D

Utiliser aussi le PascalCase lorsque vous chargez une classe dans une constante ou une variable :

const Weapon = preload("res://weapon.gd")

Fonctions et Variables

Utiliser le snake_case pour nommer les fonctions et variables :

var particle_effect
func load_level():

Préfixer un seul trait de soulignement (_) aux méthodes virtuelles que l'usager doit redéfinir, les fonctions privées, et les variables privées :

var _counter = 0
func _recalculate_path():

Signaux

Utiliser le passé pour nommer les signaux :

signal door_opened
signal score_changed

Constantes et énumérations

Écrivez les constantes avec CONSTANT_CASE, c'est-à-dire en majuscules avec un trait de soulignement (_) pour séparer les mots :

const MAX_SPEED = 200

Utilisez PascalCase pour les énumération(enum) names et CONSTANT_CASE pour leurs membres, car ce sont des constantes :

enum Element {
    EARTH,
    WATER,
    AIR,
    FIRE,
}

Write enums with each item on its own line. This allows adding documentation comments above each item more easily, and also makes for cleaner diffs in version control when items are added or removed.

Bon :

enum Element {
    EARTH,
    WATER,
    AIR,
    FIRE,
}

Mauvais :

enum Element { EARTH, WATER, AIR, FIRE }

Ordre du code

This section focuses on code order. For formatting, see Formatage. For naming conventions, see Conventions de nommage.

Nous suggérons d'organiser le code GDScript de cette manière :

01. @tool
02. class_name
03. extends
04. ## docstring

05. signals
06. enums
07. constants
08. @export variables
09. public variables
10. private variables
11. @onready variables

12. optional built-in virtual _init method
13. optional built-in virtual _enter_tree() method
14. built-in virtual _ready method
15. remaining built-in virtual methods
16. public methods
17. private methods
18. subclasses

Nous avons optimisé l'ordre pour rendre le code plus simple à lire de haut en bas, afin d'aider les développeurs à comprendre comment le code fonctionne la première fois qu'ils le lisent, et pour éviter les erreurs liées à l'ordre de déclaration des variables.

Cet ordre du code suit quatre règles générales :

  1. Les propriétés et signaux viennent en premier, suivis des méthodes.

  2. Publique vient avant privé.

  3. Les rappels(callbacks) virtuels précèdent l'interface de la classe.

  4. Les fonctions de construction et d'initialisation de l'objet, _init et _ready, viennent avant les fonctions qui modifient l'objet à l'exécution.

Déclaration de classe

Si le code est destiné à être exécuté dans l'éditeur, utilisez l'annotation ``@tool``sur la première ligne du script.

Suivi de class_name si nécessaire. Vous pouvez transformer un fichier GDScript en un type global dans votre projet à l'aide de cette fonctionnalité. Pour plus d'informations, voir Référence GDScript.

Ensuite, ajoutez le mot-clé extends si la classe étend un type intégré.

Ensuite, vous devriez avoir les commentaires de documentation facultatifs de la classe <doc_gdscript_documentation_comments>. Vous pouvez l'utiliser pour expliquer le rôle de votre classe à vos coéquipiers, son fonctionnement et la manière dont les autres développeurs devraient l'utiliser, par exemple.

class_name MyNode
extends Node
## A brief description of the class's role and functionality.
##
## The description of the script, what it can do,
## and any further detail.

Signaux et propriétés

Écrivez les déclarations de signaux, suivies des propriétés, c'est-à-dire les variables membres, après la docstring.

Les énumérations doivent venir après les signaux, car vous pouvez les utiliser comme indices d’exportation pour les autres propriétés.

Ensuite, écrivez les constantes, les variables exportées puis les variables publiques, privées et onready, dans cet ordre.

signal player_spawned(position)

enum Jobs {
    KNIGHT,
    WIZARD,
    ROGUE,
    HEALER,
    SHAMAN,
}

const MAX_LIVES = 3

@export var job: Jobs = Jobs.KNIGHT
@export var max_health = 50
@export var attack = 5

var health = max_health:
    set(new_health):
        health = new_health

var _speed = 300.0

@onready var sword = get_node("Sword")
@onready var gun = get_node("Gun")

Note

GDScript évalue les variables @onready juste avant l'appel _ready. Vous pouvez l'utiliser pour mettre en cache les dépendances des nœuds, c'est-à-dire pour obtenir les nœuds enfants de la scène sur lesquels votre classe s'appuie. C'est ce que montre l'exemple ci-dessus.

Variables membres

Ne déclarez pas les variables membres si elles ne sont utilisées que localement dans une méthode, car cela rend le code plus difficile à suivre. Déclarez-les plutôt comme des variables locales dans le corps de la méthode.

Variables locales

Déclarez les variables locales le plus près possible de leur première utilisation. Il est ainsi plus facile de suivre le code, sans avoir à trop le faire défiler pour retrouver l'endroit où la variable a été déclarée.

Méthodes et fonctions statiques

Après les propriétés de la classe viennent les méthodes.

Commencez avec la méthode de rappel _init (), que le moteur appellera lors de la création de l'objet en mémoire. Continuez avec la méthode de rappel _ready (), que Godot appelle quand il ajoute un nœud à l'arbre des scènes.

Ces fonctions doivent apparaître en premier car elles indiquent comment l'objet est initialisé.

D'autres méthodes de rappel virtuelles intégrées, comme _unhandled_input() et _physics_process, doivent venir ensuite. Celles-ci contrôlent la boucle principale de l'objet et les interactions avec le moteur de jeu.

Le reste de l'interface de la classe, les méthodes publiques et privées, viennent ensuite dans cet ordre.

func _init():
    add_to_group("state_machine")


func _ready():
    state_changed.connect(_on_state_changed)
    _state.enter()


func _unhandled_input(event):
    _state.unhandled_input(event)


func transition_to(target_state_path, msg={}):
    if not has_node(target_state_path):
        return

    var target_state = get_node(target_state_path)
    assert(target_state.is_composite == false)

    _state.exit()
    self._state = target_state
    _state.enter(msg)
    Events.player_state_changed.emit(_state.name)


func _on_state_changed(previous, new):
    print("state changed")
    state_changed.emit()

Typage statique

GDScript supports optional static typing.

Types déclarés

Pour déclarer le type d'une variable, utilisez <variable>: <type> :

var health: int = 0

Pour déclarer le type de retour d'une fonction, utilisez -> <type> :

func heal(amount: int) -> void:

Types inférés

Dans la plupart des cas, vous pouvez laisser le compilateur déduire le type en utilisant :=. Préférez := lorsque le type est écrit sur la même ligne que l'affectation, sinon préférez écrire le type explicitement.

Bon :

var health: int = 0 # The type can be int or float, and thus should be stated explicitly.
var direction := Vector3(1, 2, 3) # The type is clearly inferred as Vector3.

Incluez l'indication de type lorsque le type est ambigu et omettez l'indication de type lorsqu'elle est redondante.

Mauvais :

var health := 0 # Typed as int, but it could be that float was intended.
var direction: Vector3 = Vector3(1, 2, 3) # The type hint has redundant information.

# What type is this? It's not immediately clear to the reader, so it's bad.
var value := complex_function()

Dans certains cas, le type doit être indiqué explicitement, sinon le comportement ne sera pas celui attendu car le compilateur ne pourra utiliser que le type de retour de la fonction. Par exemple, get_node() ne peut pas déduire un type à moins que la scène ou le fichier du nœud ne soit chargé en mémoire. Dans ce cas, vous devez définir le type explicitement.

Bon :

@onready var health_bar: ProgressBar = get_node("UI/LifeBar")

Autrement, vous pouvez utiliser le mot-clé as pour transtyper le type de retour, et ce type sera utilisé pour inférer le type de la variable.

@onready var health_bar := get_node("UI/LifeBar") as ProgressBar
# health_bar will be typed as ProgressBar

Cette option est aussi considérée plus type-safe que la première.

Mauvais :

# The compiler can't infer the exact type and will use Node
# instead of ProgressBar.
@onready var health_bar := get_node("UI/LifeBar")