How to share a global variable among several nodes and make them react to changes within the editor

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By frankyboy

Suppose I have a bunch of “enemy”- nodes with individual sprites.
Now during level design I’d like to have a single “global” variable “scale” to affect all the sprite scales at the same time.

I’ve created a Node “GlobalVars”. Then I’ve added a script:

tool
extends Node
export var myscale=1.0

The Sprites also have a script attached, which looks something like

tool
extends Sprite

var rscale =1.0 setget myset,myget #dunno if I need to use setter or getter
var cntrl   #reference to my Node GlobalVars

func _ready():
	cntrl=get_node("/root/Main/GlobalVars")
	rscale=cntrl.myscale	
	self.scale=Vector2(rscale,rscale)
	
func myset(nuval):
	cntrl=get_node("/root/Main/GlobalVars")
	rscale=cntrl.myscale	
	self.scale=Vector2(rscale,rscale)
	
	
func myget():
	cntrl=get_node("/root/Main/GlobalVars")
	rscale=cntrl.myscale
	self.scale=Vector2(rscale,rscale)

I’ve reloaded the scene and immediately Godot tells me that it wasn’t able to find the Node called “GlobalVars”… However, godot runs scene is runnable and it also uses the proper scaling from the GlobalVars-Node, i.e. the Nodepath is all right…

What am I doing wrong ?
Is there a better way to accomplish what I’m trying to do? (I started to play around with Godot 2 days ago…)
I feel like there should be a cleaner way

Any suggestions?

best regards,
frankyboy.

:bust_in_silhouette: Reply From: Zylann

It tells you GlobalVars is not found because you made your scripts run in the editor. A scene in the editor is a slightly different environment from a running game, in particular when it comes to absolute paths:

cntrl=get_node("/root/Main/GlobalVars")

This path won’t work in the editor because /root will be the root of the editor itself.

  • You might want to consider using a relative path, or another way to reference the scale variable.

  • You might try using an autoload, which is the most commonly suggested, but I don’t know if tool works on them in the editor.

Another way is to use a get_node_in_parents() pattern, so the first parent found having the scale script will be used. This is good if you want to keep your scale local to the children of the node:

static func get_node_in_parents(node, klass):
	while node != null:
		node = node.get_parent()
		if node != null and node is klass:
			return node
	return null

Get first parent node having the Globals.gd script on it:
get_node_in_parents(self, preload("Globals.gd")).myscale.

  • Yet another way would be to not use nodes, but a shared resource instead. Make your myscale script extend Resource, and attach it to a Resource object which you can save next to your scene. Then attach that resource to each node where you want to use the scale. This way, if you modify the resource, all nodes having it will be able to access it.

  • Or again another way is to put your scale script into a special group, and make other nodes access it using get_nodes_in_group("globalscale")[0].myscale.