Skip to content

Instantly share code, notes, and snippets.

@xsellier
Created January 27, 2026 13:18
Show Gist options
  • Select an option

  • Save xsellier/90502efd761c22991bce2248f8d4f412 to your computer and use it in GitHub Desktop.

Select an option

Save xsellier/90502efd761c22991bce2248f8d4f412 to your computer and use it in GitHub Desktop.
ControlAnimator
@tool
class_name ControlAnimator
extends Node
@export var visible_animated := false :
set = set_visible_animated,
get = get_visible_animated
@export_range(0.01, 10.0, 0.01) var animation_duration := 0.66
@export var animation_direction := ANIMATION_DIRECTION_ENUM.FROM_BOTTOM
@export var node_path : NodePath = '..'
@export var container_path : NodePath
enum ANIMATION_DIRECTION_ENUM {
FROM_TOP,
FROM_RIGHT,
FROM_LEFT,
FROM_BOTTOM
}
var node_list_to_animate = []
var __delta_acc = 0.0
func _ready():
if node_path == null:
return
node_list_to_animate = []
node_list_to_animate.push_back(get_node(node_path))
for child_node in get_node(container_path).get_children():
node_list_to_animate.push_back(child_node)
visible_animated = node_list_to_animate[0].visible
set_process(false)
func set_visible_animated(value):
if visible_animated != value:
visible_animated = value
_queue_animation()
func get_visible_animated():
return visible_animated
func _queue_animation():
__delta_acc = 0.0
_initialize_animation()
set_process(true)
func _initialize_animation():
for node_to_animate in node_list_to_animate:
if not node_to_animate.visible:
match animation_direction:
ANIMATION_DIRECTION_ENUM.FROM_TOP, ANIMATION_DIRECTION_ENUM.FROM_BOTTOM:
node_to_animate.scale = Vector2(1.0, 0.0)
ANIMATION_DIRECTION_ENUM.FROM_RIGHT, ANIMATION_DIRECTION_ENUM.FROM_LEFT:
node_to_animate.scale = Vector2(0.0, 1.0)
match animation_direction:
ANIMATION_DIRECTION_ENUM.FROM_TOP:
node_to_animate.pivot_offset = node_to_animate.get_size() * Vector2(0.5, 0.0)
ANIMATION_DIRECTION_ENUM.FROM_RIGHT:
node_to_animate.pivot_offset = node_to_animate.get_size() * Vector2(1.0, 0.5)
ANIMATION_DIRECTION_ENUM.FROM_LEFT:
node_to_animate.pivot_offset = node_to_animate.get_size() * Vector2(0.0, 0.5)
ANIMATION_DIRECTION_ENUM.FROM_BOTTOM:
node_to_animate.pivot_offset = node_to_animate.get_size() * Vector2(0.5, 1.0)
node_to_animate.visible = true
node_to_animate.set_meta('from_scale', node_to_animate.get_scale())
node_to_animate.set_meta('from_alpha', node_to_animate.modulate.a)
if visible_animated:
node_to_animate.set_meta('to_scale', Vector2.ONE)
node_to_animate.set_meta('to_alpha', 1.0)
else:
node_to_animate.set_meta('to_alpha', 0.0)
match animation_direction:
ANIMATION_DIRECTION_ENUM.FROM_TOP, ANIMATION_DIRECTION_ENUM.FROM_BOTTOM:
node_to_animate.set_meta('to_scale', Vector2(1.0, 0.0))
ANIMATION_DIRECTION_ENUM.FROM_RIGHT, ANIMATION_DIRECTION_ENUM.FROM_LEFT:
node_to_animate.set_meta('to_scale', Vector2(0.0, 1.0))
func _process(delta):
__delta_acc += delta
_update_animation()
func _update_animation():
var animation_progress = __delta_acc / animation_duration
if animation_progress < 1.334:
var index_total := float(node_list_to_animate.size() * max(animation_duration, 3.0))
var index = 0
for node_to_animate in node_list_to_animate:
var animation_index = max(__delta_acc - index / index_total, 0.0) / animation_duration
var animation_bounce_back_easing = _ease_out_back(animation_index)
var animation_easing = ease(animation_index, 0.25)
node_to_animate.scale = lerp(node_to_animate.get_meta('from_scale'), node_to_animate.get_meta('to_scale'), animation_bounce_back_easing)
node_to_animate.modulate.a = lerp(node_to_animate.get_meta('from_alpha'), node_to_animate.get_meta('to_alpha'), animation_easing)
index += 1
else:
_finalize_animation()
func _finalize_animation():
for node_to_animate in node_list_to_animate:
node_to_animate.visible = visible_animated
set_process(false)
##########################
# Utility functions
func _ease_out_back(value):
var clamped_value = clamp(value, 0.0, 1)
return 1 + 2.70158 * pow(clamped_value - 1, 3) + 1.70158 * pow(clamped_value - 1, 2)
func _ease_out_bounce(value):
var clamped_value = clamp(value, 0.0, 1)
return 1 - pow(2.71828, (-6 * clamped_value)) * abs(cos(clamped_value * PI * 4))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment