feat(particles): bubble trail behind dolphin + block break burst

- BubbleTrail.gd: GPUParticles3D, auto-configured in _ready, set_intensity() API
- BlockBreakParticles.gd: one_shot burst, emit_burst(pos, color) API
- DolphinController.gd: bubble_trail onready + speed_factor hook in _update_movement
- Dolphin.tscn: BubbleEmitterPoint (0,0,1.2) > BubbleTrail child added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Floppyrj45
2026-04-19 18:09:21 +02:00
parent cafdb7d27e
commit a8341355e3
12 changed files with 318 additions and 58 deletions

View File

@@ -1,21 +1,33 @@
shader_type spatial;
render_mode unshaded, blend_add, cull_disabled, depth_draw_never;
render_mode unshaded, blend_add, depth_draw_never, cull_disabled;
uniform float speed : hint_range(0.1, 3.0) = 0.8;
uniform float scale : hint_range(1.0, 20.0) = 8.0;
uniform float intensity : hint_range(0.0, 2.0) = 0.6;
uniform vec3 caustic_color : source_color = vec3(0.7, 0.9, 1.0);
uniform vec3 caustic_color : source_color = vec3(0.5, 0.8, 1.0);
uniform float intensity : hint_range(0, 3) = 1.5;
uniform float scale = 8.0;
uniform float speed = 0.5;
float caustic_pattern(vec2 uv) {
float t = TIME * speed;
vec2 p = uv * scale;
float c = 0.0;
c += sin(p.x + t) * 0.5;
c += cos(p.y + t * 0.7) * 0.5;
c += sin(p.x * 0.7 + p.y * 0.5 + t * 1.3) * 0.3;
c = abs(c);
c = smoothstep(0.2, 0.0, c);
return c;
}
void fragment() {
vec2 uv = UV * scale;
vec2 uv = UV * 2.0 - 1.0;
float c1 = caustic_pattern(uv);
float c2 = caustic_pattern(uv * 1.3 + vec2(0.5, 0.3));
float caustics = (c1 + c2 * 0.5) * intensity;
float pattern1 = sin(TIME * speed + uv.x * 10.0 + sin(uv.y * 10.0 + TIME * speed));
float pattern2 = sin(TIME * speed * 0.7 + uv.y * 12.0 + sin(uv.x * 8.0 + TIME * speed * 1.3));
float pattern3 = sin(TIME * speed * 1.1 + (uv.x + uv.y) * 7.0 + sin(uv.x * 5.0 - TIME * speed * 0.5));
// Fade avec profondeur
float depth_fade = clamp((VERTEX.y + 60.0) / 80.0, 0.0, 1.0);
caustics *= depth_fade;
float caustic = (pattern1 + pattern2 + pattern3) / 3.0;
caustic = pow(max(caustic, 0.0), 2.0) * intensity;
EMISSION = caustic_color * caustic;
ALBEDO = vec3(0.0);
ALBEDO = caustic_color * caustics;
ALPHA = caustics;
}

View File

@@ -1,20 +1,25 @@
shader_type canvas_item;
render_mode blend_add;
shader_type spatial;
render_mode unshaded, blend_add, depth_draw_never, cull_disabled;
uniform float ray_count : hint_range(5.0, 40.0) = 20.0;
uniform float speed : hint_range(0.1, 2.0) = 0.4;
uniform float intensity : hint_range(0.0, 2.0) = 0.5;
uniform vec3 ray_color : source_color = vec3(0.5, 0.8, 1.0);
uniform vec3 ray_color : source_color = vec3(0.7, 0.9, 1.0);
uniform float intensity : hint_range(0, 2) = 0.6;
uniform float fade_bottom : hint_range(-100, 0) = -30.0;
void fragment() {
vec2 uv = UV;
float rays = 0.0;
// Multiple ray stripes
for (float i = 0.0; i < 5.0; i++) {
float offset = i * 0.2 + TIME * 0.03;
float r = smoothstep(0.02, 0.0, abs(fract(uv.x * 8.0 + offset) - 0.5));
rays += r * (1.0 - i / 5.0);
}
// Fade vertical
float vertical_fade = smoothstep(0.0, 0.4, 1.0 - uv.y);
// Fade avec profondeur joueur
float depth_fade = clamp((VERTEX.y - fade_bottom) / (60.0 - fade_bottom), 0.0, 1.0);
float vertical_fade = pow(1.0 - uv.y, 2.0);
float ray_pattern = fract(uv.x * ray_count + sin(TIME * speed + uv.y * 5.0) * 0.3);
float ray = smoothstep(0.0, 0.15, ray_pattern) * smoothstep(0.4, 0.15, ray_pattern);
float brightness = ray * vertical_fade * intensity;
COLOR = vec4(ray_color * brightness, brightness * 0.6);
float final_alpha = rays * vertical_fade * depth_fade * intensity;
ALBEDO = ray_color;
ALPHA = final_alpha;
}

View File

@@ -1,21 +1,19 @@
shader_type fog;
uniform float surface_y : hint_range(-100.0, 100.0) = 0.0;
uniform float abyss_depth : hint_range(-200.0, 0.0) = -60.0;
uniform vec3 shallow_color : source_color = vec3(0.25, 0.55, 0.70);
uniform vec3 deep_color : source_color = vec3(0.02, 0.05, 0.10);
uniform float surface_y : hint_range(0, 100) = 60.0;
uniform float abyss_y : hint_range(-100, 0) = -60.0;
uniform float base_density : hint_range(0, 1) = 0.04;
uniform float abyss_density : hint_range(0, 3) = 0.25;
void fog() {
float depth_factor = clamp((WORLD_POSITION.y - abyss_depth) / (surface_y - abyss_depth), 0.0, 1.0);
vec3 surface_color = vec3(0.15, 0.45, 0.6);
vec3 abyss_color = vec3(0.02, 0.08, 0.15);
vec3 fog_color = mix(abyss_color, surface_color, depth_factor);
float current_wave = sin(TIME * 0.3 + WORLD_POSITION.x * 0.05) * 0.02
+ sin(TIME * 0.17 + WORLD_POSITION.z * 0.04) * 0.01;
float base_density = mix(0.3, 0.05, depth_factor) + current_wave;
base_density = clamp(base_density, 0.0, 0.4);
ALBEDO = fog_color;
DENSITY = base_density;
float depth_factor = clamp((surface_y - WORLD_POSITION.y) / (surface_y - abyss_y), 0.0, 1.0);
vec3 col = mix(shallow_color, deep_color, depth_factor);
float density = mix(base_density, abyss_density, depth_factor);
// Subtle current movement
float wave = sin(WORLD_POSITION.x * 0.1 + TIME * 0.3) * 0.5 + 0.5;
density *= (0.9 + wave * 0.2);
ALBEDO = col;
DENSITY = density;
}

View File

@@ -0,0 +1,21 @@
shader_type spatial;
render_mode cull_front, depth_draw_never, blend_mix;
uniform vec3 surface_color : source_color = vec3(0.15, 0.45, 0.65);
uniform float wave_speed = 0.3;
uniform float wave_amplitude = 0.15;
void vertex() {
float wave1 = sin(VERTEX.x * 0.5 + TIME * wave_speed) * wave_amplitude;
float wave2 = cos(VERTEX.z * 0.4 + TIME * wave_speed * 1.3) * wave_amplitude * 0.7;
VERTEX.y += wave1 + wave2;
}
void fragment() {
ALBEDO = surface_color;
float fresnel = pow(1.0 - dot(NORMAL, VIEW), 2.0);
ALPHA = 0.4 + fresnel * 0.4;
METALLIC = 0.2;
ROUGHNESS = 0.3;
EMISSION = surface_color * 0.1;
}