Reputation: 45
Hi I'm currently making a game that houses minigames with Godot. After I finish the first minigame, that minigame can only be run when I play that specific scene.
When I try to run my whole project(starting from the main menu screen), it throws me an error(Attempt to call function 'get_node' in base 'null instance' on a null instance) saying my minigame node was not found. So I press the 'remote' button next to 'local' and see that my minigame scenetree is not there and that's why it cant detect the node.
I have tried adding the minigame scene as an autoload. This made it work and I can run it from the main menu again but then the things inside my minigame wont load so it became a blank screen when it arrives to the minigame scene.
How do I make it so my minigame will load properly and the project can be started from the main menu scene?
Upvotes: 2
Views: 5482
Reputation: 40210
So your code in Autoload is trying to access something that is not in Autoload.
As I said in the old answer, There is no guarantee that what the Autoload is trying to access is there. You cannot rely on it being loaded and available to the Autoload.
Of course, if you run the game form a scene, you could trust that particular scene is loaded. But if you start the at another scene, then that isn't the case. So what do you do in that case?
Well, you need to load the scene you need by whatever means (see old answer for ways to load a scene). And you need to pass the instance to Autoload.
One way to pass that instance, is to have a function in the code in Autoload that takes the Node as parameter. Then after you load the scene, you can call that function passing the instance.
To reiterate, your main scene will load the minigame scene (by whatever means), so it have an instance of it. Then it will get the Autoload, and call a function on it passing the instance.
Let us try again, in your main scene, you will load the minigame. That can be accomplished by different ways. For example, calling load
with the resource path will give you a PackedScene
. Then you call instance
on the PackedScene
which gives you an instance.
Afterwards, you can add that instance to the scene tree using add_child
...
That same instance you will pass it to the Autoload. The code in the Autoload needs a variable to store it, which you will set.
In your main scene you can use get_node
to get the Autoload (and yes, an Autoload can be a scene). See Singletons (AutoLoad). And then set the variable with instance you loaded.
For completeness sake, I'll also mention that you can change scenes with change_scene
. The code in Autoload would remain when you do that. And this could make changing scenes simpler. However, if you later need to make something that was a separate scene a part of a bigger one, or if you decide that you need background loading, then having relied on change_scene
will be an obstacle. See also SceneTree and Change scenes manually.
First some organization. Where are you using get_node
?
If you are using get_node
in the the main scene to access the minigame. That is ok, you just need to make sure that the minigame is already loaded and in the node path you need it.
Remember that to use get_node
you need a Node to begin with. Thus, either the code where you call get_node
is a in a Node
, or some other code gave a Node
(e.g. as a parameter on a function call) to it. Also, what you are trying to get must be there.
These are the problematic cases:
get_node
on a node some other code gave to it. You probably can have that other code give the node the Autoload needs directly.See Node communication and Understanding Node Paths.
Second, there are other things that you could be presuming to be true in your code, that might not be once it is loaded somewhere else. Such as:
And third, there are many ways to load a scene, for starters:
These methods have one important drawback: the minigame is loaded preemptively. Which may make loading the game slower. If load time is a problem, you might prefer to load it on demand. For that we have more options:
PackedScene
of your minigame in code using load
(passing the resource path as parameter) and then instance
, and add_child
.preload
(passing the resource path as parameter) to get the PackedScene
. And then when you need it, you can instance
and add_child
.class_name
(see Register scripts as classes) which would let you instance it with new
. If it is a node, you can add it to scene tree with add_child
afterwards. It might not be a node, which is also useful sometimes. By the way, you can give it static functions, which you could call without instantiating it (no static variables, if you want static variables use Autoload instead).InstancePlaceholder
node. You can call replace_by_instance
on it when you need it.Drawback? When loading on demand, the game will halt while loading. If the individual things you are loading on demand are small enough, that is no problem. However for a large scene, it might be. That leads us to a final option:
ResourceLoader.load_interactive
passing the resource path as parameter. This gives you a ResourceInteractiveLoader
, on which you can call poll
to load the scene steadily. Once it is loaded you call get_resource
, which gives you the PackedScene
that you can instance
and add_child
.Drawback? It is significantly more code in comparison with the other approaches. Ideally you would reuse it. In fact, you can put this logic on a Autoload, and that way it is available anywhere you need to load something.
You could, in fact, use background loading to load the main menu. Then the main menu can load all it needs to work simply having it there in the scene tree. Which would also mean that the main menu is not the starting scene. Instead the starting scene uses background loading to load the main menu. Visually it could have a logo and a progress bar, or something along those lines. However, this suggestion is not for every game, only for those that take considerable time to load.
In case of confusion: Node paths are in the scene tree, see get_node
and NodePath
. And resource paths are in the project internal file system (the ones that start with res://
), see Data paths.
Upvotes: 1