MagicNStuff/source/components/general/time/timescalable_timer.gd
2025-02-25 22:07:11 +01:00

127 lines
4.0 KiB
GDScript

@icon("res://components/ui/hud/timer/stopwatch.svg")
class_name TimescalableTimer
extends Node
## A timescalable-countdown timer.
##
## The [b]Timer[/b] node is a countdown timer and is the simplest way to handle time-based logic in the engine.
## When a timer reaches the end of its [member wait_time], it will emit the [signal timeout] signal.[br][br]
## After a timer enters the tree, it can be manually started with [method start].
## A timer node is also started automatically if [member autostart] is [code]true[/code].[br][br]
## Without requiring much code, a timer node can be added and configured in the editor.
## The [signal timeout] signal it emits can also be connected through the Node dock in the editor:
##
## [codeblock]
## func _on_timer_timeout():
## print("Time to attack!")
## [/codeblock]
## [b]Note:[/b] To create a one-shot timer without instantiating a node, use [method SceneTree.create_timer].[br][br]
## [b]Note:[/b] Timers are affected by [member Engine.time_scale].
## The higher the time scale, the sooner timers will end.
## How often a timer processes may depend on the framerate or [member Engine.physics_ticks_per_second].
## Emitted when the timer reaches the end.
signal timeout
## See documentation for [param process_callback] in [Timer]
@export var process_callback: Timer.TimerProcessCallback
## The time required for the timer to end, in seconds. This property can also be set every time [member start] is called.
##
## [b]Note[/b]: Timers can only process once per physics or process frame (depending on the [member process_callback]).
## An unstable framerate may cause the timer to end inconsistently,
## which is especially noticeable if the wait time is lower than roughly [code]0.05[/code] seconds.
## For very short timers, it is recommended to write your own code instead of using a [Timer] node.
## Timers are also affected by [Engine.time_scale].
@export_range(0.001, 4096.0, 0.001, "suffix:s") var wait_time: float = 1.0: get = get_wait_time, set = set_wait_time
## The maximum allowed elapsed time we can have.[br]If this is under [code]0[/code]
## we don't have any limit and we count towards infinity.
@export var one_shot: bool = false
## If [code]true[/code], the stopwatch will call [method start] when entering the scene tree.
@export var autostart: bool = false
## Manipulates, how fast or slow the timer will count down.
@export_range(-10.0, 10.0, 0.01, "or_greater", "or_less") var time_scale: float = 1.0
var time_left: float = -1.0: get = get_time_left
var paused: bool = false: set = set_paused, get = is_paused
var _stopped: bool = true
func _ready() -> void:
if autostart:
start()
func _process(delta: float) -> void:
if process_callback == Timer.TIMER_PROCESS_IDLE:
_process_timer(delta)
func _physics_process(delta: float) -> void:
if process_callback == Timer.TIMER_PROCESS_PHYSICS:
_process_timer(delta)
func _process_timer(delta: float) -> void:
if is_stopped() or is_paused():
return
time_left = maxf(time_left - delta * time_scale, 0.0)
if time_left == 0.0:
timeout.emit()
if one_shot:
stop()
else:
time_left += wait_time
#region Starting/Stopping
## Starts the stopwatch. [param custom_start_time] will set the elapsed time to it instead of
## using [param start_time].
func start(time_sec: float = -1.0) -> void:
if time_sec >= 0.0:
wait_time = time_sec
time_left = wait_time
_stopped = false
paused = false
## Stops the stopwatch.
func stop() -> float:
var final_time: float = time_left
time_left = -1.0
_stopped = true
return final_time
#endregion
func get_wait_time() -> float:
return wait_time
func set_wait_time(value: float) -> void:
wait_time = value
## Returns the elapsed time since this stopwatch was started.
func get_time_left() -> float:
return time_left if not is_stopped() else 0.0
## Returns [code]true[/code] if the timer is stopped or has not started.
func is_stopped() -> bool:
return _stopped
func set_paused(value: bool) -> void:
paused = value
func is_paused() -> bool:
return paused