Before we get started, let me address that please do not tell me to just use singletons. That is what I am trying to do. I am trying to use singletons to create a countdown timer that keeps counting down even when you switch to a different scene. Here is the code inside my global TimerData script:
extends Timer
func _process(_delta):
var _time_remaining = Timer.time_left
Here is the code for my timer itself: ```extends Node2D
var explosion: PackedScene = load(“res://Scenes/Explosion.tscn”)
@onready var label = $MarginContainer/VisibleCountdown @onready var timer = $Timer
func _ready():
timer.start()
func _time_left_until_expired_food_explodes():
var time_left = TimerData._time_remaining
var minute = floor(time_left / 60)
var second = int(time_left) % 60
return[minute, second]
print(TimerData.time_remaining)
Whenever I press F5 to run the project the debugger returns this error for the process function in my global TimerData script: _process: Invalid access to property or key ‘time_left’ on a base object of type ‘Timer’.
It looks like you create the variable every frame in the global script and keep it in local scope. You will not be able to access it outside of the process function.
You could change it to
var _time_remaining: float
extends Timer
func _process(_delta):
\_time_remaining = Timer.time_left
It still will probably not work but its one or two issues gone.
Your problem is you are not using the Timer correctly. Your error is because you are referencing a variable in _process() before it is declared. There are a couple of solutions for this.
Please format your code correctly so that it is readable. This post will help you with that:
extends Node2D
var explosion: PackedScene = load("res://Scenes/Explosion.tscn")
@onready var label = $MarginContainer/VisibleCountdown
@onready var timer = $Timer
func _ready():
timer.start()
func _time_left_until_expired_food_explodes():
var time_left = TimerData._time_remaining
var minute = floor(time_left / 60)
var second = int(time_left) % 60
return[minute, second]
print(TimerData.time_remaining)
func _process(_delta):
label.text = "%02d:%02d" % _time_left_until_expired_food_explodes()
func _on_timer_timeout():
get_tree().change_scene_to_packed(explosion)
Sorry about that. The double backticks don’t seem to work for me. Anyway, here is the Timer code in a readable format. Here is the global TimerData code once more:
I updated it so that I am not creating the variable every frame but I still get the error. The error is this: _process: Invalid access to property or key ‘time_left’ on a base object of type ‘Timer’.
When you write Timer.time_left you try to access the base class “Timer”, not a specific instance of it. You need to reference and access the specific timer you want.
If you want to access the timer the script is attached to, just write time_left. It will use time_left on itself. It is the same as self.time_left.
I also want to add that the issue before, with keeping the variable inside process is that you will not be able to access it from outside of the function. You would only have been able to access it in the process function of that script. If you want a variable to be accessible in the way you tried to access it, you have to declare it outside of any function, without indenting it. Otherwise time_left will return null.
Definitely not. You still tried to access “Timer.time_left”. That will not work as Timer is not an actively running timer but the class Timer. You can’t even name a variable “Timer” as that would shadow the class. And time_remaining doesn’t exist in that class.
I am not good at Godot, which is why I am having this issue in the first place. I have been trying to read these very closely, I spent several hours looking at singletons on docs to try to figure out the issue, but to no avail. I also do not see the variable “timer” that you seem to be referring to. I know a basic python, but when it comes to how Godot works I am mostly clueless aside from how to make a player move and scene switching and basic things like that. The script I was given was very similar to my previous script. I would like to learn these, and if you could help, that would be much appreciated. Not saying you arent trying to help, but some of the things do not make complete sense like why I can’t use timer.time_left because I set it to autostart so it should be actively running, no? Or is it not because the timer itself is never told to start in code? Needless to say i am a bit confused
Here’s a fully functional project doing what you asked for. I don’t understand why you decided this needed to be a global Timer, but this is how I would do it. It works, I tested it.
I will try it. The only reason I decided to try and use a global timer was because I had learned about singletons and assumed that that was the only way to do it lol
Whenever I try to run the game it returns this error: Invalid access to property or key ‘on_trigger_player_spawn’ on a base object of type ‘Nil’. My player script is this:
extends CharacterBody2D
class_name Player
@export var speed := 340
@onready var animated_sprite = $AnimatedSprite2D
var panicked = false
func _ready():
Global.on_trigger_player_spawn.connect(_on_spawn)
func _process(_delta):
pass
# movement script
func _physics_process(_delta):
var direction = Input.get_axis("left", "right")
if direction:
velocity.x = direction * speed
animated_sprite.play("walk_not_panicked")
animated_sprite.flip_h = direction < 0
else:
velocity.x = move_toward(velocity.x, 0, speed)
animated_sprite.play("idle_not_panicked")
move_and_slide()
func _on_spawn(Position: Vector2, _direction: String):
global_position = Position
And the script from the project you told me to try is this:
extends Label
var EXPLOSION: PackedScene = load("res://Scenes/Explosion.tscn")
func _ready():
GloTimer.timer.start()
GloTimer.timer.timeout.connect(_on_timer_timeout)
func _time_left_until_expired_food_explodes() -> String:
var time_left: float = GloTimer.timer.time_left
var minute: float = floor(time_left / 60)
var second: float = int(time_left) % 60
return "Time remaining: %02d:%02d" % [minute, second]
func _process(_delta):
text = _time_left_until_expired_food_explodes()
func _on_timer_timeout():
get_tree().change_scene_to_packed(EXPLOSION)
And the global script is this:
extends Node
@onready var timer: Timer = $Timer
My two globals are named different things. Do I not understand how globals work? What is going wrong? The reason I ask is because this error seems to be related to the timer script because it did not happen before writing that script.
For some reason the Global script had no path. I do not know why, but now the game runs. Albeit, there are some other issues. I will get back with these issues shortly, for now I am out of the house for a couple hours, but I will debug when I get back. One of the issues however is this: Cannot call method ‘start’ on a null value. That only started after instentiating the timer in my level scene