Mécanique des Projectiles en Godot¶
Introduction¶
La mécanique des projectiles est une partie importante dans la création de jeux 2D ou 3D. Un projectile est généralement un objet qui se déplace à une vitesse fixe et suit une trajectoire, souvent influencée par la physique ou les interactions avec l'environnement.
Objectifs d'apprentissage¶
- Comprendre comment créer un projectile dans Godot.
- Utiliser des forces et la physique pour simuler le mouvement d'un projectile.
- Implémenter des comportements comme les collisions ou la désactivation des projectiles hors de l'écran.
- Gérer le tir des projectiles dans un intervalle de temps.
- Optimiser les performances en utilisant le pooling d'objets pour les projectiles.
Note
J'utiliserai les ressources "Top-down shooter" de Kenney pour les graphismes des projectiles. Vous pouvez les trouver sur Kenney.nl.
Création d’un projectile simple¶
Pour commencer, nous allons créer un projectile basique qui se déplace en ligne droite. Le projectile sera instancié et ajouté à la scène lorsqu'un bouton est pressé.
Pour créer un projectile, nous pouvons utiliser un Node2D ou un RigidBody2D selon la complexité des interactions physiques souhaitées.
Dans cette leçon, nous allons utiliser un Node2D pour un projectile simple qui se déplace horizontalement.
Voici la hiérarchie de noeud que l'on aura :
Node2D(Projectile)Sprite2D(Apparence du projectile)Area2D(Zone de collision)CollisionShape2D(Forme de collision)
Voici l'image utilisée pour le Sprite2D du projectile :

Exemple de projectile avec Node2D¶
On attachera un script au Node2D pour gérer le mouvement du projectile.
Il faudra connecter le signal body_entered de l'Area2D à la méthode _on_area_2d_body_entered pour gérer les collisions.
Comprendre transform.x¶
Le transform est la propriété qu'on retrouve dans l'inspecteur pour les noeuds 2D : elle regroupe la position, la rotation et l'échelle du noeud par rapport à son parent.
Imagine que ton projectile a une flèche invisible collée dessus, qui pointe toujours « vers l'avant » (comme le nez d'une fusée). Quand le projectile tourne, la flèche tourne avec lui et continue de pointer dans la même direction que lui.
transform.x, c'est exactement cette flèche : la direction « vers l'avant » du noeud. Elle mesure toujours 1 (une flèche « unitaire »), donc elle sert seulement à indiquer où le noeud regarde, pas à quelle distance.
Par exemple :
- Si le projectile n'est pas tourné du tout (rotation à 0°),
transform.xpointe vers la droite de l'écran. - Si on le tourne de 90° vers le bas,
transform.xpointe maintenant vers le bas — la flèche a suivi la rotation.
C'est pour ça qu'on peut écrire position += transform.x * speed * delta : à chaque image, on avance le projectile d'un petit pas dans la direction où il pointe actuellement, peu importe son orientation.
Explication¶
- On retire le projectile lorsqu'il entre en collision avec un autre corps.
- On retire également le corps représentant l'ennemi lorsqu'il est touché par le projectile.
Création d'un tireur de projectiles simple¶
Pour le tireur de projectiles, nous allons utiliser un CharacterBody2D qui peut se déplacer et tirer des projectiles.
Voici l'image qui sera utilisé pour le tireur :

Voici la hiérarchie de noeud que l'on aura :
CharacterBody2D(Tireur de projectiles)Sprite(Apparence du tireur)CollisionShape2D(Forme de collision)Camera2D(Caméra pour suivre le tireur)Marker2D(Marqueur pour la direction du tir)


Code pour le tireur de projectiles¶
Explication¶
get_input(): Gère les entrées du joueur pour déplacer le tireur et tirer.look_at(): Oriente le tireur vers la position de la souris.transform.x: Vecteur de direction du tireur.shoot(): Instancie un projectile, l'ajoute à la scène principale et le positionne au niveau duMuzzle(point de tir).global_transform: Est une propriété qui permet de positionner un noeud dans l'espace global de la scène.
Gestion des tirs avec intervalle de temps¶
Pour simuler un intervalle entre les tirs, nous devons ajouter quelques éléments pour la gestion du temps.
Il faudra connaître la fréquence de tir et le temps écoulé depuis le dernier tir pour déterminer si le tireur peut tirer à nouveau.
Exemple d'implémentation :
Explication :¶
shoot_interval: Définit l'intervalle de temps entre les tirs.time_since_last_shot: Un accumulateur qui suit le temps écoulé depuis le dernier tir.
Optimisation des projectiles (Object pooling)¶
Dans les jeux, tirer et détruire des projectiles à répétition peut être coûteux en termes de performance. Une méthode efficace consiste à recycler les projectiles (Object Pooling). Au lieu de détruire les projectiles, ils sont désactivés et réutilisés. Cela réduit les allocations de mémoire et les suppressions, ce qui peut améliorer significativement les performances, surtout lorsque de nombreux projectiles sont générés.
Il faudra créer un nouvelle scène pour le Pool de projectiles. Cette scène ne contiendra qu'un Node que nous nommerons BulletPool. Ce Node contiendra un tableau de projectiles disponibles et un tableau de projectiles actifs.
Création du Pool d'objets¶
Voici le code pour le Pool de projectiles :
Dans l'inspecteur, il faudra associer la scène Bullet au BulletPool de projectiles pour qu'il puisse instancier les projectiles.
Explication
bullet_pool: Tableau de tous les projectiles créés.available_bullets: Tableau des projectiles disponibles pour le tir.- La première étape consiste à créer un pool de projectiles lors de l'initialisation.
get_bullet(): Récupère un projectile disponible dans le pool.return_bullet(): Réinitialise et retourne le projectile dans le pool.
Modification du tireur pour utiliser le Pool¶
Il faudra adapter le tireur pour utiliser le Pool de projectiles au lieu d'instancier de nouveaux projectiles à chaque tir.
Il faudra modifier le Player à quelques endroits pour utiliser le BulletPool
Explication
bullet_pool_scene: Référence à la scène duBulletPool.bullet_pool: Instance duBulletPooldans le jeu.bullet_pool.get_bullet(): Récupère un projectile du pool pour le tir.
Modification du projectile¶
Le projectile émettra un signal lorsqu'il sortira de l'écran pour être recyclé dans le BulletPool. Ce dernier écoutera ce signal pour récupérer le projectile et le remettre dans le pool.
Autres améliorations possibles¶
- Créer un Singleton pour gérer les
Poolsde projectiles. - Créer une fabrique de projectiles pour gérer différents types de projectiles.
- Détacher la dépendance du
BulletPooldu tireur.
Conclusion¶
Les projectiles dans Godot sont simples à implémenter mais peuvent devenir complexes en fonction des interactions et des effets que vous souhaitez ajouter. En utilisant des méthodes comme le pooling et la gestion des collisions, vous pouvez optimiser les performances et gérer efficacement de nombreux projectiles à l'écran.