- 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>
48 lines
1.5 KiB
GDScript
48 lines
1.5 KiB
GDScript
extends Node3D
|
|
|
|
# Creates horizontal caustic planes at multiple depths, follows the player
|
|
# Add as child of any node that follows the player (e.g. PlanktonFollower)
|
|
|
|
const LAYER_DEPTHS := [-5.0, -15.0, -25.0]
|
|
const LAYER_SIZE := 60.0
|
|
|
|
var caustic_meshes: Array[MeshInstance3D] = []
|
|
var caustic_material: ShaderMaterial
|
|
|
|
func _ready() -> void:
|
|
var shader := load("res://shaders/caustics.gdshader")
|
|
if not shader:
|
|
push_warning("CausticsLayer: caustics.gdshader not found")
|
|
return
|
|
|
|
caustic_material = ShaderMaterial.new()
|
|
caustic_material.shader = shader
|
|
|
|
for depth in LAYER_DEPTHS:
|
|
var mi := MeshInstance3D.new()
|
|
var plane := PlaneMesh.new()
|
|
plane.size = Vector2(LAYER_SIZE, LAYER_SIZE)
|
|
mi.mesh = plane
|
|
# Each layer gets its own material instance to allow per-depth tuning
|
|
var mat := caustic_material.duplicate() as ShaderMaterial
|
|
# Lower layers = less intense
|
|
var fade := clamp(1.0 + depth / 30.0, 0.0, 1.0)
|
|
mat.set_shader_parameter("intensity", 1.5 * fade)
|
|
mi.material_override = mat
|
|
mi.position = Vector3(0.0, depth, 0.0)
|
|
add_child(mi)
|
|
caustic_meshes.append(mi)
|
|
|
|
func _process(_delta: float) -> void:
|
|
# Follow camera XZ, keep fixed Y depths
|
|
var cam := get_viewport().get_camera_3d()
|
|
if cam:
|
|
var cx := cam.global_position.x
|
|
var cz := cam.global_position.z
|
|
for i in caustic_meshes.size():
|
|
var mi := caustic_meshes[i]
|
|
mi.global_position.x = cx
|
|
mi.global_position.z = cz
|
|
# Keep the fixed depth offset
|
|
mi.global_position.y = LAYER_DEPTHS[i]
|