The function set() is executed before _ready()

Godot Version

4.2.1

Question

When I run the program, for some reason the set function is executed first and because the nodes are not loaded, an error occurs

Invalid set index ‘texture’ (on base: ‘Nil’) with value of type ‘Nil’.

At the same time, everything works in the editor.

Look at this code:

@tool
extends Area2D
class_name ItemNode

@export var ITEM: InventoryItem: set = _set_item

@onready var textureRect: TextureRect

func _set_item(value: InventoryItem):
	ITEM = value
	if value != null:
		textureRect.texture = ITEM.image
	else:
		textureRect.texture = null
	
	
func get_amount():
	return ITEM.amount

Yes, there is no problem with deleting this code, it is just much more convenient to work this way everything is updated at once. I am just wondering what this is connected with? The set() function is executed first than _ready(), while nothing is written in ITEM

1 Like

The error comes because you are trying to modify a parameter of the variable textureRect, but textureRect is null because you never assign a value to it.

Just assign a TextureRect node to your variable textureRect.

Yes, there is a mistake here, probably left when trying to understand what the problem is. But even if so, how does the code execute in the inspector?

Correction on - @onready var textureRect: TextureRect = $Texture
did’t help

I added this at line 10 - textureRect = get_node("Texture")
And I got an error that the node was not found


The debugger says that all variables are null, although everything is defined in the inspector. Is it a feature of the engine that set() is executed before _ready()?

Yes, @export vars are set immediately when the scene is instantiated (pretty much right when _init() is called on the node), but the _ready() function and @onready vars aren’t processed until after the node is added to the tree.

So, you’re simply going to need to assume textureRect could be null, and then make a _ready() function which sets the texture.

Something like this should work:

@export var ITEM: InventoryItem: set = _set_item

@onready var textureRect: TextureRect = $Texture

func _ready():
	_update_texture()

func _set_item(value: InventoryItem):
	ITEM = value
	_update_texture()

func _update_texture():
	if not is_instance_valid(textureRect):
		return
	if ITEM != null:
		textureRect.texture = ITEM.image
	else:
		textureRect.texture = null
2 Likes

Yes it works if not is_instance_valid(textureRect):return
Thank you!

But i dont understand why the set() function is called at all. Like first all variables are declared with null and at this moment set() is called, and only then something is written to them?
Anyway, even a variable that is declared via @export ITEM in debugger = null

You need to understand what exactly the @export and @onready annotations are doing.

A variable with @export won’t magically have its values filled in at the moment the node is created, but shortly after creation, the code which instantiates the scene will come along and assign your exported values to your @export vars. This is why the setter is called.

@onready vars work similarly, but they are assigned later, after the node has been added to the tree (and just before its _ready() function is called). Before then, they’ll have some default value (null or 0 or [], depending on the type).

2 Likes

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