127 lines
4.0 KiB
GDScript
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
|