+13 votes

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.

in Engine by (88 points)
edited by

5 Answers

+28 votes
Best answer

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()
by (1,328 points)
selected by

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!

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! :)

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?

You can check mine below :) 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).

+1 vote

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.

by (60 points)
+4 votes

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.

by (289 points)
+1 vote

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.

by (849 points)
edited by
+13 votes

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")
by (28,878 points)

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

Nice ! Just what I was looking for

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

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.