A quiet fireplace to build around.

~

Experimentation, mechanics and stories.

~

Main account: @Sunfire

I mostly share devlog posts from there at the moment, but game releases and other announcements like that will be posted here first.


sunfire
@sunfire

slowly easing into this project, thought up an idea for a generalized "cooldown" class for godot 4.

A generic custom class, acting as a wrapper around a SceneTreeTimer (or maybe keeping track itself if that makes sense), with a handful of attributes:

  • cooldown_time, the value that it resets to after each activation
  • activation_requires, a function reference to be checked whenever it finishes in order to see if it can activate and reset, and
  • activation_function, another function reference that is called upon the cooldown reaching zero if requirements are met.

There would also be room to add some optional parameters like timescale and a toggle to continue timing when the scene tree is paused.
The activation callback could be replaced with a signal in order to keep things a bit more decoupled, but i'm not sure if the same can be said of the activation requirements function due to how this implementation of the overall concept works.

Usage would involve setting up the main attributes once, optionally randomizing the starting cooldown, and then simply letting it run in the background. At the end of the cooldown period, the object would automatically start checking its requirements and call the activation function as soon as they are met. Kind of like a reusable timer with extra steps.

For automated uses like enemy attacks and other objects, the requirement function would simply be "can this activate?", whereas for a player character you'd additionally hook it up to player inputs so that it will immediately fire only when pressing the right button.


sunfire
@sunfire

I've disentangled the original manual timing method and implemented this cooldown timer class.
I ended up inheriting the Timer class so that i can use its built-in functions, since the SceneTreeTimer is extremely lightweight and quite limiting for anything beyond a very simple timer.

Code below for those interested:


class_name CooldownTimer
extends Timer

#main parameters
var cooldown_time:float = 1
var activation_requires:Callable = func():return true
var activation_function:Callable = func():pass

#state parameters
var pause_when_cannot_activate:bool = false
var randomize_first_time:bool = false

func _ready():
	#make sure the timer doesn't cycle endlessly on its own
	one_shot = true
	#pause status
	set_pause_status()
	#start timing
	if randomize_first_time:
		start(randf_range(0,cooldown_time))
	else:
		start(cooldown_time)

func _process(_delta):
	#pause status
	set_pause_status()
	#activation
	if time_left <= 0:
		if activation_requires.call():
			activation_function.call()
			start(cooldown_time)
			

func set_pause_status():
	#pause when unable to activate, if that parameter is set
	#otherwise timer can be paused manually if desired
	if !pause_when_cannot_activate: return
	paused = !activation_requires.call()
syntax highlighting by codehost

To set it up, create the node and add it to the scene tree from another script, and pass in Callable references for the two activation functions, as well as setting the cooldown time and other parameters as needed.

In practice, there are likely many simple cases where just using a normal Timer node on repeat would serve the same purpose, but this implementation feels more flexible for my particular use case, and i figure it's something of interest to share for anyone else.

I may update it to use a signal for activation instead, if i do i'll edit this post with the new code.

One thing to keep in mind:
As the activation_requires function is called every frame, sometimes more than once, you'll want to keep it lightweight when possible. Caching precalculated values and passing in a getter would likely be a good way to do this.


You must log in to comment.