View on GitHub

Journal de développement - Mon RPG Zelda

Suivi du développement de mon jeu de type Zelda avec Godot Engine

🍎 Créer une pomme à ramasser – version améliorée (HUD + son + sécurisation) dans Godot 4.4

Dans cette leçon, on va apprendre à créer un objet à ramasser, comme une pomme 🍏, que le joueur peut récupérer en marchant dessus. C’est parfait pour des jeux type Zelda !


🎯 Objectif

Créer un objet ramassable avec :


🧱 Étapes de construction

1️⃣ Crée une nouvelle scène Pomme.tscn

Node principal : Area2D
Renomme le node en Pomme


2️⃣ Ajoute les nodes suivants :

🎨 Sprite : mets une image de pomme (tu peux utiliser un petit sprite 16x16)
⚠️ Le CollisionShape2D doit bien recouvrir la pomme, mais pas trop large non plus.


3️⃣ Active la détection

Sélectionne le node Pomme (Area2D), et dans l’inspecteur :

Ces options permettent de détecter quand un autre corps entre dans la zone.


🔔 Connecter le signal body_entered

Il y a deux façons de connecter un signal dans Godot.


🧷 Méthode 1 : Via l’éditeur (visuelle)

  1. Clique droit sur Pomme > Signals
  2. Double-clique sur body_entered
  3. Connecte-le à un script (tu peux créer un nouveau script sur Pomme.gd)
func _on_body_entered(body):
	if body.name == "Player":
		queue_free()

💻 Méthode 2 : Par le code (programmée)

Tu peux aussi connecter le signal dynamiquement dans _ready() :

func _ready():
	connect("body_entered", Callable(self, "_on_body_entered"))

func _on_body_entered(body):
	if body.name == "Player":
		queue_free()

👉 Cette méthode est utile quand tu veux générer les objets par code ou si tu préfères gérer tous les signaux dans le script.


🧪 Exercices & Solutions 🍏

Voici quelques idées pour t’entraîner à partir de ce que tu viens d’apprendre, avec des explications détaillées.


🍄 1. Remplacer la pomme par un autre objet

Tu peux utiliser une clé 🗝️, un cœur ❤️, un champignon magique 🍄, etc.

➡️ Pour cela, change simplement le sprite dans le Sprite2D du node Pomme.


🧾 2. Afficher un message quand l’objet est ramassé

🧱 Étape 1 : Créer une interface HUD

Ajoute un nouveau node CanvasLayer dans ta scène principale et appelle-le HUD.

Exemple d’arborescence :

MainScene
├── Player
├── HUD (CanvasLayer)
│   └── MessageLabel (Label)

🧠 Étape 2 : Script sur le HUD

# HUD.gd
extends CanvasLayer

func afficher_message(texte: String):
	$MessageLabel.text = texte

🧠 Étape 3 : Depuis la pomme, appeler le HUD

func _on_body_entered(body):
	if body.name == "Player":
		var hud = get_tree().root.get_node("MainScene/HUD")
		hud.afficher_message("🍏 +1 Pomme")
		queue_free()

⚠️ Remplace "MainScene/HUD" par le bon chemin dans ton projet !


🔊 3. Jouer un son lors de la collecte

  1. Ajoute un node AudioStreamPlayer2D dans la scène Pomme
  2. Glisse ton son (ex: GS2_Item_Acquire_1.wav) dans le champ Stream
  3. Modifie le script :
@onready var audio = $AudioStreamPlayer2D

func _on_body_entered(body):
	if body.name == "Player":
		audio.play()
		hide()  # On rend la pomme invisible immédiatement
		await audio.finished
		queue_free()  # On la supprime après le son

❓ Que fait hide() exactement ?

La méthode hide() rend le node invisible (visible = false) mais ne le supprime pas.
Cela permet de masquer l’objet tout en laissant un son ou une animation se terminer.


⏳ Et await audio.finished ?

Cette ligne permet de mettre en pause l’exécution du code jusqu’à ce que le son se termine.

Concrètement :

await audio.finished

➡️ Attend que le AudioStreamPlayer2D ait fini de jouer.
➡️ Une fois terminé, le code continue (ici : queue_free())

⚠️ C’est très pratique pour éviter de couper un son en supprimant l’objet trop tôt.


🧠 Exemple complet :

@onready var audio = $AudioStreamPlayer2D

func _on_body_entered(body):
	if body.name == "Player":
		get_tree().root.get_node("MainScene/HUD").afficher_message("🍏 +1 Pomme")
		audio.play()
		hide()
		await audio.finished
		queue_free()

💡 Bonus de pro : éviter que le son se rejoue si le joueur revient !

Parfois, même après avoir caché l’objet, la collision reste active.
Ce qui fait que si le joueur repasse sur la zone… le son se rejoue encore 😱

Pour corriger ça, il suffit de supprimer la collision juste après la détection :

@onready var collision_shape = $CollisionShape2D

func _on_body_entered(body):
	if body.name == "Player":
		collision_shape.call_deferred("queue_free")
		audio.play()
		hide()
		await audio.finished
		queue_free()

✅ Résultat : la pomme ne peut plus être “ramassée” deux fois même par erreur 🎯


👩‍💻 Écrit par : Lysdora
🎮 Projet : mon-rpg-zelda