Faire un jeu avec le Godot Engine ================================= Orga ---- - Laisser les parties son à Nomys - Nomys sera plus dispo à partir de mercredi - Jovial fonce sur le guide le plus possible - Ajustements sur le jeu dans un second temps Le jeu ------ Le dépôt git : Le guide -------- ### Introduction #### Principe de l'atelier - Projet starter. - Le projet qui servira de base à l'atelier est un casse brique classique qui s'appelle Raquette Fracassante. - Chaque niveau doit être complété en cassant toutes les briques à l'écran grâce à une balle qui accélère à chaque rebond. Il faut ainsi renvoyer la balle de plus en plus vite avec la raquette tout en visant les briques à casser. - Le jeu comporte des pouvoirs bonus qui pourront être débloqué en récupérant les capsules qui tombent de certaines briques une fois celles-ci détruites. Attention aux briques qui nécessitent d'être frappées plusieurs fois ! Le projet sera disponible en deux versions permettant aux personnes présentes lors de l'atelier d'orienter leur découverte du Godot Engine : - Version **architecte** : Parcours conception de niveaux (le jeu est complet, il faut juste ajouter de nouveaux niveaux) - Cela permet de découvrir l'interface du Godot Engine en douceur et d'utiliser des fonctionnalités simples. On pourra produire en peu de temps un résultat testable sur le champs et apprendre ainsi en s'amusant. - Version **artisan** : Parcours construction du jeu (le jeu contient uniquement des fonctionnalités minimales et tout le reste est à faire soi-même) - On va pouvoir ainsi ajouter divers types de fonctionnalités (interface, visuels, audio ou gameplay) et appréhender la façon dont les fonctionnalités dépendent les unes des autres. Par exemple pour ajouter un écran de victoire ou de défaite (élément d'interface), il faut d'abord que le jeu sache quand est-ce qu'on gagne ou qu'on perd (fonctionnalité de gameplay). - Vous êtes libres de faire les étapes dans l'ordre que vous voulez, mais attention aux dépendances ! Repérez vous grâce à la carte fournie. Image : carte des dépendances ![Carte des dépendances entre étapes](carte_des_etapes.png) Note : Afin que le chacun et chacune puisse ici s'y retrouver, nous présenteront les fonctionnalités par domaine et par niveau de difficulté. Ainsi même les débutants vont pouvoir ajouter des fonctionnalités qui les intéressent à notre casse-brique minimaliste. ##### Décommenter le code 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 selectionné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. #### Description de Godot - Def moteur de jeu - Un **moteur de jeu** est un ensemble de composants logiciels qui effectuent des calculs de géométrie et de physique utilisés dans les jeux vidéo. L'ensemble forme un simulateur en temps réel souple qui reproduit les caractéristiques des mondes imaginaires dans lesquels se déroulent les jeux. Le but visé par un moteur de jeu est de permettre à une équipe de développement de se concentrer sur le contenu et le déroulement du jeu plutôt que la résolution de problèmes informatiques. (Wikipédia) - Avantages de Godot - Rapidité et facilités de création et de prototypage (idéal pour faire des game jam), - Beaucoup d'outils accessibles sans code, - GDScript (langage interne) facile à lire pour les débutants et débutantes, - Possibilité de coder en C++ pour les développeureuses (ou d'autres languages via des addons), - Bibliothèque d'addons disponible dans le moteur directement, - Aide accessible directement dans le moteur, - Espace de travail modulaire pour s'adapter aux préférences de chacun et chacune, - Moteur complet au niveau des fonctionnalités de base (2D, 3D, réseau, audio, UI). - et inconvénients... - Pas encore au niveau sur certains aspects très pointus (3D et gestion audio notamment). #### Éditeur Godot #### Concepts Godot - Nœuds (débutant) - Les nœuds sont les briques de construction de bases de Godot. Ils sont agencés sous forme d'arbres dont un nœud est la racine dont part ensuite des nœuds enfants, des nœuds petits-enfants et ainsi de suite. Chaque une arborescence de nœuds constitue un **scène**. Les scènes peuvent avoir un nombre variable de nœuds suivant les besoins. - Les scènes vont être ce qui va être sauvegarder dans les fichiers du projet sous la forme de fichiers terminant par l'extension ".tscn". Enfin, les scènes peuvent être appeller les unes dans les autres, on dit alors qu'elle est instanciée - Scripts (avancé) - Permet de décrire les règles et comportements que doivent suivre les nœuds. Par exemple déplacer la balle à chaque image, éclater une brique quand elle n'a plus de vie, ou changer de musique au chargement d'un niveau. Les scripts sont écrits via l'éditeur de code intégré, et permettent de décrire comment réagir aux événements du jeu. Godot étant un moteur riche, il n'y a pas besoin d'écrire beaucoup de texte pour faire fonctionner notre jeu. Pour qu'un script soit interprété par Godot, il faut l'attacher à un nœud, via l'éditeur. - Definition **variable** : valeur qui peut changer en cours du temps, que nous pouvons lire ou écrire depuis un script via son nom (exemple : boolean a_perdu_vie ; Vector2 direction_rebond). - Une variable attachée au nœud s'appelle **propriété** ou attribut (exemple : Vector2 position pour un Node2D). - Une variable qui est une entrée d'une fonction s'appelle un **argument** - Definition **fonction** : bout de script associé à un nom qui est exécuté quand on l'appelle. - Une fonction attachée à un nœud s'appelle aussi **méthode** - Le nom d'une fonction doit contenir un verbe, car appeler une fonction c'est faire quelque chose. - Pas à pas : - Bonnes pratiques - Style : - Typage (pour ceux qui savent coder) : - Héritage - Des scripts internes existent dans Godot, afin de coder les comportements des nœuds existants. Au début d'un script, on désigne de quel autre script on souhaite hériter, via le mot-clef `extends`. Le cas le plus commun est d'hériter 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 ! - Classe : une classe est un script qui a nom : `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. :-) - Bonjour grand-père : l'héritage peut être cumulatif. Si vous héritez de Sprite2D, qui hérite lui-même de Node2D, votre script possède à la fois les propriétés de Sprite2D (comme texture par exemple) et de Node2D (position). - Signaux (médium) 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. - Pas à pas : - Utiliser un signal dans un script : - Référence : - Espace - Les objets 2D sont positionnés dans l'espace via deux coordonnés : x et y. Très souvent utilisées ensemble, ces coordonnées sont regroupées dans un même objet : un vecteur. Dans Godot, les coordonnées sont en pixel (en 2D). Ici, l'écran est un carré de 420 pixels de côté. Si un nœud est positionné en x=0, y=0, il sera en haut à gauche. S'il est en x=210, y=420, il sera au milieu tout en bas de l'écran. - Image : voir l'illustration des axes de l'écran - Comprendre les vecteurs : - Référence : Vector2 ![Illustration des axes](vector_xy1.png) ### Étapes #### Lancer le jeu depuis l'éditeur - Actions - Démarrer l'exécutable de Godot : La fenêtre de gestion des projets s'ouvre (importation, création de nouveau projet, lancement de l'éditeur, etc). - Importer l'un des projets de casse-brique fournis ; l'éditeur s'ouvre automatiquement, sinon sélectionner le projet dans la liste et cliquer sur "Éditer". - Pour démarrer le jeu via l'éditeur, cliquer sur le bouton "lecture" situé en haut à droite de l'écran (à côté du bouton "stop" notamment). - Une nouvelle fenêtre s'ouvre et le jeu démarre. - Notion de scène principale - Lorsqu'on démarre le jeu (via l'éditeur ou un exécutable), ce qui est démarré est une scène dite "principale", définie dans l'éditeur. Et c'est de cette scène que vont ensuite être démarrées toutes les autres scènes qui composent le jeu. - Expliquer l'architecture des dossiers - Les dossiers des deux projets sont organisés de manière suivante : - "Composants", contient tous les composants qui une fois assemblés forment le jeu. On y trouve donc les scènes, script, visuels et sons pour : les interfaces, les objets (balle, brique, capsule, arène, raquette, etc) et enfin les pouvoirs (balle de feu par exemple). - "Effets", qui contient les évennements qui peuvent survenir en jeu. Pour l'instant le seul est l'éclatement d'une brique quand elle a été frappé suffisament de fois par la balle. - "Exec", qui contient les principales scènes du jeu qui vont "s'exécuter". On y trouve la scène principale du jeu ("game"), une scène de gestion de la musique et deux dossiers. Le dossier "choix" contient les éléments relatifs à l'écran de choix de niveau et à son fonctionnement et le dossier "niveaux" qui contient des scènes correspondante chacune à un niveau du jeu. - "Ressources", qui contient les musiques du jeu, ainsi que les textures utilisées. - Concernant les fichiers hors dossiers : - Nous avons les fichiers terminant par ".svg", qui sont des images servant d'icônes pour l'exécutable du projet, ces fichiers ne sont pas utilisé dans le jeu lui-même. - "project.godot" est le fichier principale du projet pour l'éditeur. C'est à partir de ce fichier que l'éditeur charge le projet pour qu'on puisse ensuite travailler dessus. - Les fichiers se terminant par ".import" sont des fichiers de configuration d'importation des visuels et sons créer par le Godot Engine. - Les fichiers se terminant par ".tres" sont des fichiers textes qui permettent au Godot Engine de gérer différents types de données pour différents usages. Ici par exemple, "default_bus_layout.tres" sert à gérer les flux audio dans le projet. Note : L'ensemble de ses fichiers et dossiers doivent être édité dans le l'éditeur de Godot et non directement via le navigateur de fichiers #### Graphisme En bleu sur la carte. ##### Changer l'image de la raquette Niv. 1 La raquette est un composant on va donc trouver la scène qui lui est dédié dans le dossier "composants/objets/raquette". La scène est le fichier ".tscn" dans le dossier. - Actions - Double-cliquer sur le fichier "raquette.tscn" pour ouvrir la scène de la raquette. La scène de la raquette est composée de 3 nœuds : - Un nœud StaticBody2D, - Un nœud Sprite2D, - 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 - Cliquer sur le nœud "image". 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. Avant de changer l'image, il ne faut pas oublier de mettre votre nouvelle image en .png dans le dossier "composants/objets/raquette". - Actions - Pour modifier l'image, cliquer sur la flèche qui pointe vers le bas dans le champs "Texture" et choisir "Charger" pour pouvoir importer votre image. - Alternativement, faire un glisser-déposer entre votre fichier dans le dossier "composants/objets/raquette" dans le panneau "Système de Fichier" et l'image visible dans le champs "Texture" de l'Inspecteur. ##### Changer la couleur de la raquette 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. - Actions - Double-cliquer sur le fichier "raquette.tscn" pour oublir la scène de la raquette. La scène de la raquette est composée de 3 nœuds : - Un nœud StaticBody2D, - Un nœud Sprite2D, - Un nœud CollisionShape2D. C'est le nœud Sprite2D, dénommé "image", qui va permettre de changer la couleur de la raquette. - Actions - Cliquer sur le nœud "image". 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 l'image de la raquette dans le jeu. - Actions - Cliquer sur le rectangle blanc pour accéder à la palette de couleurs. - Choisir une couleur. - Cliquer en dehors de la fenêtre du nuancier pour la faire disparaitre et valider la couleur choisie. Note : vous pouvez aussi changer la valeur du champ "Modulate" du noeud racine `StaticBody2D`, ce qui change la couleur de tous les enfants, y compris l'image. ##### Changer la couleur de la brique en fonction de sa vie 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. - Prérequis - La brique a des vies - Actions - Chercher le dossier contenant les composants de la brique. - Décommenter le code en rapport avec la vie de la brique dans le script "brique.gd". 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. ##### Faire une trainée à la balle Niv. 3 - Actions - Trouvez le composant balle, ouvrez la scène qui se trouve dans le dossier. - Ajouter un GPUParticle2D dans la scène. - Dans l'inspecteur, remplir le champs "Texture" avec le png fournie dans le dossier "effets/trainee". - Toujours dans l'inspecteur, ajouter un nouveau "Particule Process Material" dans le champs "Process Material". - Ressources - Texture de particule dans le dossier balle. - Doc - Pas à pas : - Référence (documentation brute) : 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 (. ##### Effet impact d'une balle Niv. 3 - Image : capture paramétrage effet de particule dans Kace - Actions - Créer un nouvel effet - Dans le dossier "effet/impact", créer une nouvelle scène. - Racine : Node2D / Enfant : GPUParticles2D. - Configurer l'effet de particules en one shot dans l'Inspecteur. - Supprimer le nœud une fois que l'effet de particule est terminer via un signal. - Créer l'effet - S'inspirer de l'effet d'éclatement de la brique pour l'invocation de la scène d'impact dans le script "brique.gd". - const EclatementScene: PackedScene = preload("res://effets/eclatement_brique/eclatement_effet.tscn"). - Instancier la scene et l'ajouter à l'arbre au moment du rebond dans le script de la balle. ##### Effet de flamme Niv. 3 - Action : modifier balle_de_feu.tscn - Change l'image de la balle - 02.png - Reset les propriétés modulate et scale - Tester - Diriger la balle en fonction de la direction - Ajouter une fonction "_diriger" qui met à jour l'orientation de la balle quand on l'appelle - Utiliser la méthode angle_to pour récupérer l'angle, par rapport à une constante de Vector2 (Vector2.UP si la balle va vers le haut, Vector2.RIGHT si elle va vers la droite). - Modifier la rotation de l'image (propriété rotation) - Appeler la fonction _diriger quand la balle se met en mouvement - décommenter le code - Appeler la aussi quand elle rebondit - idem pour _rebondir que _mettre_en_mouvement - Tester - Clignoter : Changer la valeur de flip_h de l'image à intervalle régulier - Utiliser $Image pour récupérer le nœud qui s'appelle - Utiliser une variable globale pour compter le temps (ajouter delta à chaque frame) - Utiliser une constante pour la durée du clignotement - Pour calculer votre clignotement à chaque image, mettez votre code dans la fonction _process - Doc - Réf AnimatedSprite2D#flip_v : 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 ##### Effet électrique Niv. 4 - Prérequis - Pouvoir éclair - Ressources - Texture de balle éclair - Actions - Associer l'image éclair au Sprite2D - S'inspirer de l'effet de flamme pour alterner les valeurs de frame, flip_h et flip_v à intervalles réguliers. - Mode expert : alterner aussi avec une seconde image - Doc - Référence : AnimatedSprite2D ##### Effet de récupération de pouvoir Niv. 4 - Prérequis - Scène pour l'effet de récup : Bruit lors de récupération d'un pouvoir, alternative 2 - Ressources - Animation de récupération de pouvoir - Actions - Ajouter un nœud AnimatedSprite2D à la scène `recup_pouvoir` dans le dossier `effets` - Attention : il ne faut détruire la scène avec queue_free quand le son et l'animation sont terminées ! - Documentation - Référence : #### Effet d'éruption de la raquette - Dépend du pouvoir laser - Actions - Créer une scène effet dans `effets/eruption` - Utiliser un `AnimatedSprite2D` pour faire l'effet d'éruption - Dans le TileSet - Importer les trois images d'éruption - Activer la lecture au chargement - Désactiver la lecture en boucle - Auto-détruire l'effet après l'animation - Brancher le signal `animation_finished` à la méthode `queue_free()` du nœud racine #### UI Interface utilisateur. ##### Créer un menu d'accueil Sera déjà fait, comme le menu pause. ##### Afficher le compteur de balles Niv. 2 - Actions - Décommenter la variable "nombre_de_balles" à 0 dans la scène "lanceur.tscn". - Ajouter (si n'existe pas encore) signal "nb_balles_change" dans la scène du lanceur. - Émettez le signal dans l'appel "_decrementer_nombre_de_balles()". - Ajouter un label dans la scène de niveau. - Brancher le signal du lanceur du niveau vers le compteur/label. - Répéter le branchement pour chaque niveau. > Note : 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. ##### Afficher une jauge de balles 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. - Remplacer un control par un nœud plus avancé fourni par Godot ##### Afficher un écran de game over Niv. 1 - Action - Décommenter le signal "partie_perdu" dans la scène du lanceur. - L'émettre quand il n'y a plus de balle (fonction "lancer_balle()"). - Brancher dans chaque niveau : - Le signal partie_perdue du lanceur vers le nœud "Message" et sa fonction "show()". - Le signal partie_perdue du lanceur vers le nœud "Message/Perdu" et sa fonction "show()". ##### Afficher un écran de victoire Niv. 3 : beaucoup d'étapes - Actions - S'inspirer de l'écran de game over pour créer l'écran de victoire. - Comprendre la logique de comptage des briques -> code à décommenter dans conteneur_briques.gd - Afficher le message dans chaque niveau - Ajouter votre nouvelle scène en tant que nœud enfant de Message - Brancher le signal aux bonnes fonctions (montrer écran + détruire lanceur). Note : comme les balles créées par le lanceur sont des nœuds enfants, détruire le lanceur détruit aussi toutes les balles. ##### Compter et afficher le score Niv. 4 : le·a participant·e se débrouille ##### Pouvoir scroller les planètes Niv. 1 - Prérequis - Scène "choix_niveau.tscn" qui permet déjà de choisir un niveau. - Actions - Ajouter un nœud ScrollContainer dans la scène "choix_niveau.tscn" - Mettre le SystemeSolaire en tant qu'enfant de ce nœud. - Redimensionner le ScrollContainer pour qu'il prenne l'espace visible. - Soit à la main dans la vue 2D. - Soit dans l'Inspecteur, section "Transform", champs "Size", mettre les valeurs de X et Y à 420. ##### Mécanique de pseudo Niv. 4 : le·a participant·e se débrouille Idem leaderboard, afficher pseudo en jeu. #### Sons Bruitages et musique. ##### Insérer une musique dans un niveau 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). - Prérequis - Musique dans le menu - Actions - Ajouter un nœud AudioStreamplayer dans la scène de niveau. - Charger la musique voulu dans le champs "Stream" de l'AudioStreamPlayer dans l'inspecteur. - Bien penser à cocher `loop` pour les musiques importées ! - Dans le champs Bus dans l'inspecteur, sélectionner : Musique - Cocher le champs "Autoplay". - Enfin dans la section "Process" changer le champs "Mode" pour la valeur "Always" (sinon la musique se mettra en pause lors de l'affichage du menu pause. - Référence - Le nœud AudioStreamPlayer : ##### Faire un bruit à l'impact d'une balle Niv 1 - Prérequis - La brique fait un bruit en explosant - La balle avec un signal rebondi - Actions - Ajouter le noeud AudioStreamPlayer dans la scene balle. - Charger le son "collision_sfx.wav" dans le champs "Stream" de l'AudioStreamPlayer dans l'inspecteur. - Brancher le signal "rebondi" de la balle à la fonction play() de l'AudioStreamPlayer. - Dans l'inspecteur de l'AudioStreamPlayer affecter le champs "Bus" au bus : Bruits ##### Faire un bruit au clic sur bouton début Niv. 2 - Actions - Ajout du son de clic bouton dans le Menu Pause : - Ajouter un AudioStreamPlayer dans la scène "pause_menu.tscn" - Nommer l'AudioStreamPlayer : "clic_sound". - Charger le son de clic dans le champs "Stream" de l'AudioStreamPlayer. - Dans le champs Bus dans l'inspecteur, sélectionner : Bruits - Ajouter "get_node("clic_sound").play()" dans les fonctions "_quand_bouton_reprendre_est_presse()", "_quand_bouton_retour_titre_est_presse()" et "_quand_bouton_quitter_est_presse()" dans le script "pause_menu.gd". - Ajout du son de clic bouton sur les planètes du Menu Principal : - Ajouter un AudioStreamPlayer dans la scène "choix_niveau.tscn" en enfant du nœud "DefilementNiveaux". - Nommer l'AudioStreamPlayer : "clic_sound". - Charger le son de clic dans le champs "Stream" de l'AudioStreamPlayer. - Dans le champs Bus dans l'inspecteur, sélectionner : Bruits - Ajouter "get_parent().get_parent().get_node("clic_sound").play()" dans la fonction "_quand_planete_est_cliquee()" dans le script "planete.gd". ##### Faire un bruit au game over Niv. 1 - Prérequis - Scène de partie perdu : "perdu.tscn". - Actions - Ajouter un noeud AudioStreamPlayer dans la scène "perdu.tscn". - Charger le son de partie perdu (game over) dans le champs "Stream" de l'AudioStreamPlayer. - Dans le champs Bus dans l'inspecteur, sélectionner : Bruits - Brancher le signal "visibility_changed()" du nœud "OhNon" ou du nœud "CommandeRetour" sur la fonction play() de l'AudioStreamPlayer. - Note : si vous ne voyez pas la fonction play, ecrivez son nom. ##### Bruit lorsqu'un pouvoir est récupéré Niv. 1 - Prérequis - Capsule implémentée - Actions - Possibilité 1 : signal - Ajouter un signal "capsule_recuperee" - Émettre le signal - Ajouter noeud AudioStreamPlayer - Brancher le signal sur la fonction play() de l'AudioStreamPlayer - Alternative 2 : son spatialisé -> effet graphique de récupération de pouvoir - Créer un effet : Créer un nouveau dossier "recup_pouvoir" dans le dossier "effets" - Instancier un AudioStreamPlayer2D depuis le code (même emplacement que le signal possibilité 1) ##### Effet audio dynamique : diminuer l'importance de la musique quand un effet sonore joue 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. - Prérequis - Avoir deux bus, un bus "Bruits" pour les effets sonores et un bus "Musique" pour la musique. - Actions - Ajouter un effet "Compressor" (compresseur) dans le bus "Musique". - Régler les paramètres du compresseur dans l'Inspecteur comme suit : - "Threshold" (seuil de décibel à partir duquel l'effet s'active) : -17. - "Ratio" (ratio de diminution du volume du son quand le compresseur est actif) : 1.8. - "Release" (temps pendant lequel le compresseur reste actif une fois le volume du son revenu sous le seuil) : 50 ms. 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. ##### Effet audio dynamique sur le menu pause Niv. 3 Il faut ici passer par un peu de script pour piloter le bus "Musique" et activer l'un de ses effets. - Actions - Ajouter un effet "LowPassFilter" sur le bus "Musique" et laisser ses réglages par défaut. - Désactiver l'effet dans le bus (case à décocher) pour que l'effet soit éteint au démarrage du jeu. - Ouvrir la scène "pause_menu.tscn" et passer la vue en mode script. - Repérer dans le script "pause_menu.gd" la fonction "_unhandled_input(event: InputEvent)" et ajouter dans le "else" de l'embranchement : "AudioServer.set_bus_effect_enabled(2,1, true)" pour activer le "LowPassFilter" à l'apparition du menu pause. - Repérer dans le script "pause_menu.gd" la fonction "reprendre()" et ajouter "AudioServer.set_bus_effect_enabled(2,1, false)" pour désactiver l'effet quand le menu pause se ferme. - Documentation - Manipuler les bus audio avec la classe AudioServer : #### Exportation - Documentation - #### Architecte ##### Modifier le niveau existant Niv. 1 - Actions - Dans la vue 2D, configurer la grille (bouton "Option d'aimantation") avec les valeurs suivantes : - Décalage : x = 30, y = 0. - Pas : x = 30 px, y = 16 px (taille d'une brique). - Ligne primaire tous les : x = 4 pas, et y = 8 pas. - Dupliquer les nœuds Brique pour en créer de nouveaux et placer-les dans le niveau. - Changer les paramètres de chaque brique indépendament dans l'Inspecteur. Image : Capture de la configuration de la grille ![Capture de la configuration de la grille](editor_gd4_raquette_config_grille.png) ##### Créer un autre niveau Niv. 1 - Actions - Dupliquer la scène d'un niveau. - Modifier le niveau existant. - Ajouter un niveau au menu : - Aller dans la scène "choix_niveau". - Dupliquer un nœud planète. - Placer la nouvelle planète dans un endroit vide du ciel étoilé dans la vue 2D. - Modifier le champ "Niveau" de la planète dans l'Inspecteur pour choisir votre niveau. - Modifier le champs "Normal" de la section "Texture" pour changer l'image de la planète. #### Artisan ##### Faire descendre les briques au fil du temps Niv. 2 Complètement facultatif. - Actions - Créer un script qui hérite de "ConteneurDeBriques". - Créer une constante vitesse_de_descente := 5.0 # px/sec. - Appliquer la descente à chaque image (frame) via la fonction "_physics_process". ##### Faire perdre la partie si une brique sort du terrain Niv. 4 - Prérequis - Les briques descendent au fil du temps. - Actions - Modifier l'arène pour que la zone du bas, appelée ZoneExterieure, détecte les collisions avec les briques (collision_layer: mask) - Faire en sorte que l'arène envoit un signal quand une brique est détectée par la zone extérieure - Relier ce signal au même signal que le game over classique ##### Avoir un nombre limité de vies Niv. 2 - Actions - Ouvrir le script du lanceur. - Décommenter le code qui permet de configurer le nombre de balles via l'éditeur. - Écrire une fonction "_decrementer_nombre_de_balles() -> void". - Qui soustrait 1 au nombre de balles. - Modifier la fonction "lancer_balle". - Rajouter un test, s'il n'y a plus de balle, arrêter la fonction avec le mot-clef "return". - Note : "return" interrompt une fonction. - Astuce : afficher le nombre de balles après chaque décrémentation avec une fonction "print()" ##### Faire accélérer la balle Niv. 2 - Actions - Créer, dans le script de la balle, une constante : "acceleration_par_touche: float = 50.0 # px / sec / touche" - Modifier la fonction "_accelerer" qui augmente la vitesse de la balle quand elle est appelée. - Utiliser la constante précédente pour modifier la propriété vitesse de la balle. - Pour appliquer la nouvelle vitesse, vous devez aussi appeler la fonction "_mettre_mouvement". - Alternative 1 : accélerer à chaque touche de raquette. - Dans "_physics_process" : Appeler "_accelerer" après chaque rebond sur une raquette. - Note : 50 px / sec / touche c'est bien pour avoir un bon challenge. - Alternative 2 : accélerer à chaque rebond. - Dans "_physics_process" : Appeler "_accelerer" après chaque rebond. - Note : 10 px / sec / touche c'est bien pour avoir un bon challenge. ##### Passer au niveau suivant une fois un niveau terminé Niv. 4 Attribut par niveau, script niveau. ##### Pouvoir configurer le nombre de vies d'une brique Niv. 3 - Actions - Modifier "brique.gd" comme suit : - Décommenter la constante "NOMBRE_DE_VIES_MAX". - Décommenter la variable "nombre_de_vies". - Modifier la fonction "frapper" pour réduire les points de vie, et ne mourir que s'il n'en reste plus. - Décommenter "_montrer_nombre_de_vies" et la fonction qui l'appelle. - Modifier les niveaux pour ajuster la vie. - Ouvrir le niveau carré simple. - Mettre 4 vies au bloc central. - Astuce : vous pouvez sélectionner plusieurs briques en les selectionnant. - La propriété nombre de vies est visible dans l'éditeur grâce au préfixe "@export". 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é. ##### Faire un obstacle avec une nouvelle forme Niv. 3 - Actions - Nouvelle scène de racine StaticBody2D. - Nouvelle forme (sphérique par exemple). - Texture que vous voulez (planète par exemple). - Configurer les calques de collision. - C'est un mur (cochez la case "mur" dans le damier "collision_layer"). - Ça collisionne avec les balles (cochez la case "mur" dans le damier "collision_mask"). - Calques de collision. - Explications : - Référence : ##### Faire une brique avec une nouvelle forme Niv. 4 - Actions - Créer un dossier "brique_spherique" (ou autre forme) dans le dossier brique. - Copier la scène de brique dans ce dossier et la renommer pour obtenir "brique_spherique.tscn". - Modifier la forme et la texture pour l'accorder à votre besoin. - L'ajouter au niveau de votre choix. Note : comme votre nouvelle brique a le même script que la brique de base, les deux ont le même comportement ! ##### Collectibles qui donne des points Niv. 4 - Prérequis - Compteur de score. - Actions - Créer un pouvoir "ScoreBonus" (voir ci-dessous). - Associer un groupe à votre compteur de score. - Incrémenter le score quand le pouvoir est déclenché. ##### Pouvoir de ralentissement Niv. 3 - Prérequis - Capsule qui permet de libérer un pouvoir contenu dans une brique. - Actions - Ajouter un frein sur la balle. - Ajouter la balle dans le "groupe_des_balles". - Voir : Avoir un nombre de vies limité. - Décommenter la méthode "ralentir". - Créer un nouveau pouvoir. - Copier le script "bonjour_pouvoir.gd" et le renommer en "pouvoir_ralentir.gd". - Changer le nom de la classe en "RalentirPouvoir". - Choisir la couleur en modifiant la valeur retournée par "couleur_principale" (exemple : Color.WEB_GREEN). - Dans "association_pouvoirs.gd" : - Ajouter le type de pouvoir dans l'énumération "Type". - Associer votre script dans la fonction statique "fabriquer". - Facultatif : associer une texture de brique pour un type de pouvoir : - les textures possibles sont dans le dossier "composants/objets/brique/images/". - L'association est faite dans la "methode _associe_texture_brique" dans "brique.gd". - Associer votre nouveau pouvoir à une brique dans un niveau. - Écrire l'effet du pouvoir dans "declencher_pouvoir". - Écrire l'effet du pouvoir dans "declencher_pouvoir" : - Renommer l'argument "_arbre_scene" en "arbre_scene". - Pour toutes les balles, appeler la méthode "ralentir(3.0)". - À l'intérieur écrire une boucle "for", comme suit : "for balle in arbre_scene.get_nodes_in_group("groupe_des_balles"):" - Note : le pouvoir est fabriqué au moment où la capsule est libérée, quand la brique est détruite. - Note : préfixer un argument par "_" permet de dire à Godot que c'est normal que l'argument ne soit pas utilisé. - Documentation - Un vecteur normalisé a une longeur de 1 : - Référence arbre des nœuds : - Explication détaillée du fonctionnement de l'arbre des nœuds : ##### Pouvoir de vie/balles supplémentaires Niv. 3 - Prérequis - Pouvoir existant. - Affichage du nombre de balles restante. - Actions - Ajouter la fonction "incrementer_nombre_de_balles" dans le lanceur. - N'oubliez pas d'émettre le signal "nb_balles_change" ! - Cliquer sur le nœud "Lanceur" dans un niveau, puis dans l'onglet nœud → groupes, l'ajouter au "groupe_des_lanceurs" - Voir l'image qui montre comment ajouter au groupe des lanceurs - En déclenchant le pouvoir, récupérer le lanceur via son groupe, et appeler la fonction "incrementer_nombre_de_balles". - Utiliser la fonction "get_first_node_in_group()". - Documentation - Référence pour récupérer un nœud d'un groupe : ![Capture de l'ajout du groupe des lanceurs](editor_gd4_raquette_ajout_groupe_des_lanceurs.png) ##### Pouvoir agrandissement raquette Niv. 4 - Actions - Ajouter un pouvoir. - Mettre la raquette dans le groupe. - Ajouter une methode publique "changer_taille" pour modifier sa taille. - /! Il faut modifier la taille de l'image et la taille de l'enveloppe physique ! - Dans le déclenchement du pouvoir, appeler la methode "changer_taille" sur toutes les raquettes. ##### Malus diminution taille de raquette Niv. 4 - Idem ci-dessus, modulo le facteur de taille. ##### Faire une carte de niveaux interactive Niv. 4 ##### Pouvoir de feu 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. - S'inspirer du pouvoir de ralentissement pour faire le pouvoir - Nom classe : "PouvoirFeu". - Couleur : "Color.RED". - Actions - Déclenchement du pouvoir : comme pour le ralentissement, le pouvoir doit être effectué sur toutes les balles. - Appeler la méthode statique "BalleDeFeu.transformer(balle)". Note : une méthode statique est une fonction qui peut être appelée sans avoir à créer l'objet associé. ##### Pouvoir laser Niv. 4 Permet à la raquette de lancer un javelot à haute énergie qui détruit tout sur son passage ! - Prérequis - Assets graphiques javelot - Actions - Créer le javelot dans le dossier `javelot` - La racine de la scène est un `Node2D` - Ajouter l'image du javelot `mcJavelot.png` - Utiliser une `Area2D` pour déterminer la zone de destruction - Donner lui une forme en ajoutant un enfant `CollisionShape2D` - Définir une forme carrée au sommet de la flèche - Coder le comportement du javelot - Attachez un nouveau script au javelot - Monter le javelot à chaque image - Pensez à utiliser l'argument `delta` de `physics_process` - Créer une fonction `_quand_corps_entre_dans_zone_destructive` - La fonction prend en argument un `corps: Node2D` - Brancher le signal `body_entered` de la zone de destruction à cette fonction - Si le corps est une brique, frapper là ! - Auto-détruire le javelot lorsqu'il sort de l'écran - Ajouter le nœud `VisibleOnScreenNotifier2D` - Brancher le signal `screen_exited` à la méthode `queue_free()` du nœud racine - Faire un nouveau pouvoir - Déclenchement - Créée un nouveau javelot à l'endroit de la raquette - Débloque : fait un effet d'eruption à la surface de la raquette - Docs - [Comment utiliser les Area2D](https://docs.godotengine.org/fr/4.x/tutorials/physics/using_area_2d.html) - [Référence Area2D](https://docs.godotengine.org/fr/4.x/classes/class_area2d.html) ##### Pouvoir électrique Niv. 4 La balle électrique possède une zone d'influence qui détruit les briques à distance. - Dépend de laser - Prérequis - Image de la balle électique (animée dans un autre chapitre) - Actions - Copier la scène balle de feu. - Le pouvoir électrique va fonctionner de manière analogue au pouvoir de feu : lorsqu'il est déclenché, toutes les balles sont transformée - La balle électrique contient une Area2D qui va scanner les briques, et leur mettre des dégâts - Bonus : rajouter un délai entre le moment où la zone électrique touche une brique et le moment où celle-ci subit le dégât - Docs - [Référence nœud Timer](https://docs.godotengine.org/fr/4.x/classes/class_timer.html) - [Référence timer sans nœud](https://docs.godotengine.org/fr/4.x/classes/class_scenetree.html#class-scenetree-method-create-timer) ##### Pouvoir balle collante Niv. 4 La balle colle à la raquette, et peut être renvoyée avec un clic ou un appui sur espace. ##### Pouvoir balle spectrale Niv. 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. - Docs - [Masques de collision](https://docs.godotengine.org/en/4.2/tutorials/physics/physics_introduction.html#collision-layers-and-masks) ##### Faire un nouveau pouvoir de balle Niv. 4 À vous de l'imaginer, et de l'implémenter. :-)