oliver james
oliver james

Reputation: 11

Is there such thing as a global variable? (GDscript)

I'm trying to make a game but I need something like a global variable for it to work. Is there a way in GDscript that you can make a variable that works across all nodes with scripts. I need a button that makes you buy a gun which would set a variable to true and with that variable being true, you could equip the gun.

This question doesn't really fit this section where it says: What did you try and what were you expecting? so I'm just gonna skip it.

Upvotes: 1

Views: 9761

Answers (1)

Theraot
Theraot

Reputation: 40170


New Answer

Starting with Godot 4.1 you can use static variables:

static var my_variable := true

All the instances of your script will share these variables.

Also you can make the equivalent of the Globals autoload by using a class_name like this:

class_name Globals

static var has_gun := false

Which you do not need to register as an autoload. You just need to have this script somewhere in your project.

Godot has also static methods (static func), which you can call from anywhere.

Be aware that this approach makes for an inconvinient signal bus, because currently there are no static signals (proposal). But there are workarounds, see: How to write a static event emitter in GDScript?.


Old Answer

Is there a way in GDscript that you can make a variable that works across all nodes with scripts.

You could use an autoload.

Go to the Project menu, the Project Settings option, in the Autoloads tab… And there you can set a script, and give it a name. It will be available for every node in the scene tree.

For example, you can have a "globals.gd" script that looks like this:

extends Node

var has_gun := false

Then you make it an autoload with the name "Globals". So in any other script you can use it. For example:

extends Node

func _ready() -> void:
    print(Globals.has_gun)

And yes, autoloads will stay there even if you change the current scene.

You might also be interested in the Signal bus (Event bus) pattern, which involves defining signals in an autoload, such that other scripts emit them or connect to them.


Technically the autoload is not a true global. As I said, the autoload will be available for the nodes in the scene tree.

This also means the autoload will not be available for a script that is not a Node (e.g. a Resource), or otherwise not in the scene tree.

Unless you use a hacky workaround to get a reference to the autoload, which I will not go into.


Instead, I will give you an alternative: resource based communication.

This time you create a "global_resource.gd" that look like this:

class_name GlobalResource
extends Resource

var has_gun := false

And then you can use the context menu on the FileSystem panel to create a new resource. When Godot asks you for the type, you select GlobalResource, and give it a name such as "globals.tres".

Then you can use it like this:

extends Node

const Globals := preload("res://globals.tres")

func _ready() -> void:
    print(Globals.has_gun)

Everywhere you preload that same resource file ("globals.tres") you will get the same Resource instance. It does not matter if it is in the same scene, or if you changed the current scene.

And yes, this does not depend on the scene tree. And yes, you can put signals in there too.


For completeness sake, I'll also mention that there is another hacky workaround which involves defining a Dictionary or Array as const in a script with a class name. Since in Godot 3 const does not imply inmutable (don't count on this on Godot 4). That is how some people currently work around the lack of static variables. However, I believe you won't find it necessary.


Addendum: You add custom properties in project -> Project Settings… And you can give its default value there (even a different one per target platform). In runtime you can read them with ProjectSettings.get_setting or write them with ProjectSettings.set_setting.

Upvotes: 3

Related Questions