How can I get a variable from another node?

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

I know this has been asked and answered many times before but i must’ve missed or misunderstood something cause nothing in those questions seems to work for me.

I’m making a sort of debugging overlay for myself to display some variables in-game while I’m working on a weather system and I prefer to have my debugging code centralized in one script if possible(UserInterface.gd in this case).

I have my village map/scene with a Player.tscn with the UI.gd in it and a CanvasModulate for changing the tint of the scene depending on the weather. This CanvasMod has a script attached called WeatherManager,gd with the variable I want to access and display on my UI called “currentWeather”(contains a string with the current weather).

So in the UI.gd, this is the basic code I’ve tried but it always return null which indicates an incorrect path:

onready var canvasMod = get_node("/Village/CanvasModulate")
func _physics_process(delta):
	var _curW = canvasMod.currentWeather
	if $CurrentWeathr:
		$CurrentWeathr.text = str("Weather - ") + str(_curW)

I’ve also tried using $CanvasModulate and every possible path I can think of :
/…/CanvasModulate
/CanvasModulate
/root/Village/CanvasModulate
/root/CanvasModulate
Also tried the filepath:
res://Game Scenes/Village.tscn
This solution too which I found in another question:
get_node(“object here”).variable
etc

SceneTree looks like this:

  • Village
    -----TileMap(of course a bunch of other TM’s and other things but unrelated to the question)
    -----YSort
    ----- -----Player - Inside it’s separately saved scene:
    ----- ----- -----UserInterface(CanvasLayer type with UserInterface.gd attached)
    ----- ----- -----CurrentWeathr(Label type)
    -----CanvasMod(WeatherManager.gd attached

Any and all help is appreciated. Sorry for the long post. Thanks!

try

var villa = load("res://GameScenes/Village.gd").new()

or
player script

var villa
func _ready():
     villa = get_owner().get_node("CanvasMod")
     pass

func example():
   villa.func_name_in_the_canvasmod()
   pass

ramazan | 2022-09-18 12:24

:bust_in_silhouette: Reply From: aXu_AP

Traversing from UserInterface node, path to CanvasModulate is get_node("../../../CanvasModulate"). Each .. steps up in hierarchy: Player > Ysort > Village from which descent into CanvasModulate.

This, while is plausible way to do it however, is very prone to errors. What if you move things around? What if you put your player scene in some other scenario? For these reasons, it’s better to use one of following:

1) Use export variable
This option is good, because the path is settable from the editor. If something moves, editor takes care of updating the path. In your case, you also need to set player’s children editable (right click/editable children) since it’s separate scene in order to set the path.

export var canvasModPath : NodePath
onready var canvasMod = get_node_or_null(canvasModPath)

Note: check that the variable isn’t null before using it, so you won’t get errors in surprising situations (unless error is more desirable than silent fail).

2) Use groups
This one’s also nice for finding something you don’t always beforehand. You need to add the CanvasModulate node in a group, in this case called “Weather”. You can manage groups by selecting the node and switching in the right (inspector) panel to Node tab > Groups.

func _ready() -> void:
	var weatherGroup = get_tree().get_nodes_in_group("Weather")
	if weatherGroup.size() > 0:
    	# Get first node and ignore if there's more
		canvasMod = weatherGroup[0] 

3) Use find_node()
This option is sometimes handy, if there’s too much going on and you’re sure how the needed node is named and no other nodes share that name. You should name the node more uniquely, for example WeatherCanvasModulate. You then can find it with following code:

get_tree().root.find_node("WeatherCanvasModulate")

This solution, does again presume some things about node structure, which does has it’s own hazards. If you return to your game after a few weeks or months break, you might not remember that node name has certain significance and might break it unintentionally.

I see what you mean. I’m really just looking to have a label on my screen that tells me what a variable is returning while I’m making something new. I want the label to follow my player which is why I want to reference it in a different object.

I’m trying out what you suggest, the first solution seems the best and most straight forward but I’m kinda stupid so I must be doing something wrong cause I can’t get it to work.

I have those 2 “export var/ get_node_or_null” lines in my now renamed WeatherCanvasModulate. Then in my player script I have this:

$curWeatherLabel.text = str(WeatherCanvasModulate.currentWeather)

Of course a label with that name in the player scene as well. The player and canvasmod has editable children enabled but I can’t reference the object nor the variable in any way(that’s apparent to me).

I really appreciate the help, thanks!

Burloe | 2022-09-18 16:05