@export var set in inspector is null when launching scene

Godot Version

v4.2.2.stable.arch_linux

Question

I am writing a tool to visualize the maximum jump trajectory for my player character (2d platformer).

I have a scene with my player scene added as a child and a custom Node2D type (called arc) added as a child of the Player.

The player has several vars that describe stats related to jumping (run speed, jump height, gravity multipliers, etc).

The Arc is a @tool script that has it’s own copy of each of the player’s jump stats, as well as a reference to the player (via and @export var). I have structured it this way so that I can test different configurations of the stats related to jumps in the Arc node which then uses a setter function to update it’s own copy, sets the player’s stat to be the new value, and the recalculates the line that displays the trajectory. Here is an example of the players run speed setter from the Arc class.

@export var speed: float = 300:
	set(value):
		speed = value
		player.speed = value
		_recalculate_points()

The idea here is to enable me to fine tune the jump without the player class needing to know about the dev tools.

Everything is working fine in the editor, but when I run my test scene it immediately hangs and complains about accessing values on a null value (player).

The player is definitely set in the scene via the inspector view. I have tried resetting it but no luck there. I am guessing that the value of export vars is not actually set until later in the scene initialization which is causing a crash by the setters for the Arc being called before the player is added to the scene. How can I fix this? Do I need to restructure my scene? Or is there a way to block the setters from being called until the player is initialized?

The issue occurs because the setters in your Arc class are being called before the player reference is fully initialized, leading to null reference errors. To fix this, you can:

Add a null check in the setters to ensure they only proceed if the player is set.

@export var speed: float = 300:
	set(value):
		if player:
			speed = value
			player.speed = value
			_recalculate_points()

Delay initialization by moving your logic to the _ready() function, ensuring the scene is fully set up before any properties are accessed.

func _ready():
	if player:
		_recalculate_points()

Use a manual initialization method to set up the player reference and recalculate points after the scene is loaded.

func initialize(player_ref):
	player = player_ref
	# Set player stats and recalculate the trajectory
	_recalculate_points()

(the codes are just examples)

This should prevent the crash and allow your tool to function properly without restructuring your scene.

1 Like

I assumed this was what was happening. I think null checks work the best in this case. It just feels a bit wrong because I would prefer to crash if the player is actually missing once the scene is loaded. I guess I can check for it during _ready.

Thanks for the help.

1 Like

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