Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Instanciation avec des signaux

Les signaux fournissent un moyen de découpler les objets du jeu, ce qui vous permet d'éviter de forcer un arrangement fixe de nœuds. Un signe qu'un signal peut être appelé est lorsque vous vous trouvez en train d'utiliser get_parent(). Se référer directement au parent d'un nœud signifie que vous ne pouvez pas facilement déplacer ce nœud à un autre endroit de l'arbre de scènes. Cela peut être particulièrement problématique lorsque vous instanciez des objets au moment de l'exécution et que vous souhaitez les placer à un endroit arbitraire dans l'arbre de scènes en cours d'exécution.

Nous allons examiner ci-dessous un exemple d'une telle situation : tirer des balles.

Exemple de tir

Imaginez un personnage joueur qui peut tourner et tirer vers la souris. Chaque fois que le bouton de la souris est cliqué, nous créons une instance de la balle à l'emplacement du joueur. Voir Création d'instances pour plus de détails.

Nous allons utiliser une Area2D pour la balle, qui se déplace en ligne droite a une vitesse donnée :

extends Area2D

var velocity = Vector2.RIGHT

func _physics_process(delta):
    position += velocity * delta

Cependant, si les balles sont ajoutées en tant qu'enfants du joueur, elles resteront "attachées" au joueur lors de sa rotation :

../../_images/signals_shoot1.gif

Au lieu de cela, nous avons besoin que les balles soient indépendantes du mouvement du joueur - une fois tirées, elles doivent continuer à voyager en ligne droite et le joueur ne peut plus les affecter. Au lieu d'être ajouté à l'arbre de la scène en tant qu'enfant du joueur, il est plus logique d'ajouter la balle en tant qu'enfant de la scène de jeu "principale", qui peut être le parent du joueur ou même plus haut dans l'arbre.

Vous pouvez le faire en ajoutant directement la balle à la scène principale :

var bullet_instance = Bullet.instantiate()
get_parent().add_child(bullet_instance)

Cependant, cela conduira à un problème différent. Maintenant, si vous essayez de tester votre scène "Player" de manière indépendante, elle se bloquera lors du tir, car il n’y a pas de nœud parent auquel accéder. Cela rend beaucoup plus difficile le test indépendant du code de votre joueur et signifie également que si vous décidez de modifier la structure des nœuds de votre scène principale, le parent du joueur risque de ne plus être le nœud approprié pour recevoir les balles.

La solution consiste à utiliser un signal pour "émettre" les balles du joueur. Le joueur n'a alors pas besoin de "savoir" ce qu'il advient des balles après cela. Quel que soit le nœud connecté au signal, il peut "recevoir" les balles et prendre les mesures appropriées pour les générer.

Voici le code pour le joueur utilisant des signaux pour émettre la balle :

extends Sprite2D

signal shoot(bullet, direction, location)

var Bullet = preload("res://bullet.tscn")

func _input(event):
    if event is InputEventMouseButton:
        if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
            shoot.emit(Bullet, rotation, position)

func _process(delta):
    look_at(get_global_mouse_position())

In the main scene, we then connect the player's signal (it will appear in the "Node" tab of the Inspector)

func _on_player_shoot(Bullet, direction, location):
    var spawned_bullet = Bullet.instantiate()
    add_child(spawned_bullet)
    spawned_bullet.rotation = direction
    spawned_bullet.position = location
    spawned_bullet.velocity = spawned_bullet.velocity.rotated(direction)

Maintenant, les balles conserveront leur propre mouvement indépendamment de la rotation du joueur :

../../_images/signals_shoot2.gif