How do I Identify individual instances of the same scene?

Godot 4.3

I feel like this is a really simple question, I just can’t find the answer. I have instantiated a list of OptionButtons in a column via code. They all call the same function when an option is selected, and determining which option was selected is simple enough.

My question is how do i differentiate between each of these OptionButtons, is there an unique “instance ID” i can reference? it needs to be the same value every time, IE. the 3rd OptionButton down is always ID=3

EDIT: I’ve made some progress:

var part_select = part_selector.instantiate() as OptionButton
part_select.id = 1

will change the id variable defined in the OptionButton scene to 1, but when I try to send that variable back to the main script when I call _part_selected() via a signal from an instance of the OptionButton scene :

func _part_selected(index, id):

nothing happens, no error, no code is run from _part_selected(). As soon as I remove the id arg, it runs fine (but without the id variable obviously). I know this has something to do with signals, I just don’t fully understand them yet

One way of doing it is subclassing and adding your own name variable. Another way would be to pass an extra parameter on the bind() method identifying the object. Here is an example where do_something() is called when item is selected.

class OptionButtonNamed extends OptionButton:
	var opt_name: String	

func do_something(selected:int, option: OptionButtonNamed):
	prints(option.opt_name, option.selected, selected)
	pass
	
func _ready():
	var part_select1 := OptionButtonNamed.new()
	part_select1.opt_name="NAME1"
	part_select1.add_item("ABC", 1)
	part_select1.add_item("XYZ", 2)
	part_select1.item_selected.connect(do_something.bind(part_select1))
	add_child(part_select1)
	
	var part_select2 := OptionButtonNamed.new()
	part_select2.opt_name="NAME2"
	part_select2.add_item("ONE", 1)
	part_select2.add_item("TWO", 2)
	part_select2.item_selected.connect(do_something.bind(part_select2))
	add_child(part_select2)
	part_select2.position.y=200 #repositions 2nd OptionButton
	
	return
1 Like

This all seems far more complicated than it needs to be, maybe I’m not using the right terminology to explain what I need, let my try to clarify: I have a “main_scene” I have a “selector_scene”. The “selector_scene” contains only an OptionButton with 12 items added through the editor. it’s script is:

func _on_item_selected(_index: int) -> void:
	pass

one “selector_scene” has been added to the tree through the editor
“main_scene” script contain:

func _part_selected(index):
	print("index from main script : ", index)

this prints index as expected, then creates a new instance of the OptionButton:

var part_select = part_selector.instantiate() as OptionButton
$ColorRect/NinePatchRect/HBoxContainer/PartSelectPanel/VBoxContainer.add_child(part_select)

From the player side, they start off seeing one OptionButton, when they make a selection, a new OptionButton appears below the initial one, the player then selects an option from that OptionButton, a new one appears below, etc. If one selection is made, in sequence this all works, but if the player goes back and changes for example the 4th OptionButton down i need to know it came from the specific OptionButton, I can then swap out a value from an array that is storing those selection at a given index

I’ve managed to assign a value to a variable stored in the “selector_scene” upon instantiation, am I correct in assuming that that variable value will be unique to that one instance of the “selector_scene” and if so, how do I send that value back to _part_selected() function in the “main_scene” when item_selected signal is sent from the “selector_scene” instance

Can you post a mini section of the code?

That’s basically all the relevant code. Any other code I’ve written so far isn’t relevant yet. Can I not just assign a sequential value to a variable inside each instance of the “selector_scene” and then emit a custom signal containing that variable whenever _on_item_selected() is called? Effectively giving me a “selected_from” variable alongside “index” in the “main_scene” allowing me to insert “index” (representing the item chosen) at “selected_from” (representing the position in an Array where that chosen item should be inserted)

Edit:
I’m trying to avoid having 10+ OptionButtons individually added to the scene tree and only made visible one at a time, as the player selects from each, in which case I could manually identify each one and be able to determine which one triggered _part_selected() but I feel like wouldnt be as efficient

This is an interesting problem. I think you need a dictionary, adding each button to it as they instantiate. You can then retrieve them with the name you added them with or their number in the list (“Dictionaries will preserve the insertion order when adding new entries” according to the docs).

Sounds similar to adding all the OptionButtons to a group as they’re instantiated, this came up in my search for a solution, but I don’t understand how this allows me to identifiy each OptionButton when the player selects an option from that particular OptionButton

From what I interpreted that your problem is, you need to keep track of what each OptionButton does. With a group you can not differentiate between the different elements of the group, you simply either check if they are in the group or not. With Dictionary you can differentiate between them based on their entry key or order of insertion.

Thanks for the help everyone, in the end ChatGPT actually solved my issue, with 5 prompts it managed to spit out very well commented, functional code for my main scene and for the OptionButtons, wasn’t even worth copying the code it generated because it was so close to what I had already written, I’ll include the code it generated here for anyone thats curious:

Main Scene

extends Node2D

# Preload the OptionButton scene
var OptionButtonScene = preload("res://OptionButtonScene.tscn")

# Store the current number of OptionButton instances
var current_button_count = 0

func _ready():
    # Create the first OptionButton instance when the scene starts
    _create_new_option_button()

# Function to create and add a new OptionButton instance
func _create_new_option_button():
    var new_button = OptionButtonScene.instance()
    add_child(new_button)

    # Increment the counter for how many buttons we've created
    current_button_count += 1

    # Connect the custom "selection_made" signal from the OptionButton to the main scene
    new_button.connect("selection_made", self, "_on_option_selected")

# This function is called when a selection is made from any OptionButton
func _on_option_selected(button_id: int, selected_index: int):
    print("Selection made from button with ID: ", button_id, " at index: ", selected_index)

    # If the button was the most recently created, add a new one
    if button_id == current_button_count - 1:
        _create_new_option_button()

OptionButton

extends OptionButton

# Static counter to give each instance a unique ID
# This variable is shared among all instances of the OptionButton
static var id_counter: int = 0

# Each instance will have its own unique ID
var instance_id: int

# Custom signal to notify the main scene of a selection
signal selection_made(button_id: int, selected_index: int)

# Called when the node is added to the scene
func _ready():
    # Assign the instance a unique ID
    instance_id = id_counter
    id_counter += 1

    # Fill OptionButton with dummy items (for demonstration purposes)
    add_item("Option 1")
    add_item("Option 2")
    add_item("Option 3")

    # Connect the item_selected signal to handle the selection
    connect("item_selected", self, "_on_item_selected")

# Function to handle when an item is selected
func _on_item_selected(index: int):
    # Emit the custom signal when an option is selected, passing the instance ID and the selected index
    emit_signal("selection_made", instance_id, index)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.