global variable value not changing after get_tree().reload_current_scene()

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

I wanted the variable

first_playthrough

to become false so when the scene reloads, it won’t show the text “Hello from Number Guesser” anymore. But it’s still showing it.

Therefore, it’s either: it never became false, or that it became false, but then went back to true.

The shortened version of the code:

extends Node

var first_playthrough = true

func _ready():
  # this is here so it will show the message
  first_playthrough_checker()

func first_playthrough_checker():
  # problem here is that, the message below still shows even though i thought i set it to 'false' already.
  if first_playthrough == true:
    text_printer("Hello from Number Guesser!\n\n")

func _restart_game():
  #I've tried everywhere else. Thought it would work here. i was wrong.
  get_tree().reload_current_scene()
  first_playthrough = false

One solution would be a persistent data storage.
But maybe for a simple game like this one, it isn’t needed anymore?
What am i doing wrong here?

I’ll post the whole script if needed.

:bust_in_silhouette: Reply From: omggomb

first_playthrough isn’t global though, it’s local to the script. So once you call reload_current_scene a new node with a new instance of the same script will be created and first_playthrough will be true again. The old node, where the value is false, will be around but not in the scene tree, so it doesn’t get updated in anyway and isn’t visible, until it is freed (automatically).
One way to solve this is using singletons (AutoLoad in Godot)
See here: https://docs.godotengine.org/en/3.1/getting_started/step_by_step/singletons_autoload.html?highlight=autoload

Ah, i suspected the scene was just reloading along with first_playthrough’s true when i thought it was going back to true after it became false. That makes sense!

This made me learn how to use singletons.

Thank you for pointing me in the right direction!

Follow up question. (Not sure if it’s totally out of scope to the OG question here) Did you mean then that get_tree().reload_current_scene() does not destroy the old scene, henceforth creates a memory leak? Then should i always .free() the scene even when using reserved functions such as reload_current_scene()?

jagc | 2019-05-14 20:30

It’s deleted automatically, no worries. What I meant is that the old scene isn’t immediately destroyed after you call reload_current_scene but is kept in memory until it is save to delete it and then deleted automatically. If you were to delete it immediately chances are that some node hasn’t finished processing and you would be left with an unstable program. Search for call_deferred in the singleton docs if you want to know more. A node’s queue_freemethod is there for the same reason. See here: https://docs.godotengine.org/en/3.1/classes/class_node.html?highlight=queue_free#class-node-method-queue-free

omggomb | 2019-05-15 19:08

:bust_in_silhouette: Reply From: jagc

Building on @omggomb’s answer.
After creating the singleton globals where first_playthrough is declared, i replaced all instances of the variable on the script into globals.first_playthrough.

So in the shortened version of the code, this looks like:

extends Node

# removed the declaration here already, since it's already declared in globals.gd

func _ready():
  # this is here so it will show the message
  first_playthrough_checker()

func first_playthrough_checker():
  # message below doesn't show anymore after globals.first_playthrough becomes false.
  if first_playthrough == true:
    text_printer("Hello from Number Guesser!\n\n")

func _restart_game():
  #I haven't tested it but i suspect the line after reloading the scene will create a memory leak?
  #So i changed globals.first_playthrough's value before reloading the scene instead.
  globals.first_playthrough = false
  get_tree().reload_current_scene()

The script works as intended now.

By learning to use singletons, i learned that:

  • Declaring a variable global to the class even in a single script project doesn’t make it actually global.
  • An object is only global if it is declared in the project as so.
  • I should keep in mind that I’m still using a framework.
  • With gdscript, I have 3 options to store persistent information. 2 of which are most recommended.