🍎 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 :
- Une zone de détection (
Area2D
) - Une pomme visible (
Sprite2D
) - Une collision (
CollisionShape2D
) - Un signal qui fait disparaître l’objet quand le joueur le touche
- 🔊 Un son de collecte
- 📝 Un message à l’écran
🧱 É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 :
Sprite2D
(affiche la pomme)CollisionShape2D
(forme de détection, cercle ou carré)
🎨 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 :
- Coche ✅ “Monitorable”
- Coche ✅ “Monitoring”
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)
- Clique droit sur
Pomme
> Signals - Double-clique sur
body_entered
- 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
.
- Ajoute dedans un
Label
(ouRichTextLabel
) et positionne-le en haut de l’écran - Donne-lui un nom comme
MessageLabel
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
- Ajoute un node
AudioStreamPlayer2D
dans la scènePomme
- Glisse ton son (ex:
GS2_Item_Acquire_1.wav
) dans le champStream
- 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