Skip to content

Instantly share code, notes, and snippets.

@cgbeutler
Last active April 7, 2020 21:46
Show Gist options
  • Save cgbeutler/e996652e5b28612d538be3eb941d47f3 to your computer and use it in GitHub Desktop.
Save cgbeutler/e996652e5b28612d538be3eb941d47f3 to your computer and use it in GitHub Desktop.
# Singleton Time
extends Node
##
# Set this class as a singleton in Godot named Time or similar.
# Setting it near the top will ensure it is processed before
# everything else, giving you consistent values for all nodes
# that use this class.
# this class has a global process and physics process count
# that is very useful when doing things less often.
# A wrapper has provided to make that even quicker:
# eg: if Time.process_every(5): do_thing_only_every_5_frames()
# There are two main timing objects: Stopwatch and TickTimer
# Stopwatches will increment at the beginning of the update
# frame and can be started, stopped and reset. It's value is
# a float of seconds since it was started.
# TickTag is a way of marking update frames. Useful for
# buffering values. Use tag_now() to update it's value, then
# current() or within(x) to check if the value is current or
# recent.
##
const TICK_MIN := -9223372036854775808 # int min
const TICK_MAX := 9223372036854775807 # int max
const TICK_START := TICK_MIN + 1000 # start global values 1000 more than tick tag values
var process :int = TICK_START
var physics_process :int = TICK_START
var process_stopwatches := []
var physics_process_stopwatches := []
var global_scale := 1.0
func process_every( frames :int ):
return not process % frames
func physics_process_every( frames :int ):
return not physics_process % frames
func create_process_tick_tag() -> ProcessTickTag:
return ProcessTickTag.new(self)
func create_physics_process_tick_tag() -> PhysicsProcessTickTag:
return PhysicsProcessTickTag.new(self)
func create_process_stopwatch() -> Stopwatch:
var sw = Stopwatch.new()
process_stopwatches.append(weakref(sw))
return sw
func create_physics_process_stopwatch() -> Stopwatch:
var sw = Stopwatch.new()
physics_process_stopwatches.append(weakref(sw))
return sw
func _process( delta ):
process += 1
var stopwatches_to_remove = []
for i in range( process_stopwatches.size() ):
var stopwatch :Stopwatch = process_stopwatches[i].get_ref()
if stopwatch == null:
stopwatches_to_remove.append( i )
elif stopwatch.running:
stopwatch.update( delta )
if len(stopwatches_to_remove) > 0:
stopwatches_to_remove.invert()
for i in stopwatches_to_remove:
process_stopwatches.remove( i )
func _physics_process( delta ):
physics_process += 1
var stopwatches_to_remove = []
for i in range( physics_process_stopwatches.size() ):
var stopwatch :Stopwatch = physics_process_stopwatches[i].get_ref()
if stopwatch == null:
stopwatches_to_remove.append( i )
elif stopwatch.running:
stopwatch.update( delta )
if len(stopwatches_to_remove) > 0:
for i in stopwatches_to_remove.invert():
physics_process_stopwatches.remove( i )
class Stopwatch:
var value :float = INF # Start maxed out, so no user things trigger without their say.
var running :bool = true
func reset( new_value :float = 0.0 ):
value = new_value
func stop():
running = false
func resume():
running = true
func update( delta :float ):
value += delta
class ProcessTickTag:
var value = TICK_MIN
var _time
func _init( time ):
_time = time
func tag_now():
self.value = _time.process
func current() -> bool:
return self.value == _time.process
func within( frames : int ):
return (_time.process - self.value) <= frames
class PhysicsProcessTickTag:
var value = TICK_MIN
var _time
func _init( time ):
_time = time
func tag_now():
self.value = _time.physics_process
func current() -> bool:
return self.value == _time.physics_process
func within( frames : int ):
return (_time.physics_process - self.value) <= frames
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment