Adding child to CanvasLayer node brings up "null" error. Am I missing something?

Godot Version

Godot 4.5

Question

Hello there. To keep it brief: I want to instantiate and then spawn in a "gameover" screen for my game. My plan was to create a reference to a CanvasLayer node, then add the gameover scene (a control scene) as a child of the CanvasLayer node so it displays on top of everything else. The end goal is to have whatever's going on in the background continue while the gameover screen is displayed. Of course, when I run it, it comes back as null because I missed something with the CanvasLayer node. I've looked around, but haven't gotten a super clear answer. Help! Code is below.

@onready var gameover_scene = preload(“res://Scenes/gameover.tscn”)
var gameover_flag: bool = false
@onready var canvas_layer: CanvasLayer = $CanvasLayer
func gameoverscreen():
	var gameover_inst = gameover_scene.instantiate()
	canvas_layer.add_child(gameover_inst)

Make sure both the path for the gameover_scene is correct, AND that Godot finds the $CanvasLayer correctly and that it’s not null. If either of them are incorrect, make sure you fix it.

I just did the standard ctrl+click from here:

Is there any reason why this might be wrong? The “GlobalHandler” script I’m using is enabled under the autoload menu.

print(get_path()) in script’s _ready() or before using the problematic variable.

If that’s a global script, then that path will not find the CanvasLayer. $CanvasLayer just means “I’m looking for the Node that’s directly my child called CanvasLayer”, but if this script is global, then that won’t be the case. You need to manually find the reference to this Canvas layer node.

1 Like

Hello! I would… recommend instead of @onready var gameover_scene use @export var gameover_scene : PackedScene and then drop your gameover.tscn to that variable in the inspector y’know.

Try that. Perhaps would work?

Or instead of using variable just point to $CanvasLayer during script execution. Like so:


func gameoverscreen():
	var gameover_inst = gameover_scene.instantiate()
	$CanvasLayer.add_child(gameover_inst)

That’ll do it, yeah. What’s the best way to reference something from a global script if it isn’t attached to a node? I’m trying different things but not having much success.

If this scene will appear during the game anyway, why not make it a global node?
If it’s something that is the same across every instance, simply make your global script into a global node instead, and make that CanvasLayer it’s child.

What’s a “global script”?

A script that is set to autoload, and hence can be accessed from anywhere. Singletons (Autoload) — Godot Engine (latest) documentation in English

Umm… I was asking the OP to see their understanding of the concept.

Numerous times I’ve seen this misconception people have about autoloaded scripts, that they are somehow floating in the air as “global scripts”

There’s really no such thing as “global script” in Godot. Once you set a script as an autoload it will always create an “invisible” persistent node parented to root that runs that script. From then on it doesn’t make sense to run this script on other nodes. It also makes no sense to obtain nodes in that script via relative paths from the perspective of some other node.

This is why I said to print the path in my first response - to determine to which node exactly is the script attached, and if there are multiple nodes in the tree that are simultaneously running the script.

This problem happens very often and is caused by people not understanding how autoloads work.

So please @thegregoflife1123 print the paths and also show your remote scene tree.

Then perhaps you should add more to your comment rather than just asking a question :slight_smile:

I already provided a diagnostic solution in my first post.

Interesting thing to note is that the docs page you linked never uses the term “global script”. That term is highly misleading.

Two things to keep in mind for your next reply:

  1. I’m a solo developer who is, at best, tinkering with godot. My goal is not to create this perfect, well-oiled machine, but rather have my silly ideas run (ideally without crashing or major issues). Me using a couple of misleading words as a placeholder for another concept isn’t the end of the world. Especially when the person I was talking to understood what I was saying.
  2. When I ask for a solution, I don’t mean one sentence with a vague solution that I may or may not know how to implement. I’m new and I need all the gory details. That way I can take your solution, use it, and then study how it works afterward. That is how I operate. It’s like having the answers to a test: some people will just cheat and put down the answers without thinking. I like having the answer so I can draw a route from the question to the answer, which in turn gives me the tools I need to solve more answers like it. Besides, my goal isn’t to become a perfect programmer. I like learning, but I just want my project working for now.

I remember your response to a post I made a couple months ago, and it made me feel stupid. In fact, I tried desperately to come up with a solution on my own because of that. I shouldn’t have to feel that way. I made an account on this forum because I wanted to hear human perspectives, and everyone has different ideas about how to handle things (which is cool). The documentation can’t really provide that.

1 Like

So, in other words, add the gameover scene to the globals menu, and then give the scene its own script? Is that what you mean?

Your feelings are not my concern or responsibility.

I always start with short posts to determine if people are willing to actually engage. A lot of times immediate elaborate answers get ignored and time wasted. Remember, we’re humans, not chatbots.

Print the node path from the script to determine on which node(s) it runs and post the printout along with the snapshot of your runtime (remote) scene tree. That way we can diagnose what exactly is happening with your scripts. The error is caused by the script running on a node that you’re not aware of. And that’s likely caused by you not understanding how singletons actually work. Pointing that out is not an insult. Not understanding is not a character flaw.

So there are two parts if you want a full solution: immediate fix of this situation, and you putting some effort to learn how it works so it doesn’t bite you in the butt again in the future.

1 Like

That’s more like it. I’ll give it a shot. For the record: how you say things makes a big difference. Just something I learned in my time as a human.

Indeed. That’s why proper terminology needs to be used instead of misleading terms like “global script”.