I have put nodes in a group. And I have put a func on the scene script to make changes to the nodes in group. In that func,I made the nodes to queue free and stuffs like that. But when I change scene and come back to the previous scene,the queued free is back again,it is not queued free anymore. How do I make it not change even after changing scene?
Why information is lost
When you change the current scene with change_scene
or change_scene_to
the current scene is unloaded, and the new one is loaded and instanced.
Perhaps it helps to conceptualize that the instance of the scene is not the same as the scene in storage. So what happens is like opening a file in an editor, modifying and not saving it.
Alright, that is one solution if you really want to go that route: you can save a scene.
First create a PackedScene
, for example:
var packed_scene := PackedScene.new()
Then tell it to pack the root node of the scene, for example:
packed_scene.pack(self)
Note: any Node
s that don't have their owner
property set to the Node
you passed here will be ignored. And no, add_child
does not set the owner
property.
If you have been paying attention, you know you can give a PackedScene
to change_scene_to
... But how do you keep it around when the scene changes?
There are a few ways. And the thing is: if we can keep information around, we might not need to save the scene.
Keep things around in autoloads
The scripts and scene you add to your autoloads (singleton) in project settings stay there (unless you explicitly remove them) even when you change scene.
Thus, a very simple way to keep information around is to have a script with some variables that you can write and read from anywhere in your project. And you can do that with an autoload.
Keep things around in resources
Godot caches resources. When you load the same resource in multiple places, you actually get the same object.
Well, you know you can create a custom Resource
class. To do that, on the context menu of the FileSystem panel select "New Script", and in the script make a class that extends Resource
, and give it a class_name
.
Then you can create resources of that Resource
from the context menu of the FielSystem panel by selecting "New Resource" and picking your Resource
class when asked.
Everywhere you load one of those, you are going to get the same object. Yes, even if it is in another scene. So you can add variables to your Resource
class, write them in one scene and read them in another.
I explain a more concrete example elsewhere.
Keep things around in storage
You can write to a file and read from a file. For example you can do this:
# save
var file = File.new()
file.open("user://a.sav", File.WRITE)
file.store_pascal_string(var2str(data))
file.close()
# load
file.open("user://a.sav", File.READ)
data = str2var(file.get_pascal_string())
file.close()
Or, if what you want to store is a Resource
(be it a PackedScene
, or some other Resource
class including a custom one), you can use ResourceSaver
and ResourceLoader
:
# save
ResourceSaver.save("user://a.tres", resource)
# load
resource = ResourceSaver.load("user://a.tres")
Of course, you can also load resources with load
, or preload
. You may also be interested in Background Loading.
By the way, if you are going to save player progress, having all the player progress data in a single object makes sense. And if you are going to have all the data you are keeping all the player progress data in a single place, it makes sense it would be somewhere it is accesible all the time and stays around even when you change scenes, thus: put the player progress data in an autoload. Bonus: you can put the functions to save and load to a file there too.
Don't change scenes
Since changing scenes brings problems - consider another solution: don't.
You can load an scene:
var packed_scene := load("res://scene.tscn") as PackedScene
Then make an instance of it:
var scene := packed_scene.instance()
Then add it to your current scene tree:
add_child(scene)
Yes, it is a Node
! It also means you can…
scene.queue_free()
Or you can simply remove it with remove_child
which does not free it, so you can add it back later.
So you would be in control of what gets loaded or unloaded and when. Which is useful to keep stuff around (e.g. the UI, the player character, etc...). A drawback of doing it the way I describe here is get_tree().current_scene
would not be useful to you anymore. See also Change scenes manually.