Node not found error on global node

Godot Version 4

Question

Hello So I have HUD node that I’m using to display score and lives. This is my Kill Zone script:

extends Area2D
@onready var timer = $Timer
@onready var death_sound = $AudioStreamPlayer2D
@onready var hud = %HUD

func _on_body_entered(body):
death_sound.play()
hud.set_lives(-1)
if hud.lives == 0:
Engine.time_scale = 0.5
body.get_node('CollisionShape2D').queue_free()
timer.start()

func _on_timer_timeout():
Engine.time_scale = 1
get_tree().reload_current_scene()

then in hud.gd script:

extends CanvasLayer

var score = 0
var lives = 3
@onready var score_label = $ScoreLabel
@onready var lives_label = $Lives

func add_point():
score += 1
score_label.text = "Score: " + str(score) 

func set_lives(value):
lives += value
lives_label.text = "Lives: " + str(lives)

I have a very similar code in my coin.gd script:

extends Area2D

@onready var hud = %HUD
@onready var animation_player = $AnimationPlayer

func _on_body_entered(body):
hud.add_point()
animation_player.play("pickup")

And the coin logic is working just as expected. when I collect coins, it updates the score label text in HUD. but for lives it gives me this error as soon as I enter the danger area:

E 0:00:00:0844   kill_zone.gd:5 @ _ready(): Node not found: "%HUD" (relative to "/root/Game/Slime/KillZone").
  <C++ Error>    Method/function failed. Returning: nullptr
  <C++ Source>   scene/main/node.cpp:1651 @ get_node()
  <Stack Trace>  kill_zone.gd:5 @ _ready()

Also, I’m a beginner ). Did a ton of google searches but to no avail.

What am I missing?

Is the kill zone script a part of the same scene file as the HUD node? Unique names are not global, they are unique within the scene file they are stored in. So if your coin scene is a different scene file than the one with the HUD, then it can not find the node by scene unique name.

A common pattern to get around this is to use the event bus pattern. It works by having a global autoload that acts as a “relay” to forward changes. Here is a page that explains this programming pattern in detail in case you want to use this approach:

2 Likes

Not sure of the correct answer but to access the node using % you have to make sure the node is designated unique and it is in the current scene.

1 Like

Thank you for your suggestions. So I ended up fixing this by creating a new scene for the Hud canvas with the labels as it’s children and then autoloading that scene with the game.

It fixed the issue. Is there any reason not to do it that way?

It kinda depends on your game, but usually you have other scenes (like main menu or game over screen) where you don’t want the HUD to be visible. With the HUD as an autoload, you have to manually manage it’s visibility. That’s why usually you keep the HUD in the level scenes, and use patterns like the event bus to communicate between HUD and game objects.

1 Like