feat: add sparse circus lights to circus sign on landing (max 4-5 at a time)
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
shader_type canvas_item;
|
||||
// Shader per l'insegna centrale UPENDI CIRCUS:
|
||||
// Lucine colorate lungo la cornice del pannello che si accendono in modo rado e casuale
|
||||
// solo dopo che l'insegna ha finito di atterrare e rimbalzare (sign_lights_active = 1.0).
|
||||
|
||||
uniform float sign_lights_active : hint_range(0.0, 1.0) = 0.0;
|
||||
uniform float blink_speed : hint_range(0.5, 8.0) = 2.2;
|
||||
|
||||
// 37 posizioni lampadina distribuite lungo il contorno in legno dell'insegna (UV su canvas 880x561)
|
||||
const vec2 sign_bulbs[37] = vec2[37](
|
||||
// Arco superiore
|
||||
vec2(0.2107, 0.3839), vec2(0.2590, 0.3851), vec2(0.3223, 0.3828), vec2(0.3725, 0.3774),
|
||||
vec2(0.4209, 0.3707), vec2(0.4946, 0.3551), vec2(0.5700, 0.3261), vec2(0.6281, 0.3031),
|
||||
vec2(0.6769, 0.2784), vec2(0.7503, 0.2651), vec2(0.7999, 0.2504), vec2(0.8620, 0.2458),
|
||||
// Bordo destro
|
||||
vec2(0.8565, 0.3564), vec2(0.8585, 0.4328), vec2(0.8579, 0.5043), vec2(0.8628, 0.5807),
|
||||
vec2(0.8640, 0.6594), vec2(0.8703, 0.7179), vec2(0.8680, 0.7879),
|
||||
// Arco inferiore
|
||||
vec2(0.8264, 0.8164), vec2(0.7829, 0.8452), vec2(0.7112, 0.8651), vec2(0.6513, 0.8823),
|
||||
vec2(0.5675, 0.8988), vec2(0.5082, 0.9059), vec2(0.4341, 0.9007), vec2(0.3600, 0.8980),
|
||||
vec2(0.3098, 0.8763), vec2(0.2447, 0.8536), vec2(0.1897, 0.8309), vec2(0.1363, 0.7941),
|
||||
// Bordo sinistro
|
||||
vec2(0.1328, 0.6995), vec2(0.1297, 0.6286), vec2(0.1256, 0.5398), vec2(0.1239, 0.4893),
|
||||
vec2(0.1221, 0.4318), vec2(0.1208, 0.3685)
|
||||
);
|
||||
|
||||
// Palette di colori circensi vivaci
|
||||
vec3 get_bulb_color(int idx) {
|
||||
int c = idx % 6;
|
||||
if (c == 0) return vec3(1.0, 0.25, 0.25); // Rosso rubino
|
||||
if (c == 1) return vec3(1.0, 0.84, 0.15); // Giallo oro
|
||||
if (c == 2) return vec3(0.25, 0.88, 0.40); // Verde smeraldo
|
||||
if (c == 3) return vec3(0.25, 0.70, 1.00); // Blu ciano
|
||||
if (c == 4) return vec3(0.95, 0.38, 0.90); // Magenta fucsia
|
||||
return vec3(1.0, 0.55, 0.15); // Arancio caldo
|
||||
}
|
||||
|
||||
// Generatore pseudo-casuale deterministico per lampadina e tempo
|
||||
float pseudo_rand(float n) {
|
||||
return fract(sin(n) * 43758.5453123);
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec4 color = texture(TEXTURE, UV);
|
||||
|
||||
if (sign_lights_active > 0.001) {
|
||||
vec2 px = UV * vec2(880.0, 561.0);
|
||||
|
||||
// Calcolo delle 5 lampadine attive nei 5 settori della cornice
|
||||
// Durate leggermente sfalsate per evitare che si sincronizzino
|
||||
const float durations[5] = float[5](1.3, 1.6, 1.9, 1.5, 2.1);
|
||||
const int ranges_start[5] = int[5](0, 7, 15, 22, 30);
|
||||
const int ranges_count[5] = int[5](7, 8, 7, 8, 7);
|
||||
|
||||
for (int c = 0; c < 5; c++) {
|
||||
float dur = durations[c] / (blink_speed / 2.2);
|
||||
float step = floor(TIME / dur);
|
||||
float sub_t = fract(TIME / dur);
|
||||
// Campana morbida di accensione (fade-in -> picco -> fade-out)
|
||||
float lit = sin(sub_t * 3.14159265);
|
||||
|
||||
if (lit <= 0.15) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Indice lampadina estratta pseudo-casualmente per questo settore e questo ciclo
|
||||
float r_val = pseudo_rand(step * 17.13 + float(c) * 31.7);
|
||||
int chosen_bulb = ranges_start[c] + int(floor(r_val * float(ranges_count[c])));
|
||||
chosen_bulb = clamp(chosen_bulb, 0, 36);
|
||||
|
||||
vec2 delta = px - sign_bulbs[chosen_bulb] * vec2(880.0, 561.0);
|
||||
float r = length(delta);
|
||||
|
||||
// Nucleo piccolo e brillante ~5px + alone diffuso ~12px
|
||||
float core = 1.0 - smoothstep(2.0, 6.0, r);
|
||||
float halo = exp(-r / 7.5);
|
||||
float intensity = lit * sign_lights_active;
|
||||
vec3 bulb_col = get_bulb_color(chosen_bulb);
|
||||
|
||||
// Colorazione del nucleo e alone additivo
|
||||
color.rgb = mix(color.rgb, bulb_col, core * intensity);
|
||||
color.rgb += bulb_col * (halo * 0.75 * intensity * (1.0 - core));
|
||||
color.a = max(color.a, halo * 0.5 * intensity);
|
||||
}
|
||||
}
|
||||
|
||||
color.rgb = min(color.rgb, vec3(1.0));
|
||||
COLOR = color;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ const DISPLAY_FONT := preload("res://shared/assets/fonts/NotoSerifDisplay-Conden
|
||||
const MENU_SHADER := preload("res://menus/assets/shaders/ambient_drift.gdshader")
|
||||
const TENT_STAR_SHADER := preload("res://menus/assets/shaders/tent_star_glow.gdshader")
|
||||
const TENT_LIGHTS_SHADER := preload("res://menus/assets/shaders/tent_lights.gdshader")
|
||||
const SIGN_LIGHTS_SHADER := preload("res://menus/assets/shaders/circus_sign_lights.gdshader")
|
||||
|
||||
# Posizione e ingombro condivisi della freccia indietro in tutte le schermate.
|
||||
const BACK_BUTTON_CENTER := Vector2(0.12, 0.14)
|
||||
@@ -52,6 +53,13 @@ static func tent_material(garland_strength := 0.0) -> ShaderMaterial:
|
||||
return material
|
||||
|
||||
|
||||
static func sign_lights_material() -> ShaderMaterial:
|
||||
var material := ShaderMaterial.new()
|
||||
material.shader = SIGN_LIGHTS_SHADER
|
||||
material.set_shader_parameter("sign_lights_active", 0.0)
|
||||
return material
|
||||
|
||||
|
||||
static func add_image(parent: Control, texture: Texture2D, center: Vector2, normalized_size: Vector2, material: Material = null) -> TextureRect:
|
||||
var image := TextureRect.new()
|
||||
image.texture = texture
|
||||
|
||||
@@ -341,6 +341,8 @@ func _add_sign() -> void:
|
||||
|
||||
_add_sign_layer(rig, CIRCUS_SIGN_ROPES)
|
||||
var panel := _add_sign_layer(rig, CIRCUS_SIGN_PANEL)
|
||||
var sign_mat := MenuUI.sign_lights_material()
|
||||
panel.material = sign_mat
|
||||
var final_y := panel.position.y
|
||||
panel.position.y = final_y - panel.size.y * 1.15
|
||||
|
||||
@@ -353,7 +355,13 @@ func _add_sign() -> void:
|
||||
# L'impatto è sincronizzato con la massima estensione, prima del ritorno elastico.
|
||||
tween.tween_callback(func(): sign_landed.emit())
|
||||
tween.tween_property(panel, "position:y", final_y, 0.50).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
|
||||
tween.tween_callback(func(): sign_bounced.emit())
|
||||
tween.tween_callback(func():
|
||||
sign_bounced.emit()
|
||||
# Attiva le lucine colorate dell'insegna con una dolce dissolvenza solo a fine animazione
|
||||
var lights_tween := create_tween()
|
||||
lights_tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
|
||||
lights_tween.tween_method(func(val: float): sign_mat.set_shader_parameter("sign_lights_active", val), 0.0, 1.0, 0.6).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
|
||||
)
|
||||
|
||||
|
||||
func _add_sign_layer(parent: Control, texture: Texture2D) -> TextureRect:
|
||||
|
||||
Reference in New Issue
Block a user