Issue with making node visible

godot 4

I am working on making a banking UI for my game and when run it gives me the error
Invalid set index ‘visible’ (on base: ‘null instance’) with value of type ‘bool’.
which is weird because i have the exact same code for making things visible else where in the game and that works fine. this code also has a error with displaying text as strs which I also have done at other times
thanks for any help in advance
Here is the code

extends Area2D
var gold = Inventory.gold
var bankGold = Inventory.bankGold

func _on_body_entered(body):
if body.has_method(“pickUpGold”):
print_debug(“in range”)
%CanvasLayer.visible = true
%CanvasLayer/startScreen.visible = true

func _on_button_pressed():
%CanvasLayer/withdraw.visible = true
%CanvasLayer/startScreen.visible = false

func _process(_delta):
pass

func _on_button_2_pressed():
%CanvasLayer/input.visible = true

func _on_g_pressed():
if Inventory.bankGold >= 1:
Inventory.bankGold -= 1
Inventory.gold += 1

func _on_five_g_pressed():
if Inventory.bankGold >= 10:
Inventory.bankGold -= 10
Inventory.gold += 10

func _on_fifty_g_pressed():
if Inventory.bankGold >= 50:
Inventory.bankGold -= 50
Inventory.gold += 50

func _on_all_pressed():
Inventory.gold = Inventory.bankGold
Inventory.bankGold = 0

func _on_g_in_pressed():
if Inventory.gold >= 1:
Inventory.gold -= 1
Inventory.bankGold += 1

func _on_five_g_in_pressed():
if Inventory.gold >= 10:
Inventory.gold -= 10
Inventory.bankGold += 10

func _on_fifty_in_pressed():
if Inventory.gold >= 50:
Inventory.gold -= 50
Inventory.bankGold += 50

func _on_all_in_pressed():
Inventory.bankGold = Inventory.gold
Inventory.gold = 0

Few ideas:

  • I’m thinking the node may have a different name when you reference it with the $ or % syntax. Double check that, this is the most likely reason.
  • Maybe the _on_body_entered fires before the entire scene is ready. So the CanvasLayer isn’t in the scene yet and you are already trying to set its visibility?

Also I’d recommend to extract the nodes you are referencing into onready variables like this:

@onready var start_screen: Control = %CanvasLayer/startScreen

And then in _ready you can check if they are not null. Just to be safe.

thanks for that you where right it was the wrong name
Btw if I was wondering if you knew of a way to make a label display a int that’s are var and update as the var gets changed
I have this code here
gold and bank gold are vars in an auto load script it loads on start but doesn’t update with the vars

var gold = Inventory.gold
var bankGold = Inventory.bankGold
func _process(delta):
%ColorRect/gold.text = str(gold)
%ColorRect/bankGold.text = str(bankGold)

For a new project updating the label every frame is fine. Once you start having a lot of UI elements, i tend to go for this approach:

  • Have a GameState autoload (singleton)
  • The GameState has a should_update_ui signal, which it emits every time a displayed property changed
  • The UI (CanvasLayer maybe?) connects to this signal and updates only when necessary

But don’t worry about it too much. A single label is fine. When you have a lot of UI elements, some solution will emerge. Focus on your game firt and good luck!

1 Like

That’s because you only get the values from your Autoload once (outside the scope of your _process function, i.e. when the script is loaded). If you define the variables in _process (i.e. every frame anew), the labels should update correctly:

func _process(delta):
  var gold = Inventory.gold
  var bankGold = Inventory.bankGold
  %ColorRect/gold.text = str(gold)
  %ColorRect/bankGold.text = str(bankGold)

or shorter, by using the Autoloads variables directly:

func _process(delta):
  %ColorRect/gold.text = str(Inventory.gold)
  %ColorRect/bankGold.text = str(Inventory.bankGold)
1 Like