Connecting signals don't work on Resources instantiated in code (.new)

Godot Version

4.2.1

Question

I’ve been trying to connect to connect Signals from a UI class to a Resource.
When instantiating a Resource from code with .new() the signal connect doesn’t seem to work.
When preloading/loading the Resource the signal connect does work, what’s the different here and how can I get the code version to work with signals.

extends Resource
class_name TestResource

var testValue = 100

func onButtonClicked():
	print("Button clicked")
extends Area2D
class_name GodotButton

signal buttonClicked

func _on_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if event is InputEventMouseButton and event.pressed:
		buttonClicked.emit()	
extends Node2D

@onready var button: GodotButton = $Button



func _ready():
	# When connecting the Signal on this resource it works
	var testResourceFromTres: TestResource = preload("res://TestResource.tres")
	# When connecting the Signal on this resource it doesn't work
	var testResourceFromCode : TestResource = TestResource.new()

	button.buttonClicked.connect(testResourceFromCode.onButtonClicked)

I suspect that your new() instance goes out of scope and gets freed from memory whereas preload keeps a copy somewhere in memory.
Try moving the definition outside of _ready().

var testResourceFromCode : TestResource 
func _ready():
	testResourceFromCode : TestResource = TestResource.new()

	button.buttonClicked.connect(testResourceFromCode.onButtonClicked)
2 Likes

It works! Thanks for the solution!

Why would it get freed when it’s created in the _ready() function when that class is still being used.
I don’t fully understand why it works outside but not inside the ready function. Do you have any links I can read how this works to learn more about it?

When I do the following it also works

extends Node2D

@onready var button: GodotButton = $Button
var testResourceFromCode : TestResource


func _ready():
	# When connecting the Signal on this resource it works
	var testResourceFromTres: TestResource = preload("res://TestResource.tres")
	# When connecting the Signal on this resource it doesn't work
	testResourceFromCode = TestResource.new()

	button.buttonClicked.connect(testResourceFromCode.onButtonClicked)

Is it because the variable is only instantiated in the function so after the function ran is gets freed?

1 Like

Yes, you create a variable inside a function its lifetime is only the lifetime of the function.
Its called local scope.
When you create a variable outside of any function it is scoped to the class (node) and will live so long as the instance of the class is alive.
There is a little bit of info about scope here.
These scope rules are very much the same for most programming languages.

It seems in GODOT the preload creates a resource in global scope memory so that would be why the other version works.
However this tells me that it probably isn’t a good idea to do this inside the _ready() function (or any function generally):
var testResourceFromTres: TestResource = preload("res://TestResource.tres")
Because now when the function ends your variable goes out of scope and there is no way to free the resource (I am not 100% sure of this though).
If you are going to preload, you should move that variable to class level as well.

2 Likes

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