Godot Version
Godot 4.4.1 Stable
Question
I’m trying to access buttons from a different scene but I always get an error. Once the player runs out of lives a Game Over screens appears with 2 buttons, one says retry, the other one says Quit. I was able to make the Game Over screen appear but when I try to reload the scene by clicking on the retry button I get this error: Invalid access to property or key ‘pressed’ on a base object of type ‘null instance’.
extends Control
signal health_depleted
var health := 5: set = set_health
@onready var _heart_h_box_container: HBoxContainer = %HBoxContainer
@onready var _game_over_screen: Control = $GameOverScreen
@onready var _retry_button: Button = %RetryButton
@onready var _quit_button: Button = %QuitButton
func _ready() -> void:
var tween := create_tween()
tween.tween_property(self, "health", 0, 5.0)
set_health(health)
_game_over_screen.visible = false
func set_health(new_health: int) -> void:
health = clampi(new_health, 0, 5)
for child in _heart_h_box_container.get_children():
child.visible = health > child.get_index()
if health == 0:
health_depleted.emit()
game_over()
func game_over() -> void:
_game_over_screen.visible = true
_retry_button.pressed.connect(func() -> void:
get_tree().reload_current_scene.call_deferred()
)
Note that the _retry_button is a Control Node located in a different scene within the Scene Tree of the Game Over screen. I’m getting the error in the game_over () function.
If you could post some screenshots of your scene tree that would be great.
Unique names only work within the same scene. You need the full node path or export variables for accessing nodes in different scenes.
1 Like
I was running into a similar issue in the past, how I solved this was using a global script. Instead of having a script on a node handle scene management, it’s easier to emit a signal that’s connected to a global that handles scene management.
Globals are always present, are separate from the scene tree, and always have the name you assigned them. There’s no issue of scripts and nodes being unable to find them.
So, the steps I’d use are as follows:
-
Make a global script and name it “SceneLoader” (project > project settings > globals)
-
Paste in the following code:
extends Node
signal s_reload_scene
func _ready() -> void:
s_reload_scene.connect(_reload_scene)
func _reload_scene():
get_tree().reload_current_scene.call_deferred()
- Attach the following script to your Retry button:
extends Control
func _on_pressed() -> void:
SceneLoader.emit_signal("s_reload_scene")
- Use the UI to connect an “on press” signal from the Retry button to its own
_on_pressed()
function.
Also, a disclaimer; I haven’t personally used get_tree().reload_current_scene.call_deferred()
, so I don’t know if this is a valid way to use that function. Personally I’ve just been having scenes delete themselves then instancing a whole new one; Don’t think that works for you though.
Edit: step 0. Comment out the code for reloading the scene in the script you showed in the post, otherwise it may cause the same error as before, and prevent the scene reloading.
I’m sorry I forgot this before.
I ended up restructuring my scene, I actually combined the game over scene with the GameUI scene. This made is a lot simpler to manage the UI stuff in one place.
Yes I realized this while doing some research on the topic so, I restructured the game over scene. Now I’m accessing the buttons from one scene that contains all the UI stuff, no more errors.
Yes indeed, I had to modify my script to make this work but I get the general idea. Thanks a lot for the explanation and for providing that script sample, it really does help! 
Also: get_tree().reload_current_scene.call_deferred()
does work. At. least with the current setup I have.
1 Like