My custom signal is not being received

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By zantonius

So, I have this code in “Mob.gd”

extends RigidBody2D
signal bullet_hit

func _on_Mob_body_entered(body):
    print("A bullet hit me")
	emit_signal("bullet_hit")
	queue_free()

And this code i “Bullet.gd”

extends RigidBody2D
func _on_bullet_hit():
	print("Bullet hit something")
	queue_free()

The two signals are connected via the Godot GUI as in the attached image.

It’s printing: “A bullet hit me”, and removing the mob. But for some reason, the “_on_bullet_hit()”-function doesn’t run. Can someone explain what I’ve missed? I know I could try to get this to work via code, but I wish to use the GUI for this.

Thanks in advance,
Zantonius

Check that the Bullet.gd script is attached to the right node.
Right click on the signal in the inspector select go to method.
Would like to see a picture of your node tree.

LeslieS | 2023-01-16 00:20

Thank you for your reply! Please see the attached image with the node tree and the dialog that shows when I click on the green arrrow next to the function “_on_bullet_hit” in Bullet.gd.
Screenshot - 55a79ca5eeaef63632494ed06c61ed7e - Gyazo

zantonius | 2023-01-16 08:30

It may be worth considering redesigning a bit, depending on what you’re wanting to do. Let’s say you want a Bullet to delete if it strikes a Mob. Let’s say you’ve defined the function to do that in bullet.gd, and named it bullet_hit_mob.

bullet_hit_mob():
    print("Bullet hit something... deleting bullet")
    queue_free()

When a Bullet enters a Mob, you’ve already got it set up to trigger the _on_Mob_body_entered function in mob.gd. So in _on_Mob_body_entered you can check if whatever collided with Mob is a bullet, and if it is you can call the bullet_hit_mob function to delete the bullet:

_on_Mob_body_entered(body):
    if body.is_in_group("bullet"):
        print("Calling bullet_hit_mob on the bullet that hit this mob")
        body.bullet_hit_mob()

To make this work you need to open up your Bullet.tscn and add it to a group named bullet. Screenshot - 320d2782b9af8eda0dad02620d19ed1c - Gyazo The reason we do that is because if something other than a Bullet collides with a Mob it won’t have a function named bullet_hit_mob so an error would occur. Like, if the Player collided with a Mob it would be wrong to try to call bullet_hit_mob from Player.

One extra note. You could even get away without having any function in bullet.gd. You could delete the bullet from _on_Mob_body_entered:

_on_Mob_body_entered(body):
    if body.is_in_group("bullet"):
        print("A bullet hit this mob. Deleting the bullet that hit this mob")
        body.queue_free()

I hope this gives another perspective on how you could achieve similar results as you would if you used a signal to signal from the Mob to the Bullet that the Mob was hit. Please feel free to ask for further information or clarification.

haydenv | 2023-01-16 15:03

Thank you for your very thorough answer haydenv!

Your solution works like a charm, and it probably fits my use case better, but I am still very confused as to why the “signal chaining” I’m using doesn’t work. I attempted that approach first since that is the way they do it in the 2D-tutorial in the official Godot documentation.

zantonius | 2023-01-16 20:18

You’re welcome.

Was the Bullet in your main scene hitting the Mob in your main scene, or was it hitting a Mob that was spawned by the MobPath spawner?

If you connect the bullet_hit signal from the Mob in your main scene to the Bullet, it won’t automatically connect the bullet_hit signal from the spawned Mobs to the Bullet. That is to say, the Mobs that are spawned by MobPath wouldn’t have their bullet_hit signal connected to Bullet, even if the Mob that you added to your main scene had its bullet_hit connected to Bullet.

haydenv | 2023-01-16 20:47

Thank you once again for the explanation :slight_smile:

The location is taken from the MobPath-spawner, but the mob itself is an instance of the Mob in the main scene:

    func _on_MobTimer_timeout():
    	var mob = mob_scene.instance()
    	
    	var mob_spawn_location = get_node("MobPath/MobSpawnLocation")
    	mob_spawn_location.offset = randi()
        ...
        add_child(mob)

Does instances of a scene created in the above way not connect to their “template’s” signal? That isn’t very intuitive to me if that’s the case.

zantonius | 2023-01-17 13:12

That is indeed the case. I think the standard practice would be to include the signal connection code in the _ready function of whatever scene you’re instantiating.

haydenv | 2023-01-17 16:09