Created
January 27, 2026 13:18
-
-
Save xsellier/90502efd761c22991bce2248f8d4f412 to your computer and use it in GitHub Desktop.
ControlAnimator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @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