
Memento GDScript & Godot Engine
Voici une liste des différents codes source et syntaxes courantes utilisés en GDScript dans Godot engine.
Ce fichier est un canevas qui s'étoffera au fur et à mesure de mes expérimentations sur ce langage .
Références/Sources:
- Doc Godot: Gdscript
- Certains exemples de code sont basés sur la version 3.0 de Godot et peuvent être obsolètes
Syntaxe de base
Les variables et les types simples
-
exemple
# full syntax with new gdscript version (static typed from Godot 3.1) var variable_name : type = value # type is fixed but determine by the value with new typed gdscript var variable_name := value # type is dynamic (all gdscript versions) var variable_name = value # Examples var my_var # no value assigned, no type either my_var = 5 # assigning value, type is int but can be changed my_var : String = "Hello world" # my_var is a string and ONLY var empty = null var my_float := 5.0 # my_var is a float and ONLY var bool_true = true or false # constants (use same syntax as variables) const MY_CONST = 200 const MAX_PLAYER_SPEED : int = 500 const MAX_PLAYER_SPEED_MAX := 1000 # string concatenation var full_name = "First" + " " + "Last" var full_nameV2 : String = "First2" + " " + "Last2" # Containers (list of values) var empty_list : Array = [] var my_array = [1, "cat", false, 18.56, 'whatever'] var my_dict = { "one": 1, "two": 2, "three": 3, "four": 4 } my_dict = {one = 1, two = 2, three = 3, four = 4 } my_dict.four = 4 my_dict["five"] = 5
Les chaînes formatées
-
exemple
# Define a format string with placeholder '%s' var format_string = "We're waiting for %s." # Using the '%' operator, the placeholder is replaced with the desired value var actual_string = format_string % "Godot" # output: "We're waiting for Godot." print(actual_string) # Multiple placeholders var format_string = "%s was reluctant to learn %s, but now he enjoys it." var actual_string = format_string % ["Estragon", "GDScript"] # output: "Estragon was reluctant to learn GDScript, but now he enjoys it." print(actual_string) # Define a format string var format_string = "We're waiting for {str}" # Using the 'format' method, replace the 'str' placeholder var actual_string = format_string.format({"str":"Godot"}) # output: "We're waiting for Godot" print(actual_string)
Les conditions et les boucles
-
exemple
if user_answer == "B" and my_var == 1: # leave the condition pass elif user_answer == "C" or my_int = 5: do_something() else: do_something_else() # tests if a value is in an array var my_array = [1, "cat", false, 18.56, 'whatever'] if my_var in my_array: do_something() else: do_something_else() # test for an empty array if not my_array: # my_array is empty for quote in quotes: quote.capitalize() var y = [1,2,3,4] for x in y: print(x) for x in range(8): print(x) while x < 10: print(x) # skip the end of a block (on an if or in a loop) continue # BREAK the block and go to next line (on an if or in a loop) break
Les fonctions
-
exemple
func get_random_item_in(my_list)->void: # TODO: get a random number item = my_list[0] # get a quote from a list print(item) # show the quote in the interpreter return "program is over" # returned value
Les Classes
-
Création d'une classe: un fichier GDscript est considéré comme une classe
-
Exemple d'héritages possibles:
# Inherit/extend a globally available class. extends SomeClass ... # Inherit/extend a named class file. extends "somefile.gd" ... # Inherit/extend an inner class in another file. extends "somefile.gd".SomeInnerClass
-
Exemple de classe dérivée
extend Sprite var max_health := 100 func take_damage (amount:int)->void health -= amount
-
Vérifier si une instance donnée hérite d'une classe:
# Cache the parent class. const Enemy = preload("enemy.gd") # Use 'is' to check inheritance. if entity is Enemy: entity.apply_damage()
-
Appeler une fonction dans une classe parente (c'est-à-dire une extension dans votre classe actuelle), ajoutez le préfixe. au nom de la fonction
.a_function(args) func my_function(x): # Calls the same function on the parent class. .my_function(x)
Les objets
-
Enregistrer un script comme une nouvelle classe (permet de créer de nouveaux types)
extends Node # Declare the class name here, add a comma and an optional path to an image to use as an icon class_name ScriptName, "res://path/to/optional/icon.svg" func _ready(): var this = ScriptName # reference to the script var cppNode = MyCppNode.new() # new instance of a class named MyCppNode cppNode.queue_free()
-
Instantiation d'un objet
var object := Object.new()
-
Forcer le type d'un objet (casting), utile pour accèder aux méthode propres à classe dérivée
($AnimationPlayer as AnimationPlayer).play("walk")
Les noeuds (Node)
-
Création d'un noeud
var s:Sprite func _ready()->void: s = Sprite.new() # Create a new sprite! add_child(s) # Add it as a child of this node.
-
Suppression immédiate d'un noeud
func _someaction()->void: # delete s (object previous defined) s.queue_free() # delete current node queue_free()
-
Supression plus sécure d'un noeud
func _someaction()->void: # delete s (object previous defined) s.queue_free() # delete current node queue_free()
Les scenes
-
Instantiation d'une scene existante
# loading the scene method 1: Will load when the script is instanced. # var scene = load("res://myscene.tscn") # loading the scene method 2 (préféred):Will load when parsing the script. var scene = preload("res://myscene.tscn") # create the scene instance as a "special node" (PackedScene) var node : PackedScene = scene.instance() # add it to the current scene root add_child(node)
-
Création d'un noeud et ajout d'un script attaché.
Le code d’un script comme celui ci est beaucoup plus lent que le C++ du moteur.
Il est préférable de créer la scéne dans l'éditeur, de la créer en tant que PackedScene et de l'instancier.extends Node func _init(): var child = Node.new() child.name = "Child" child.script = preload("Child.gd") child.owner = self add_child(child)
Écran & Images
L'affichage
-
Connaître la taille de la fenêtre
position = get_viewport_rect().size.y:
-
Changer la taille de la fenêtre
# TODO
-
Passer en Plein écran ou mode fenêtré
# TODO
Le GamePlay
Notions utiles
-
Récupérer une référence vers un noeud
get_node("first/chid/child") # $ is a shortcut for get node $first/chid/child
-
Créer et émettre un signal
# code in the signal emitter script (player) signal direction_changed func _physics_process(delta:float)->void: emit_signal('direction_changed', input_direction) #...
-
Recevoir et gérer un signal
# code in the signal receiver script player_node = get_node('player') player_node.connect("direction_changed", self, '_on_Player_direction_changed') #... func _on_Player_direction_changed(direction)->void: #...
-
Exemple d'implémentation d'un évènement sur un bouton
extends Panel func _on_button_pressed()->void: get_node("Label").text = "HELLO!" func _ready()->void: get_node("Button").connect("pressed", self, "_on_button_pressed")
-
Helpers pour les collisions
# first method: delta is already applied and a slide movement is also applied on collision velocity = input_direction.normalized() * speed move_and_slide(velocity) # second method: just a basic collision var motion = input_direction.normalized() * speed * delta var collider = move_and_collide(motion)
Le Delta time
- La fonction
_physic_process
est indépendante du delta time et est appelée à frame constante (60 FPS) -
Le delta time est directement passé à la fonction
_process
extends Label var accu := 0 func _process(delta:float)->void: accu += 1 var text := str(accu)
Gestion des entrées utilisateur
Le clavier
-
Intercepter une touche du clavier
input_direction := Vector2() input_direction.x = int(Input.is_action_pressed("move_right")) - int(Input.is_action_pressed("move_left")) input_direction.y = int(Input.is_action_pressed("move_down")) - int(Input.is_action_pressed("move_up"))
-
Déplacer un sprite au clavier
extends Sprite export var SPEED := 100 func _process(delta:float): var direction := Vector2(0, 0) if Input.is_key_pressed(KEY_UP): direction.y -= 1 if Input.is_key_pressed(KEY_DOWN): direction.y += 1 if Input.is_key_pressed(KEY_LEFT): direction.x -= 1 if Input.is_key_pressed(KEY_RIGHT): direction.x += 1 direction = direction.normalized() # To make sure diagonal movements will be in the same speed direction *= SPEED * delta # Multiply by speed (pixels per second) and the time passed (seconds) translate(direction) # Move the Sprite by the direction vector
Le joystick
- Intercepter un bouton du joystick
func _input(event):
if event is InputEventJoypadButton:
prints("Button:", str(event.button_index))
- Déplacer un sprite avec un joystick
extends Sprite
const SPEED: = 300
var device_index: = 0
func joy_connect(index: int, connect) -> void:
# When a joystick is detected, keep the device index in a variable
if connect:
device_index = index
func _ready() -> void:
Input.connect("joy_connection_changed", self, "joy_connect")
func _process(delta: float) -> void:
var direction: = Vector2(0, 0)
# Query Input singleton with the device index
if Input.is_joy_button_pressed(device_index, 12): # UP
direction.y -= 1
if Input.is_joy_button_pressed(device_index, 13): # DOWN
direction.y += 1
if Input.is_joy_button_pressed(device_index, 14): # LEFT
direction.x -= 1
if Input.is_joy_button_pressed(device_index, 15): # RIGHT
direction.x += 1
direction = direction.normalized()
direction *= SPEED*delta
translate(direction)
La souris
-
Afficher/Masquer le curseur de la souris
# TODO
-
Connaître l'état des boutons de la souris
func _input(event): if event is InputEventMouseButton && event.pressed: prints("Button", event.button_index, "is pressed at", str(event.position)) if event is InputEventMouseMotion: prints("Mouse moved to", str(event.position))
func _process(delta): if Input.is_mouse_button_pressed(BUTTON_LEFT): prints("Holding left mouse button at", get_tree().get_root().get_mouse_position())
-
Connaître la position de la souris
x = get_global_mouse_position().x y = get_global_mouse_position().y
-
Déplacer un sprite avec la souris
func _input(event): if event is InputEventMouseMotion: position = event.position
Tactile (Touchscreen)
-
Connaître l'état du Touchscreen
func _input(event): if event is InputEventScreenTouch && event.pressed: prints("Screen touch at", str(event.position)) if event is InputEventScreenDrag: prints("Screen drag at", str(event.position))
-
Déplacer un sprite avec le Touchscreen
func _input(event): if event is InputEventScreenTouch: position = event.position
Physique
les différent types d'objets physiques
- StaticBody2D
- non déplacé par le moteur physique
- participe à la détection des collisions, mais ne se déplace pas en réponse à la collision.
- utilisé pour des objets qui font partie de l'environnement ou qui n'ont pas besoin d'avoir un comportement dynamique, comme les murs ou le sol.
- RigidBody2D
- simule la physique
- vous ne contrôlez pas directement un RigidBody2D, mais on lui appliquez des force (gravité, impulsions, etc.) et le moteur physique intégré de Godot calcule le mouvement résultant, y compris les collisions, les rebonds, la rotation...
- Vous ne devez pas modifier la position ou la linéarité de RigidBody2D à chaque frame ou même très souvent. Si vous devez affecter directement l'état de l'objet, utilisez
_integrate_forces
, qui vous permet d'accéder directement à l'état physique (et donc à changer ses propriétés, telles que sa position)
- KinematicBody2D
- pas de physique
- participe à la détection des collisions, mais ne se déplace pas en réponse à la collision qui doivent être implémentés dans le code
- utilisé pour les joueurs ou les acteurs qui nécessitent une physique de style arcade plutôt qu'une simulation réaliste.
Gravité & Inertie
-
Déplacer un objet ayant un angle de rotation (en degré)
utiliser un rigibody2d pour appliquer le moteur physique à un objet
les propriétés du moteur physique sont paramètrables dans le propriétés du projet (par ex le coefficient de gravité) et dans celle du rigidbody2D (par ex la friction avec Linear>Damps et Angular>Damp)func _process(delta): thrust = Vector2() if state in [DEAD, INIT]: return if Input.is_action_pressed("thrust"): thrust = Vector2(engine_power, 0) rotation_dir = 0 if Input.is_action_pressed("rotate_right"): rotation_dir += 1 if Input.is_action_pressed("rotate_left"): rotation_dir -= 1 func _physics_process(delta): set_applied_force(thrust.rotated(rotation)) set_applied_torque(spin_power*rotation_dir)
-
la function
_integrate_forces
permet de lire et de modifier en toute sécurité l'état physique d'un RigidBody2D. Utilisez-la à la place de_physics_process
si vous devez changer directement la position ou d'autres propriétés physiques.
L'audio
Musique
- Charger et jouer une musique ou un son
- ajouter un ou plusieurs noeuds AudioStreamPlayer (par exemple
CoinSound
) à la scene - affecter un fichier audio à chacun d'eux
- jouer l'audio, par exemple
$CoinSound.play()
- ajouter un ou plusieurs noeuds AudioStreamPlayer (par exemple
Système
Fichiers
-
godot conserve toutes les ressources dans le dossier du projet. Elles sont accessibles par code via le chemin
res:://
. Ce dossier est en lecture seule -
Les données en lecture/écriture sont accessibles par code via le chemin
user:://
. Son emplacement réel dépend de la plateforme, il peut être déterminé par la fonctionOS.get_user_data_dir()
-
Lire un fichier texte
var highscore = 0 var score_file = "user://highscore.txt" var f = File.new() if f.file_exists(score_file): f.open(score_file, File.READ) var content = f.get_as_text() highscore = int(content) f.close()
-
Ecrire dans un fichier texte
var highscore = 0 var score_file = "user://highscore.txt" var f = File.new() f.open(score_file, File.WRITE) f.store_string(str(highscore)) f.close()
Divers
Gestion de l'application
-
Quitter l'application
# TODO