I’m making a 2d platformer, there are variables I want to save across different scenes. For instance there are coin collectables 1 per level, and I want the game to know which level a coin has been picked up in, and how many total coins. I’m also trying to have a death tracker. I also put in a timer for each level but dont know how to save the finished time.
I’ve searched this up and found a huge amount of answers but none seem to work for me. I’m sorry if this is a common question, I just feel lost when trying to make it work. I’ve tried @export var EX (example) in a “global” singleton and then in my other script “var EX = 1”. Ive tried “var _lvl1_time = $CanvasLayer/Panel.time” and that didnt work.
My script for my timer:
@export var time : float = 0.0
var min : int = 0
var sec : int = 0
var msec : int = 0
signal completed_time
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta) -> void:
time += delta
msec = fmod(time, 1) * 100
sec = fmod(time, 60)
min = fmod(time, 3600) / 60
$minutes.text = "%02d:" % min
$Seconds.text = "%02d." % sec
$MS.text = "%03d" %msec
func _stop_timer() -> void:
set_process(false)
func _get_time_formatted() -> String:
return "%02d:%02d.%03d" % [min, sec, msec]
func _on_next_level_lvl_done() -> void:
emit_signal("completed_time")
_stop_timer()
My script for my global singleton:
class_name saved_data extends Node
@export var _lvl1_time: int = 0
@export var _lvl2_time: int = 0
@export var _lvl3_time: int = 0
@export var _lvl4_time: int = 0
@export var _lvl5_time: int = 0
@export var _lvl6_time: int = 0
@export var _lvl7_time: int = 0
@export var _lvl8_time: int = 0
@export var _lvl9_time: int = 0
@export var _lvl10_time: int = 0
@export var _total_time: int = 0
@export var _total_deaths: int = 0
@export var _lvl1_coin: bool = false
@export var _lvl2_coin: bool = false
@export var _lvl3_coin: bool = false
@export var _lvl4_coin: bool = false
@export var _lvl5_coin: bool = false
@export var _lvl6_coin: bool = false
@export var _lvl7_coin: bool = false
@export var _lvl8_coin: bool = false
@export var _lvl9_coin: bool = false
@export var _total_coins: bool = false
@export var _lvl1_complete: bool = false
@export var _lvl2_complete: bool = false
@export var _lvl3_complete: bool = false
@export var _lvl4_complete: bool = false
@export var _lvl5_complete: bool = false
@export var _lvl6_complete: bool = false
@export var _lvl7_complete: bool = false
@export var _lvl8_complete: bool = false
@export var _lvl9_complete: bool = false
@export var _lvl10_complete: bool = false
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func completed_time():
var _lvl1_time = $CanvasLayer/Panel.time
var _total_time = _total_time + $CanvasLayer/Panel.time
print(_lvl1_time)
Export just means the var is available to edit in the inspector view. It doesn’t mean “export so that other scripts can see it”.
It looks like there’s some confusion on signals here as well. You set up a signal called completed_time, and even emit said signal, but you never handle said signal. The method func completed_time() in your global singleton does not fire when your signal emits, from the code I see here.
If you want to save some data between levels, one simple way is to just use an autoload script. I would imagine your global singleton is such a script, since autoloads are just global singletons. You didn’t mention the Autoload’s name, so let’s just assume it is called Globals.
In globals.gd:
var all_coin_pickups = {}
var all_deaths = {}
func pickup_coin(level_name:String, num_coins): # Or whatever
all_coin_pickips[level_name] = num_coins
func record_death(death_time, other_info): # Or whatever
all_deaths[death_time] = other_info
Then in player.gd:
func die():
# whatever death code you already have
Globals.record_death(current_time, whatever_data)
and in coin.gd:
func _on_coin_pickup():
# Whatever other code you already have on coin pickup
Globals.pickup_coin(current_level_name, 1)
Ah so the big thing I was missing was establishing a function in global and then calling it in other scripts. Thank you so much.
New questions I have is for the coin pickup how would I establish what the current_level_name is? Or would I have to manually put that in for each level and have a specific coin script for each level?
And lastly concerning signals I was very confused on how to get the global to look out for signals, I think I just figured that out. Is it a bad idea to have global load nodes to look for signals like in the documentation example?
func _ready():
var timer = get_node("Timer")
timer.timeout.connect(_on_timer_timeout)
New questions I have is for the coin pickup how would I establish what the current_level_name is? Or would I have to manually put that in for each level and have a specific coin script for each level?
You only need one coin script, and you can pass the level name when you instantiate the coin. Or query Globals.current_level (which you need to set each time the level changes). Or put the coin pickup code in level.gd, and have it fire off of a coin_picked_up signal. If these concepts are all new, then probably the simplest is using globals for things until you get a better feel for stuff.
And lastly concerning signals I was very confused on how to get the global to look out for signals, I think I just figured that out. Is it a bad idea to have global load nodes to look for signals like in the documentation example?
Globals can listen for whatever signals you like, but it will be awkward to get this to work if the signals are emitted from dynamically instantiated nodes. One workaround that I’ve come to enjoy quite a bit is to put all of my signals into an autoload called SignalBus.
signal_bus.gd:
signal health_changed
signal player_died
signal enemy_killed
signal coin_picked_up
signal game_over
# etc etc etc
This allows anyone anywhere to emit whatever signals, while any listeners don’t need to be aware of who is emitting the signals, but just needs to know the signal names: