Connecting the same signal from multiple instances (collectable coins)

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

I have a scene called ‘Coin’, it’s an Area2D Node with a Sprite and a CollisionShape2D.
The following script is attached to it:

extends Area2D

signal gold_up	
func _physics_process(delta):
	var bodies = get_overlapping_bodies()
	for body in bodies:
		if body.name == "Player":
			queue_free()
			emit_signal("gold_up")

I put three instances of this scene into my main scene (‘StageOne’).
StageOne has the following script attached to it:

extends Node2D

var gold = 0

func _ready():
	$Coin.connect("gold_up", self, "_on_Coin_gold_up")
		
func _on_Coin_gold_up():
	gold += 1
	print (gold)

The problem is, that it only connects to “Coin”, and not to “Coin2” and “Coin3”, and I can’t have multiple nodes named “Coin” in my scene (afaik).
How can I make a signal that can be used by multiple instances of the same scene?

Thanks in advance!

:bust_in_silhouette: Reply From: Zylann

There are several ways you could go for this.

If you want to use signals, you need to iterate all nodes of your scene and connect all of those having your coin script. This can be done by walking the tree with a recursive function, and check node is preload("res://path/to/coin.gd").

But there are other ways:
You could put all your coins in a Coins group, and then you can get a list of all of them without having to walk the tree yourself.

You could also not use signals, and instead put nodes listening to gold_up in a GoldUpListeners group, so coins can notify them like this:

get_tree().call_group("GoldUpListeners", "on_Coin_gold_up")

In my game, I did it yet another way:

if body.has_method("collect_pickup"):
	body.collect_pickup(self)

Another tip:
instead of using _fixed_process() in all your coins (which runs every physics frame), you could listen to the body_entered signal, which happens right when a body enters the area.

:bust_in_silhouette: Reply From: pennyloafers

I would argue that this code should live in the player (checking if the collision body is a coin). In that case a signal would not be needed. Or if this is for a HUD control then the player could signal that it collected some gold.

If coin naming is still in issue you can add your coins to a coin group and you can check if the collision if body.is_in_group(“coin”)