Kiowe Smith
Kiowe Smith

Reputation: 3

Godot 4: Change label text on UI scene when player enters area2d

Im making a game in Godot 4 and have a main world scene that the player is on. It has an Area2d node that changes the current scene to a UI scene when the player enters the area2D. The area2D takes a PackedScene and locationName as export variables. It loads the UI scene (named "Location") fine but I cannot get the UI scene to load the locationName I want. Also, the UI scene is not in the world scene (ie. where the area2d is and player are)

I have tried multiple methods including moving the UI scene to the world scene and using signals, also creating set gets. The problem seems to be coming from the fact that the label node on the UI is ready after the name is changed, so I get a nil exception.

Location.gd:

extends Node

@onready var itemList = $VBoxContainer/HBoxContainer/VBoxContainer/ItemList
@onready var nameLabel = $VBoxContainer/HBoxContainer/VBoxContainer/LocationName
@onready var image = $VBoxContainer/HBoxContainer/Image

var localName: String = "test"

func setLocationName(newName: String):
    self.localName = newName
    print(self.localName)
    
func setLocationImage(newImage: Image):
    image.texture = newImage

# Called when the node enters the scene tree for the first time.
func _ready():
    print("ready")
    if is_node_ready():
        update()
    #generate 3 rgcs and add them to itemList, display their name, gang, and favor
    #image.texture = ResourceLoader.load(location image)
    
func update():
    print("update")
    nameLabel.text = self.localName
    print(self.localName)

EntryPoint.gd:

extends Area2D

@export var targetLocation : PackedScene
@export var locationName: String

func _ready():
    pass

func _on_body_entered(body):
    var location = targetLocation.instantiate()
    location.setLocationName(locationName)
    get_tree().change_scene_to_packed(targetLocation)

    

enter image description here

Upvotes: 0

Views: 640

Answers (1)

Theraot
Theraot

Reputation: 40220

What you seem to be trying to solve is how to communicate information across a change of scene?


What you are doing is not going to work. Because the instance you create here is wasted:

var location = targetLocation.instantiate()
location.setLocationName(locationName)

You are effectively leaking that instance (Nodes are not reference counted).

And changing the property on it does not have the effect you expect because when you call change_scene_to_packed Godot will create a new instantiate of that scene.


So, how to communicate information across a change of scene?

There are a few things that survive when the scene changes:

  • Properties in an Autolaods
  • static properties
  • Resource properties※
  • External files

※: Everywhere you preload a Resource you should get the same instance, because Godot is keeping an internal reference preventing it from unloading... Unless you mess with that.

So you could store the information in one of those places, and then when the new scene loads, it can retrieve the information.


The alternative is to change the conditions of the test problem: You do not need to worry about how to communicate information across a change of scene, if you never change scene at all.

This is the approach I have personally taken: I never change the main scene. In that main scene I have the UI, and I load, instance, add as children, and free the world/stage scenes inside of it.

Upvotes: 0

Related Questions