Skip to content

Instantly share code, notes, and snippets.

@etodd
Created June 15, 2026 16:33
Show Gist options
  • Select an option

  • Save etodd/3fbc8224005b9e6dd8b8a2aed3efdf01 to your computer and use it in GitHub Desktop.

Select an option

Save etodd/3fbc8224005b9e6dd8b8a2aed3efdf01 to your computer and use it in GitHub Desktop.
My GDScript utility functions
class_name Util
extends Node
## Call this function every frame to move the given value toward the target in
## a smooth, springy, FRAMERATE INDEPENDENT way, such that it will take
## "duration" to reach within 1% of the target.
##
## Credit: https://x.com/FreyaHolmer/status/1757836988495847568
static func smooth_toward(current: float, target: float, duration: float, delta: float) -> float:
return lerpf(current, target, 1.0 - pow(0.01, delta / duration))
## Show or hide the given CanvasItem with a nice fade. The animation can be
## interrupted by another show_with_fade call and it will do the right thing.
static func show_with_fade(control: CanvasItem, show: bool = true, duration: float = 0.25) -> void:
var existing: Variant = control.get_meta("show_with_fade_tween", false)
var existing_tween: Tween = existing as Tween if existing else null
var tweening: bool = existing_tween and existing_tween.is_running()
if tweening:
var tweening_target: bool = existing_tween.get_meta("target", false)
if tweening_target == show:
# already tweening toward desired state
return
existing_tween.kill()
if (not tweening) and (control.visible && control.modulate.a == 1.0) == show:
# already desired state
return
control.visible = true
var tween: Tween = control.create_tween()
control.set_meta("show_with_fade_tween", tween)
tween.set_meta("target", show)
if show:
control.modulate = Color.TRANSPARENT
tween.tween_property(control, "modulate", Color.WHITE, duration)
else:
tween.tween_property(control, "modulate", Color.TRANSPARENT, duration)
tween.tween_callback(control.hide)
await tween.finished
## Await this function to load a resource asynchronously.
static func load_async(requester: Node,
path: String,
type_hint: String = "",
use_sub_threads: bool = false,
cache_mode: ResourceLoader.CacheMode = ResourceLoader.CACHE_MODE_REUSE
) -> Resource:
ResourceLoader.load_threaded_request(path, type_hint, use_sub_threads, cache_mode)
while ResourceLoader.load_threaded_get_status(path) == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
await requester.get_tree().process_frame
return ResourceLoader.load_threaded_get(path)
## Await this function to wait until the given function returns true.
static func wait(node: Node, f: Callable) -> void:
var tree: SceneTree = node.get_tree()
while not f.call():
await tree.process_frame
## Clamp a value in the range [-1, 1] to 0 if it is within the given dead zone.
static func dead_zone(x: float, zone: float) -> float:
if x < -zone:
return (x + zone) / (1.0 - zone)
elif x > zone:
return (x - zone) / (1.0 - zone)
else:
return 0.0
## Return the angle x plus or minus some multiple of PI*2 so that it is the
## closest possible to angle y.
static func closest_angle(x: float, y: float) -> float:
var result: float = x
while result > y + PI:
result -= PI * 2.0
while result < y - PI:
result += PI * 2.0
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment