Unassignable Variable

Godot Version

4.3

Question

` I have an odd problem, which I hope is just me, and is an easy fix. I have been working on a simple 2d game, where I have created a characterbody2d you can select with the mouse and order around on a tilemap.

The issue is with a sprite2d which is the 2nd child of the characterBody2d, called ‘highlight’, which is supposed to appear with highlight.show() once you left click on the character, to show it has been ‘selected’

The problem is; no matter how I assign the variable ‘highlight’ it always returns null on runtime. I’ve tied so far:

var highlight = $highlight
$highlight.show()
@onready var highlight = get_child(1)
@onready var highlight = get_node(“highlight”)
@export var highlight : Sprite2d

I’ve even tried assigning the variable during its instancing,
var ob = obscene.instantiate()
ob.highlight = ob.get_child(1)

I think something is blocking anything being assigned to that variable, but I can’t image what it could be. This is a brand new project with only three scripts, so there is no interference I can see.

I assume I’ve checked a ‘read only’ button or something of that nature. I was hoping if anyone else recognizes what this is, they can give me their wisdom.

Thanks.`

I think you can grab the node in the scene tree with the mouse, hold control, and drag it into the script. It will write the correct way to onready the node.

My guess its a misspelling of the nodepath.

But also onready will only be called when its added to the tree. So you should probably add it first then get the child. In this situation a unique node name could be beneficial.

Onready should happen after _enter_tree and before _ready

Thanks for the quick response. unfortunately I tried that , i even used a timer for a delayed function to assign it well after the initial load, but no luck. Yeah, its a real puzzle to me.

Can you show the function/functions that try and get the node in code, and maybe also the scene tree?

Also get_child has a second parameter to include internal children, this is false by default, i think in the instantiate option you need to pass true.

If you want to learn more about node lifecycles take a look at this doc. And this one too

1 Like

There really isn’t much code to be honest.

extends CharacterBody2D
the class is just called ‘person’
@onready var highlight: Sprite2D = $highlight

the function that calls the highlight to appear:

func _input(event: InputEvent) → void:
if event.is_action_pressed(“LeftClick”):
MouseManager.selectedUnit = self
highlight.show() <<< crashes here, returns null value

You could try checking is_node_ready() is true during input. It could be possible that node has entered_tree and is now excepting input before it is ready.

If the node is ready and you still get null i question if the onready nodepath is correct.

1 Like

Did you add this script as a Global/Autoload?

no not global, just regular old script and class. I’ll give the is_node_ready() a go and see what results i get

The node must be ready and in the scene tree to recieve _input events. Could you show your scene tree and the results of print(get_path())?

Okay, I just tried a few things. is_node_ready() doesn’t return a true or a false, just null, same as print(get_path()).

I tried assigning the variable through a function with the timer every second or so and at no point will it assign it. Always null. I think you are correct, I believe it is something with the nodepathing. I’ve made several games with Godot and never run into this.

At the end of the day, I can find a work around. using canvas ui elements to follow the characters around, just the show() method is usually so much easier. Thank you so much for all your help all the same, you’re a legend.

How does this return null? Can you post how you added this to your script and the actual output logs?

oh sorry, the output in _ready was /root/World/Character2
the null was from the highlight

Okay I found the problem. This is the renaming, deletion bug. I renamed and deleted another character earlier on. For some reason if you do this on occasion, it doesn’t go away properly and it can still share some variables and resources.

It was trying to assign the highlight to the dead object I guess, and always coming up null. Once I cleared out anything suspicious, and moved a few things around, the original code started working.

Sorry for the run around. You guys did gave me some good tips, and I’m very grateful for your help.