Signal from one instance triggers the handling function for all instances

Godot Version

4.2.1

Question

I have a main scene and secondary scene. I want to create multiple instances of the secondary scene. The secondary scene will emit a signal with information which is specific to it. The main scene will detect the signal and act on the information.

The main scene is empty. The secondary scene is made of an icon and collision2D to allow detection of mouse clicks:

first

Secondary.gd:

class_name Secondary extends Area2D
@onready var sprite_2d = $Sprite2D

signal secondary_clicked(value)
var information

func _input(event):
    if event.is_action_pressed("mouse_left_click"):
        secondary_clicked.emit(information)

Main.gd:

class_name Main extends Node2D

# Called when the node enters the scene tree for the first time.
func _ready():
    var secondary_scene = preload("res://Secondary.tscn")
    var secondary_instance = secondary_scene.instantiate()
    add_child(secondary_instance)
    secondary_instance.information = "1st"
    secondary_instance.position = Vector2(510, 320)
    secondary_instance.secondary_clicked.connect(handle_signal)
    
    secondary_instance = secondary_scene.instantiate()
    add_child(secondary_instance)
    secondary_instance.information = "2nd"
    secondary_instance.position = Vector2(710, 320)
    secondary_instance.secondary_clicked.connect(handle_signal) 

func handle_signal(value):
    print("The value from the scene: " + value)

I’m expecting that mouse click will result in “The value from the scene: 1st” or “The value from the scene: 2nd” depending on which instance I clicked.

The actual result is that I get two prints, regardless of which one I clicked. This output was made by a single click:

second

You never told Godot to only handle the one you clicked on. As far as those objects are concerned, they see a click event and do their code.

To fix this, you’ll have to add some logic for Godot to which one you clicked on, or get another way to handle the input.

1st way: Handling input another way

Your secondary scene is an Area2D, which is great because Area2D can detect input events. The only thing you have to do is connect the input_event signal from the area onto the script.
For example, connect the input_event signal to a method named _on_input_event(event) and use the same code from before:
func _on_input_event(event):
    if event.is_action_pressed("mouse_left_click"):
        secondary_clicked.emit(information)

2nd way: Adding logic

This can be done in many ways. This is an example that first comes to mind and it checks how close the click was to the node.
if event.is_action_pressed("mouse_left_click"):
    if global_position.distance_to(get_global_mouse_position()) < some_radius:
        secondary_clicked.emit(information)

@senseibobo Thank you for you explanation, I applied the first solution and it worked.

I still don’t fully understand why this is the case. I didn’t expect methods on a class to act across all instances, and it’s still unclear to me why connecting the event to the function behaves differently. I’d be grateful if you know of an article that explains this and can link to it.

The _input(event) method is called on every single active node in the viewport every time some input happens (pressing a key, moving a mouse and all of that). It’s just how it works.
Check this article out, maybe it’ll clear some things up.