Transfering a variable over to another scene?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By spicy
:warning: Old Version Published before Godot 3 was released.

Okay, so I’m stuck here.

When my player gets hit, he loses a life (this is displayed in a lives counter at the top of the screen) and then the scene resets itself after about 4 seconds (it reloads the scene).

The only problem is the lives counter also resets when the scene reloads. Instead, I want it so that when the scene resets itself, the lives counter remains the same as it was from the previous scene (ie the same scene, just before it was reset).

I’ve heard this can be done using Autoloads or saving data to a file and then loading it later on. I’ve looked into this online but didn’t manage to get any luck in being able to get either to work. I kept getting errors about null instances if I’m not mistaken.

So what I’m asking is, are these two methods what will work for me? And is there any decent tutorials showing this? Because the ones I’ve followed haven’t helped me too much.

EDIT: I’ve managed to load a globals.gd script upon startup, so that’s a start.

:bust_in_silhouette: Reply From: PlanetKiller

Usually I just make an auto load script to hold global data. I then write some functions to get and set the values from another script. You have to add the script to the autoload list in project settings, then use get_node() to assign it to a variable.

:bust_in_silhouette: Reply From: YeOldeDM

Create a new script (doesn’t have to be assigned to a node). Let’s call it global.gd

In Project settings, under the Autoload tab. Find the global.gd path and call it ‘global’. Check it as a singleton (this should be on by default).

Your global.gd script should look something like this:

extends Node

var lives = 10

Since global.gd is a singleton called ‘global’, we can call it from anywhere else in our game as global.lives, and anything kept in global.gd will be retained regardless of what the current scene is.

example:

func die():
    global.lives -= 1
    if global.lives <= 0:
        game_over()

oh wow, that’s a neat new feature in 2.0! saves me so much code not having to get_node that global.gd everywhere!

batmanasb | 2016-03-22 22:30

Thank you for taking the time to answer!

Compared to other tutorials I’ve read, you explained it really easily and I was able to get it running in no time. Thanks again! :slight_smile:

spicy | 2016-03-23 13:13

The problem I see with this solution is that it involves creating a global “singleton” script, which is generally a bad software development practice. Surely it does the job but it could get messy very quickly.

Are there any other solutions?

David Saltares | 2016-08-11 12:33

You can check mine below :slight_smile: it’s still kind of a singleton, but that’s the best I can think off if change_scene() is used. Otherwise I would not use change_scene (with everything it implies).

Zylann | 2016-12-14 21:12

:bust_in_silhouette: Reply From: Nuno Donato

Besides the autoload solution, I’ll share how I’m doing it in my game since I have many levels.
I have a “play” scene, which holds the in-game UI, pause menus, etc, and one child is the level itself. So when I restart, I only reload the level scene, which is a child node of the main scene.

:bust_in_silhouette: Reply From: batmanasb

Here you go.

Basically, what you do is:

  1. make a new script and make it extend something like Node for example
  2. add it to AutoLoad in the project settings
  3. access it from any other script using: get_tree().get_root().get_node("AutoLoad_name")
    4(not in Docs yet, new feature in 2.0). or if you check the little “Singleton” check box in AutoLoad, you can simply just access the script anywhere using the AutoLoad name you give it

ex: make a script called global.gd, added it to AutoLoad with the name “global”, check the Singleton box, then simply type “global.someMethod()” or “global.someVariable” to access it!

This way it works just like any other script, you can access it’s variables and methods. The only difference is that when you switch scenes or reload a scene, it isn’t part of the scene, so it doesn’t get touched. It also gets loaded when you launch the game, so it’s always there for you to access.

:bust_in_silhouette: Reply From: Zylann

I’ll add my small contribution:

While using a singleton with public variables anyone can read and modify at any time is a working solution, I don’t really like the design.
After all, the problem is to open a scene with arguments, right?

Then, this is what I did:

# scene_switcher.gd
extends Node

# Private variable
var _params = null

# Call this instead to be able to provide arguments to the next scene
func change_scene(next_scene, params=null):
	_params = params
	get_tree().change_scene(next_scene)

# In the newly opened scene, you can get the parameters by name
func get_param(name):
	if _params != null and _params.has(name):
		return _params[name]
	return null

I add this in AutoLoad as SceneSwitcher, then it can be used like this:

# In the calling scene
SceneSwitcher.change_scene("map_viewer.tscn", {"location":selected_location})

# In the new scene
var current_location = SceneSwitcher.get_param("location")

I love your approach! Thanks for sharing it :D.

Dri | 2016-12-14 12:58

Nice ! Just what I was looking for

AlvaroAV | 2017-03-21 23:59

Yes, it’s better to try to stop unwanted writes to the data. Now there appears to be Setters/getters available in the GDScript.

backendcoder | 2018-01-21 18:05