How to get a signal to effect an Instantiate scene?

Godot Version

Godot 4.4

Question

Hello! I’m going to do my best to describe the issue I’m having:

I’m currently working on a cooking game. I have a scene set up with a fridge and a cooktop. When you click on the fridge, it spawns in a burger patty. This burger patty is not in the scene tree. I want to code it so when the burger is put on the cooktop, the sprite slowly changes, yet I cannot figure out how to get it to receive signals, as it is not in the scene tree of any element. Sorry if this is confusing, but I’m very new to godot. Any help is appreciated!

As a basic rule, any scene you instantiate needs to be added to the scene tree. From what you described the code the fridge calls needs to look something like this:

burger = burger_scene.instantiate()
cooktop.add_child(burger)
burger.global_position = cooktop.global_position
burger.burger_signal.connect()

this is the code for the fridge, which spawns the burger

extends Node2D

@export var spawn_object = preload("res://Scenes/dragtest.tscn")
@onready var open_area = $"FridgeRECT/Fridge OPEN AREA"
@onready var close_area =$"FridgeRECT/Fridge CLOSE AREA"

@export var items: Array[ItemData] = []
@export var inventory_item_scene: PackedScene
@onready var item_grid: GridContainer = $itemgrid


var OPEN = false

func _ready():
	var OPEN = false

func spawn():
	var obj = spawn_object.instantiate()
	obj.position = Vector2(450,100)
	add_sibling(obj)

func _on_fridge_open_area_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if Input.is_action_just_pressed("leftclick"):
		if OPEN == false:
			OPEN = true
			
	if OPEN == true:
		open_area.visible = false
		close_area.visible = true
		
func _on_fridge_close_area_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if Input.is_action_just_pressed("leftclick"):
		OPEN = false
	if OPEN == false:
		open_area.visible = true
		print("door closed")
		close_area.visible = false

and this is the code of the burger itself

extends Sprite2D

@export var cooking_time: float = 3.0
@export var raw_patty_texture = preload(“res://sprites/burger raw.png”)
@export var cooking_patty_texture = preload(“res://sprites/burger half.png”)
@export var cooked_patty_texture = preload(“res://sprites/burger cooked.png”)
@export var patty_sprite = Sprite2D

var is_cooking: bool = false
var timer: float = 0.0

var data: ItemData = null
var is_picked: bool = false
var size: Vector2:
get():
return Vector2(data.dimentions.x, data.dimentions.y) * 32

var anchor_point: Vector2:
get():
return global_position - size / 2

func _ready() → void:
if data:
texture = data.texture

func _process(delta: float) → void:
if is_picked:
global_position = get_global_mouse_position()
if is_cooking:
timer += delta
var progress: float = timer/cooking_time
if progress < 1.0:
if progress < 0.33:
texture = raw_patty_texture
elif progress < 0.66:
texture = cooking_patty_texture
else:
texture = cooking_patty_texture
else:
texture = cooked_patty_texture
is_cooking = false
timer = 0.0
print(“patty cooked”)

func set_init_position(pos: Vector2):
global_position = pos + size / 2
anchor_point = global_position - size / 2

func get_picked_up():
add_to_group(“held_item”)
is_picked = true
z_index = 20
anchor_point = global_position - size / 2

func get_placed(pos: Vector2i):
is_picked = false
global_position = pos + Vector2i(size / 2)
z_index = 0
anchor_point = global_position - size / 2
remove_from_group(“held_item”)

func _input(event: InputEvent) → void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_RIGHT && event.is_pressed():
if is_picked:
do_rotation()

func do_rotation():
data.is_rotated = !data.is_rotated
data.dimentions = Vector2i(data.dimentions.y, data.dimentions.x)
var tween = create_tween()
tween.tween_property(self, “rotation_degrees”, 90 if data.is_rotated else 0, 0.2)

func _on_itemgrid_cooking() → void:
is_cooking = true
timer = 0.0

this is the code for the cooktop

extends GridContainer

const SLOT_SIZE: int = 32
@export var inventory_slot_scene: PackedScene
@export var dimentions: Vector2i
var slot_data: Array[Node] = 

var held_item_intersects: bool = false

signal cooking

func _ready():
create_slots()
init_slot_data()

func create_slots():

self.columns =dimentions.x
for y in dimentions.y:
	for x in dimentions.x:
		var inventory_slot = inventory_slot_scene.instantiate()
		add_child(inventory_slot)

func _gui_input(event: InputEvent):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT && event.is_pressed():
var held_item = get_tree().get_first_node_in_group(“held_item”)
if !held_item:
var index = get_slot_index_from_coords(get_global_mouse_position())
var slot_index = get_slot_index_from_coords(get_global_mouse_position())
var item = slot_data[slot_index]
if !item:
return
item.get_picked_up()
remove_item_from_slot_data(item)
else:
if !held_item_intersects: return
var offset = Vector2(SLOT_SIZE, SLOT_SIZE) / 2
var index = get_slot_index_from_coords(held_item.anchor_point + offset)
var items = items_in_area(index, held_item.data.dimentions)
if items.size():
return
held_item.get_placed(get_coords_from_slot_index(index))
add_item_to_slot_data(index, held_item)
if event is InputEventMouseMotion:
var held_item = get_tree().get_first_node_in_group(“held_item”)
if held_item:
detect_held_item_intersection(held_item)

func detect_held_item_intersection(held_item: Node):
var h_rect = Rect2(held_item.anchor_point, held_item.size)
var g_rect = Rect2(global_position, size)
var inter = h_rect.intersection(g_rect).size
held_item_intersects = (inter.x *inter.y) / (held_item.size.x * held_item.size.y) > 0.8

func remove_item_from_slot_data(item: Node):
for i in slot_data.size():
if slot_data[i] == item:
slot_data[i] = null

func add_item_to_slot_data(index: int, item: Node):
for y in item.data.dimentions.y:
for x in item.data.dimentions.x:
slot_data[index + x + y * columns] = item
emit_signal(“cooking”)

func items_in_area(index: int, item_dimentions: Vector2i) → Array:
var items: Dictionary = {}
for y in item_dimentions.y:
for x in item_dimentions.x:
var slot_index = index + x + y * columns
var item = slot_data[slot_index]
if !item:
continue
if !items.has(item):
items[item] = true
return items.keys() if items.size() else 


func init_slot_data():
slot_data.resize(dimentions.x * dimentions.y)
slot_data.fill(null)

func attempt_to_add_item_data(item: Node) → bool:
var slot_index: int = 0
while slot_index < slot_data.size():
if item_fits(slot_index, item.data.dimentions):
break
slot_index += 1
if slot_index >= slot_data.size():
return false

for y in item.data.dimentions.y:
	for x in item.data.dimentions.x:
		slot_data[slot_index + x + y * columns] = item

item.set_init_position(get_coords_from_slot_index(slot_index))
return true

func item_fits(index: int, dimentions: Vector2i) → bool:
for y in dimentions.y:
for x in dimentions.x:
var curr_index = index + x +y * columns
if curr_index >= slot_data.size():
return false
if slot_data[curr_index] != null:
return false
var split = index / columns != (index + x) / columns
if split:
return false
return true

func get_slot_index_from_coords(coords: Vector2i) → int:
coords -= Vector2i(self.global_position)
coords = coords / SLOT_SIZE
var index = coords.x + coords.y * columns
if index > dimentions.x * dimentions.y || index <0:
return - 1
return index

func get_coords_from_slot_index(index: int) → Vector2i:
var row = index / columns
var column = index % columns
return Vector2i(global_position) + Vector2i(column * SLOT_SIZE, row * SLOT_SIZE)

Change _ready in your burger scene to _init, and @onready your fridge inside the burger scene and connect to the fridge signal from the burger scene in your init function

If you plan on having more than 1 burger spawn at a time, may i also suggest at some point disconnecting said signal, maybe even in the function the signal calls, keeps recursion under control.

It’s probably better not to use signals, seems like the cooktop has an inventory system which knows about the burger patty, from there it can set the object’s properties directly.
You could add a line to the cooktop that checks for that cooking property

# upon adding to cook top
if "is_cooking" in item:
    item.is_cooking = true

# when removing
if "is_cooking" in item:
    item.is_cooking = false

Signals are better used for generic actions calling out to the world that something has happened to them, not for two specific things interacting like this stovetop is cooking this burger. Signals are more for this burger is now fully cooked, and anybody listening can do with that information they please.