Vous avez à disposition un projet starter en Godot. C'est un casse-brique en 2D que vous aurez la liberté d'améliorer selon vos envies.
Le projet sera disponible en deux versions permettant aux personnes présentes lors de l'atelier d'orienter leur découverte du Godot Engine :
Légende de la carte :
Il y aura du code déjà présent à dé-commenter dans les scripts. Essayez de comprendre chaque bout de code vous-même.
Les commentaires en Godot commencent avec #
. Raccourci pour dé-commenter
les lignes sélectionnées : Ctrl
+ K
.
Note : les commentaires doubles
##
sont des commentaires spéciaux dits de documentation (docstrings). Il ne faut pas les dé-commenter ! Le texte associé est visible dans l'éditeur.
Partie théorique pour avoir un peu de contexte.
Définition d'un moteur de jeu
Avantages de Godot
et inconvénients...
Documentation officielle sur l'éditeur
.tscn
.Héritage
extends
. Le cas le plus commun est d'hériter d'un
script interne à Godot, mais on peut aussi hériter d'un de nos
scripts déjà existants. Lorsque nous héritons d'un script, nous
pouvons appeler toutes ses méthodes et accéder à ses propriétés.
Par exemple, un script qui hérite de Node2D peut modifier la
propriété position, et ainsi déplacer l'objet !
class_name
Balle
. Quand on écrit un script, on ne peut hériter que
d'une classe. Heureusement, tous les scripts internes de
Godot sont aussi des classes. :-)Espace / géométrie
Prérequis
Actions
Notion de scène principale
Les dossiers des deux projets sont organisés de la manière suivante :
Concernant les fichiers hors dossiers :
Note : L'ensemble de ses fichiers et dossiers doivent être édités dans l'éditeur de Godot et non directement via le navigateur de fichiers.
Niv. 1
Image : Capture de la configuration de la grille
Niv. 1
Prérequis
Actions
[ ] J'ai fait cette étape.
Suite
Niv. 1
Actions
[ ] J'ai activé le scrolling dans le choix du niveau !
Suite
Niv. 1
La raquette est un composant, on va donc trouver la scène qui lui est dédiée dans le dossier "composants/objets/raquette". La scène est le fichier ".tscn" dans le dossier.
Prérequis
Actions
La scène de la raquette est composée de 3 nœuds :
Un nœud CollisionShape2D. C'est le nœud Sprite2D, dénommé "image", qui va permettre l'affichage de l'image de la raquette.
Actions
Dans l'Inspecteur, on peut voir le champs "Texture". C'est le contenu de ce champ qu'il faut modifier pour changer l'image de la raquette dans le jeu.
La belle image pour votre raquette est disponible dans composants/objets/raquette/sprite.png
.
Actions
[ ] J'ai changé l'image de la raquette !
Suite
Niv. 1
Prérequis
Actions
C'est le nœud Sprite2D, dénommé "image", qui va permettre de changer la couleur de la raquette.
Dans l'Inspecteur, dans la section "Visibility", on peut voir le champs "Self-Modulate". C'est le contenu de ce champ qu'il faut modifier pour changer la couleur de la raquette dans le jeu.
Note : vous pouvez aussi changer la valeur du champ "Modulate" du nœud racine
StaticBody2D
, ce qui change la couleur de tous les enfants, y compris l'image.
Niv. 2
Ne plus avoir de balles, c'est comme ne plus avoir de vies : si ça arrive, la partie est perdue !
@export_range(1, 10) var nombre_de_balles: int = 3
Attention ! Pour faire une comparaison d'égalité, il faut utiliser l'opérateur
==
! L'opérateur=
permet d'assigner une valeur à une variable.Note : "return" interrompt une fonction.
Astuce : afficher le nombre de balles après chaque
décrémentation avec une fonction `print()`
Niv. 2
N'hésitez pas à lire l'explication sur les signaux si besoin !
nb_balles_change
dans la scène du lanceur.
_decrementer_nombre_de_balles()
.Stock
dans un niveau, qui se trouve dans composants/interface
Note : Le signal possède une méthode
emit
, qui permet d'émettre le signal.Attention : Si le label renvoie une erreur : "Cannot convert argument 1 from int to String.", cela veut juste dire qu'il faut convertir la valeur de
nombre_de_balles
en String avant d'émettre le signal.
Mécanique idéale pour faire communiquer des nœuds entre eux. Les signaux permettent d'envoyer des messages à zéro, un ou plusieurs destinataires en même temps. À chaque émission de signal correspond l'exécution d'une fonction pour tous les nœuds connectés à ce signal. Les nœuds de la bibliothèque offrent des signaux et des fonctions déjà utilisables, et il est possible d'en créer dans nos scripts.
Il est recommandé d'utiliser le plus possible les signaux, afin de minimiser les dépendances entre vos nœuds et scripts. Cela facilitera l'organisation de votre code. Vos collègues ou le futur vous-même vous remerciera !
Niv. 1
lancer_balle()
).show()
. C'est une fonction Godot, vous
devez décocher "Scripts Methods Only" pour voir cette méthode.show()
.Niv. 3 : beaucoup d'étapes
perdu.tscn
pour créer la scène de
victoire.conteneur_briques.gd
Note : comme les balles créées par le lanceur sont des nœuds enfants, détruire le lanceur détruit aussi toutes les balles.
Niv. 2
Conventions : les fonctions et variables considérées internes à votre votre script sont préfixées par un trait bas
_
. Elles sont dites privées. Cela donne une indication de qui a le droit d'utiliser cette donnée, facilitant la lecture et la maintenance du code. Par exemple,_vitesse
est une variable privée ; seule la balle elle-même a le droit de la modifier, car c'est sa responsabilité.
Certaines méthodes préfixées par _
sont des fonctions que Godot connaît
et qu'il peut appeler pour vous donner le contrôle à certains moments.
La méthode _ready()
est appelée après que votre nœud soit entré en scène,
et dès tous ses enfants sont prêts (c'est à dire que la fonction _ready() a
été appelée pour chaque enfant). Cette méthode est présente dans de nombreux scripts pour
préparer un nœud.
La méthode _process
est appelée avant le rendu de chaque image. Cette méthode
peut être utilisée pour coder la logique de votre jeu (gagner des points ou de la vie
par exemple) ou pour modifier l'apparence de votre nœud (changer la couleur de votre objet au fil du temps).
Par défaut, cette fonction est appelée 60 fois par seconde, mais dépend de la fréquence de rafraîchissement
de votre écran.
La méthode _physics_process
est appelée à chaque fois que Godot résoud
les calculs physiques permettant de déplacer vos objets. Cette fonction est importante
pour appliquer des forces ou déplacer vos objets.
Par défaut, cette fonction est appelée 50 fois par seconde, mais cela peut se paramétrer.
Note : les fonctions
_process
et_physics_process
reçoivent un nombre à virgules,delta: float
, qui représente le nombre de secondes depuis la dernière fois ou la fonction est appelée. Dans l'idéal, ce nombre est très souvent fixe, mais il peut varier selon la performance de l'appareil. Il faut donc le prendre en compte pour vos calculs liés au temps. Par exemple, si un objet se déplace à 40 pixels par seconde, on écrira :
func _physics_process(delta: float) -> void:
position.x += 40.0 * delta
Enfin, la méthode _unhandled_input()
est appelée quand un périphérique est actionné :
quand une touche de clavier est enfoncée, quand la souris a bougé, un joystick de manette s'est déplacé,
quand un bouton de manette est relâché. Elle prend un argument qui décrit l'événement qui a eu lieu.
Note : la fonction
_input()
existe aussi, mais préférez_unhandled_input
qui appelée seulement si l'événement n'a pas déjà été consommé par un autre nœud.
Il existe d'autres méthodes virtuelles exposées par Godot, mais vous connaissez maintenant les plus utiles.
Bravo pour avoir terminé votre parcours initiatique !
Bienvenue au carrefour où attendent Vladimir et Estragon. N'attendez pas Godot, partez à sa recherche !
Note : vous repasserez probablement par ici plus tard ; n'hésitez pas à cocher les parcours que vous avez déjà faits !
Niv. 1
Les AudioStreamPlayer sont les nœuds permettant de jouer des sons, on peut les intégrer dans tout types de scènes et les manipuler avec des fonctions simples comme play() ou stop() par exemple. Il existe 3 AudioStreamPlayer, le simple (stéréo), l'AudioStreamPlayer2D (qui gère l'audio positionnel en 2 dimensions) et l'AudioStreamPlayer3D (audio positionnel en 3 dimensions).
ressources/musiques
.loop
pour les musiques importées !Niv. 2
composants/interface/clic_sfx.wav
pressed
de chaque bouton à la fonction
interne play
de l'AudioStreamPlayer.$SonClic.play()
dans les
fonctions _quand_bouton_reprendre_est_presse()
,
_quand_bouton_retour_titre_est_presse()
et
_quand_bouton_quitter_est_presse()
du script
pause_menu.gd
.choix_niveau.tscn
en enfant du nœud
DefilementNiveaux.pressed
de chaque bouton planète
à la fonction play
de SonClic%SonClic.play()
dans la fonction _quand_planete_est_cliquee()
dans
le script planete.gd
.Niv. 1
Niv 1
Actions
[ ] J'ai fait cette étape.
Suite
Niv. 3
Note : GPU signifie Graphical Process Unit, cela signifie que les particules sont calculées avec le processeur graphique. Il est préférable de l'utiliser car plus performant ; cependant ça ne marche pas sur toutes les machines. Auquel cas, on utilisera CPUParticles2D (https://docs.godotengine.org/fr/4.x/classes/class_cpuparticles2d.html#class-cpuparticles2d).
Niv. 3
Actions
[ ] J'ai fait cette étape.
Suite
Niv. 3
Il faut ici passer par un peu de script pour piloter le bus "Musique" et activer l'un de ses effets.
Niv. 2
Les bus audio sont des "tubes virtuels" dans lesquels on fait passer les flux audio. Ils sont visibles dans l'onglet "Audio" du panneau inférieur de l'éditeur. Par défaut il n'existe qu'un bus dit "Master" à l'intérieur duquel le son circule de haut en bas, passant du contrôleur de volume, aux effets éventuels pour finir par sortir via vos hauts-parleurs. De nouveaux bus peuvent être ajoutés facilement pour contenir les musiques, les effets sonores, les voix, etc et leur appliquer des traitements dédiés.
Le compresseur est un effet audio complexe a utilisé qui sert à établir un plancher au-dela duquel le volume sonore du son augmentera moins ou plus du tout. Cela va permettre ici de faire perdre en définition la musique quand les effets sonores sont joués afin que le joueur/la joueuse dispose toujours des informations audio nécessaires pour jouer dans de bonnes conditions et que la musique ne couvre jamais les effets sonores.
En l'état le compresseur s'active et agit quand le contenu du bus "Musique" voit son volume passer au-dessus du "Treshold". Il faut changer cela, car on veut que le compresseur s'active quand les effets sonores joues (contenu du bus "Bruits").
Dans le champs "Sidechain" sélectionner le bus "Bruits", cela va permettre au compresseur de s'activer quand le contenu du bus Bruits dépassera le seuil, cependant le compresseur agira toujours sur le contenu du bus "Musique". Ainsi la musique passera légèrement en fond quand les effets sonores seront joués.
[ ] J'ai fait cette étape.
Suite
Niv. 3
Note : quand vous modifiez la vie dans l'éditeur, sa couleur change en direct ! Cela est possible grâce à l'annotation "@tool" en haut du script, qui permet de faire fonctionner le script dans l'éditeur (à utiliser avec précaution) ; et la méthode "set_nombre_de_vies", utilisée pour modifier le nombre de vie (set = set_nombre_de_vies), qui rafraichit la couleur de la brique dès que le nombre de points de vie est modifié.
Niv. 2
Il y a déjà un dégradé de noir grâce à l'étape précédente.
Alternatif : Essayer de modifier la fonction "_montrer_nombre_vies" le script "brique.gd" de la scène "brique.tscn" pour faire un dégradé vers le rouge à la place.
Note : Le script a comme première instruction @tool : cela signifie qu'il s'exécute aussi dans l'éditeur. Cela permet de voir le changement de couleur aussi dans l'éditeur lorsque vous fabriquez un niveau.
Niv. 2
Complètement facultatif.
Niv. 4
Actions
[ ] J'ai fait cette étape.
Suite
Niv. 3
Documentation
[ ] J'ai fait cette étape.
Suite
Niv. 1
Niv. 3
grande_notif.tscn
capsule.gd
grande_notif.tscn
, modifier son texte, puis l'ajouter à l'arbre de scènegrande_notif.tscn
et utiliser un timer qui démarre dans la fonction _ready()
de grande_notif.gd
queue_free
soit appeléebase_pouvoir.gd
, ajouter une méthode nom_pouvoir()
qui retourne "Pouvoir inconnu"PouvoirBase
, ajouter une méthode nom_pouvoir()
qui retourne le nom de ce pouvoir en particuliergrande_notif.gd
, exposez une méthode publique qui permet de modifier la propriété text
du labelcapsule.gd
, modifier le texte de la notif avec le nom du pouvoir avant de l'ajouter à l'arbre de scèneNote : lorsque l'on appelle la méthode
VieBonus.nom_pouvoir()
, la méthodePouvoirBase.nom_pouvoir()
n'est pas appelée. Cette mécanique s'appelle la surcharge.
Niv. 4
recup_pouvoir
dans le dossier effets
Documentation
[ ] J'ai fait cette étape.
Suite
Niv. 3
Niv. 3
Ici, lorsque le pouvoir sera activé, la (ou les) balle sera transformée en balle de feu. Cela signifie qu'il y a une scène dédiée à la balle de feu, qui existe et que vous pouvez regarder.
Note : une méthode statique est une fonction qui peut être appelée sans avoir à créer l'objet associé.
Niv. 3
Note pour améliorer la performance : stocker la référence vers le nœud dans une variable pour éviter de demander à Godot de chercher le nœud à chaque fois.
@onready image : Sprite2D = $Image
Niv. 4
La balle électrique possède une zone d'influence qui détruit les briques à distance.
Niv. 4
Niv. 4
Permet à la raquette de lancer un javelot à haute énergie qui détruit tout sur son passage !
javelot
Node2D
mcJavelot.png
Area2D
pour déterminer la zone de destruction
CollisionShape2D
delta
de physics_process
_quand_corps_entre_dans_zone_destructive
corps: Node2D
body_entered
de la zone de destruction à cette fonctionVisibleOnScreenNotifier2D
screen_exited
à la méthode queue_free()
du nœud racineeffets/eruption
AnimatedSprite2D
pour faire l'effet d'éruptionanimation_finished
à la méthode queue_free()
du nœud racineNiv. 4
La balle spectrale devient transparente au contact sur la raquette : elle ne rentre pas en collision avec les briques, jusqu'à son premier rebond contre un mur.
Niv. 4
À vous de l'imaginer, et de l'implémenter. :-)
Pareil que pour Linux.
Vous pouvez utiliser Wine pour contrôler votre export.
Pour itch.io, nommez l'artefact produit index
afin d'avoir un index.html.
Faites une archive.
Niv. 4
Pour les plus experts d'entre vous.
Le plus facile est d'utiliser l'image docker pour CI Godot.
Niv. 3
Niv. 4
Note : comme votre nouvelle brique a le même script que la brique de base, les deux ont le même comportement !
Niv. 4 : le·a participant·e cherche par lui-même une solution ;-)
On pourra imaginer que le nombre de points dépend du temps. Plus un niveau est terminé rapidement, plus il y a de points ! On peut supposer que le nombre de briques détruites influe aussi sur le nombre de points.
Niv. 4
Niv. 4
Niv. 4
Idem ci-dessus, modulo le facteur de taille.
[ ] J'ai fait cette étape.
Suite
Niv. 4
Permettre au joueur de pouvoir choisir la couleur de sa raquette depuis le menu.
C'est à vous de trouver comment faire !
Niv. 4
Permettre au joueur de pouvoir choisir son pseudo depuis le menu.
Bon courage. :-)
Niv. 4 : le·a participant·e cherche par lui-même une solution ;-)
Niv. 4
Afficher la liste meilleurs scores sur l'écran de game-over.
Les scores doivent être sauvegardés dans un fichier.
Niv. 4
Attribut par niveau, script niveau.
Niv. 4
Ça peut être ce que vous voulez pour rendre le choix du niveau plus vivant.
Niv. 4 : naviguer la doc et expérimenter
Remplacer le label par une jauge, dont le nombre de points représente le nombre de balles.