Skip to content

Instantly share code, notes, and snippets.

@xsellier
Last active December 9, 2024 13:01
Show Gist options
  • Save xsellier/47a98354fa3392eb34da7142670e6490 to your computer and use it in GitHub Desktop.
Save xsellier/47a98354fa3392eb34da7142670e6490 to your computer and use it in GitHub Desktop.
Transition effect
@tool
extends CanvasLayer
const TRANSITION_ANIMATION_DURATION = 1.0
const TRANSITION_ANIMATION_FONT_DURATION = 0.66
const TRANSITION_TYPE_LIST = [{
index = 0,
trans = Tween.TRANS_QUAD
}, {
index = 1,
trans = Tween.TRANS_BOUNCE
}]
enum TRANSITION_STATE_ENUM {
READY_STATE = 0,
SHOWING_STATE = 1,
SHOWN_STATE = 2,
HIDDING_STATE = 3
}
const LOADING_TEXT_FORMAT = 'LABEL_LOADING_%d'
const LOADING_TEXT_MAX_INDEX = 50
@onready var transition_material = $transition.get_material()
@onready var loading_label = $transition/loading
@export var __current_state : TRANSITION_STATE_ENUM = TRANSITION_STATE_ENUM.READY_STATE :
set = set_transition_state
# On a commencé a transitionné
signal transition_started()
# La demande de transition est faite, on peut directement charger et placer la scène dans l'arbre de scène
# On peut supprimer l'autre scène de l'arbre
signal transition_screen_shown()
# La transition est terminée
signal transition_finished()
var __tween = null
func start_transition():
__current_state = TRANSITION_STATE_ENUM.SHOWING_STATE
func continue_transition():
__current_state = TRANSITION_STATE_ENUM.HIDDING_STATE
func set_transition_state(value):
var accept_transition = false
var signal_to_emit = null
if __tween != null:
__tween.stop()
__tween.kill()
match __current_state:
TRANSITION_STATE_ENUM.READY_STATE:
accept_transition = value == TRANSITION_STATE_ENUM.SHOWING_STATE
signal_to_emit = 'transition_started'
loading_label.text = LOADING_TEXT_FORMAT % [
randi_range(1, LOADING_TEXT_MAX_INDEX)
]
$transition.visible = true
__tween = create_tween().set_parallel(true).set_ease(Tween.EASE_OUT).set_trans(_pick_random_transition())
# set_shader_parameter
__tween.tween_method(_set_shader_progress, 0.0, 0.5, TRANSITION_ANIMATION_DURATION)
__tween.chain().tween_property(loading_label, 'self_modulate', ColorManager.WHITE_COLOR, TRANSITION_ANIMATION_FONT_DURATION)
__tween.chain().tween_callback(set_transition_state_with_delay.bind(TRANSITION_STATE_ENUM.SHOWN_STATE))
__tween.play()
TRANSITION_STATE_ENUM.SHOWING_STATE:
accept_transition = value == TRANSITION_STATE_ENUM.SHOWN_STATE
signal_to_emit = 'transition_screen_shown'
TRANSITION_STATE_ENUM.SHOWN_STATE:
accept_transition = value == TRANSITION_STATE_ENUM.HIDDING_STATE
__tween = create_tween().set_parallel(true).set_ease(Tween.EASE_OUT).set_trans(_pick_random_transition())
# set_shader_parameter
__tween.tween_property(loading_label, 'self_modulate', ColorManager.PURE_WHITE_COLOR_TRANSPARENT, TRANSITION_ANIMATION_FONT_DURATION)
__tween.chain().tween_method(_set_shader_progress, 0.5, 1.0, TRANSITION_ANIMATION_DURATION)
__tween.chain().tween_callback(set_transition_state_with_delay.bind(TRANSITION_STATE_ENUM.READY_STATE))
__tween.play()
TRANSITION_STATE_ENUM.HIDDING_STATE:
accept_transition = value == TRANSITION_STATE_ENUM.READY_STATE
signal_to_emit = 'transition_finished'
$transition.visible = false
if accept_transition:
__current_state = value
if signal_to_emit != null:
emit_signal(signal_to_emit)
func set_transition_state_with_delay(value, delay = 0.1):
get_tree().create_timer(delay).connect('timeout', set_transition_state.bind(value))
func _set_shader_progress(value):
transition_material.set_shader_parameter('progress', value)
func _pick_random_transition():
var transition_type = TRANSITION_TYPE_LIST.pick_random()
transition_material.set_shader_parameter('transition_type', transition_type.index)
return transition_type.trans
shader_type canvas_item;
uniform int transition_type : hint_range(0, 1) = 0;
uniform vec4 transition_color_top : source_color;
uniform vec4 transition_color_bottom : source_color;
uniform vec2 circle_size = vec2(16.0, 16.0);
uniform float progress : hint_range(0.0, 1.0) = 0.0;
uniform float rotation : hint_range(-3.14, 3.14);
mat2 rotate(float angle) {
return mat2(vec2(cos(angle), -sin(angle)), vec2(sin(angle), cos(angle)));
}
void vertex() {
// Called for every vertex the material is visible on.
}
vec4 circle_transition(vec2 fragCoord, vec2 screenPixelSize, vec2 uv) {
mat2 rotationMatrix = rotate(rotation);
vec2 screen_ratio = (1.0 / screenPixelSize) / circle_size;
vec2 computed_uv = uv * screen_ratio * rotationMatrix;
vec2 uv_floor = floor(computed_uv);
vec2 uv_fract = fract(computed_uv);
vec2 center = uv_fract * 2.0 - 1.0;
float circle = 0.0;
if (progress < 0.5) {
float wave = uv_floor.x / (screen_ratio.x) - (progress * 2.0 * -2.6 + 1.0);
circle = 1.0 - step(wave, length(center));
} else {
float wave = uv_floor.x / (screen_ratio.x) - ((progress - 0.5) * 2.0 * -2.6 + 1.0);
circle = step(wave, length(center));
}
return vec4(circle) * mix(transition_color_top, transition_color_bottom, uv.y);
}
vec4 clap_transition(vec2 fragCoord, vec2 screenPixelSize, vec2 uv) {
mat2 rotationMatrix = rotate(rotation);
vec2 screen_center = vec2(0.5) * screenPixelSize.x / screenPixelSize.y;
vec2 computed_uv = (uv * rotationMatrix + vec2(0.33)) / 2.0;
vec4 compute_color = vec4(0.0, 0.0, 0.0, 0.0);
if (progress < 0.5) {
if ((computed_uv.y < progress) || (computed_uv.y > 0.5 && (1.0 - computed_uv.y) < progress)) {
compute_color.a = 1.0;
}
} else {
float computed_progress = abs(progress - 1.0);
if ((computed_uv.y < computed_progress) || (computed_uv.y > 0.5 && (1.0 - computed_uv.y) < computed_progress)) {
compute_color.a = 1.0;
}
}
return compute_color;
}
void fragment() {
switch (transition_type) {
case 0:
COLOR = circle_transition(FRAGCOORD.xy, SCREEN_PIXEL_SIZE, UV);
break;
case 1:
COLOR = clap_transition(FRAGCOORD.xy, SCREEN_PIXEL_SIZE, UV);
break;
}
}
[gd_scene load_steps=4 format=3]
[ext_resource type="Script" path="res://script/singleton/transition.gd" id="1_q7ulk"]
[ext_resource type="Shader" path="res://shader/transition.gdshader" id="2_peo10"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_oepvc"]
shader = ExtResource("2_peo10")
shader_parameter/transition_type = 0
shader_parameter/transition_color_top = null
shader_parameter/transition_color_bottom = Color(0, 0, 0, 1)
shader_parameter/circle_size = Vector2(96, 96)
shader_parameter/progress = 1.0
shader_parameter/rotation = 0.504
[node name="main" type="CanvasLayer"]
layer = 4
script = ExtResource("1_q7ulk")
[node name="transition" type="ColorRect" parent="."]
visible = false
material = SubResource("ShaderMaterial_oepvc")
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(1, 1, 1, 0)
metadata/_edit_use_anchors_ = true
[node name="loading" type="Label" parent="transition"]
self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(1024, 1024)
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -0.5
offset_top = -117.0
offset_right = 0.5
offset_bottom = 117.0
grow_horizontal = 2
grow_vertical = 2
theme_type_variation = &"TooltipLabel"
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_font_sizes/font_size = 72
text = "LABEL_LOADING_9"
horizontal_alignment = 1
vertical_alignment = 1
autowrap_mode = 3
uppercase = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment