| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 | .. meta::    :keywords: Signal.. _doc_instancing_with_signals:Instancing with signals=======================Signals provide a way to decouple game objects, allowing you to avoid forcing afixed arrangement of nodes. One sign that a signal might be called for is whenyou find yourself using ``get_parent()``. Referring directly to a node's parentmeans that you can't easily move that node to another location in the scene tree.This can be especially problematic when you are instancing objects at runtimeand may want to place them in an arbitrary location in the running scene tree.Below we'll consider an example of such a situation: firing bullets.Shooting example----------------Consider a player character that can rotate and shoot towards the mouse. Everytime the mouse button is clicked, we create an instance of the bullet at theplayer's location. See :ref:`doc_instancing` for details.We'll use an ``Area2D`` for the bullet, which moves in a straight line at agiven velocity:.. tabs:: .. code-tab:: gdscript GDScript    extends Area2D    var velocity = Vector2.RIGHT    func _physics_process(delta):        position += velocity * delta .. code-tab:: csharp    using Godot;    public partial class Bullet : Area2D    {        public Vector2 Velocity { get; set; } = Vector2.Right;        public override void _PhysicsProcess(double delta)        {            Position += Velocity * (float)delta;        }    }However, if the bullets are added as children of the player, then they willremain "attached" to the player as it rotates:.. image:: img/signals_shoot1.gifInstead, we need the bullets to be independent of the player's movement - oncefired, they should continue traveling in a straight line and the player can nolonger affect them. Instead of being added to the scene tree as a child of theplayer, it makes more sense to add the bullet as a child of the "main" gamescene, which may be the player's parent or even further up the tree.You could do this by adding the bullet to the main scene directly:.. tabs:: .. code-tab:: gdscript GDScript    var bullet_instance = Bullet.instantiate()    get_parent().add_child(bullet_instance) .. code-tab:: csharp    Node bulletInstance = Bullet.Instantiate();    GetParent().AddChild(bulletInstance);However, this will lead to a different problem. Now if you try to test your"Player" scene independently, it will crash on shooting, because there is noparent node to access. This makes it a lot harder to test your player codeindependently and also means that if you decide to change your main scene'snode structure, the player's parent may no longer be the appropriate node toreceive the bullets.The solution to this is to use a signal to "emit" the bullets from the player.The player then has no need to "know" what happens to the bullets after that -whatever node is connected to the signal can "receive" the bullets and take theappropriate action to spawn them.Here is the code for the player using signals to emit the bullet:.. tabs:: .. code-tab:: gdscript GDScript    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()) .. code-tab:: csharp    using Godot;    public partial class Player : Sprite2D    {        [Signal]        public delegate void ShootEventHandler(PackedScene bullet, float direction, Vector2 location);        private PackedScene _bullet = GD.Load<PackedScene>("res://Bullet.tscn");        public override void _Input(InputEvent @event)        {            if (@event is InputEventMouseButton mouseButton)            {                if (mouseButton.ButtonIndex == MouseButton.Left && mouseButton.Pressed)                {                    EmitSignal(SignalName.Shoot, _bullet, Rotation, Position);                }            }        }        public override void _Process(double delta)        {            LookAt(GetGlobalMousePosition());        }    }In the main scene, we then connect the player's signal (it will appear in the"Node" tab of the Inspector).. tabs:: .. code-tab:: gdscript GDScript    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) .. code-tab:: csharp    private void OnPlayerShoot(PackedScene bullet, float direction, Vector2 location)    {        var spawnedBullet = bullet.Instantiate<Bullet>();        AddChild(spawnedBullet);        spawnedBullet.Rotation = direction;        spawnedBullet.Position = location;        spawnedBullet.Velocity = spawnedBullet.Velocity.Rotated(direction);    }Now the bullets will maintain their own movement independent of the player'srotation:.. image:: img/signals_shoot2.gif
 |