Randoloot/scripts/planets/surface_flight_effects.gd
2026-10-20 19:53:03 +02:00

112 lines
4.5 KiB
GDScript

extends Node2D
## Ground wash stays in world space after emission, independently of the lander.
const LIMIT := 220
var source: Control
var weather: Node2D
var _rng := RandomNumberGenerator.new()
var _particles: Array[Dictionary] = []
var _soft: GradientTexture2D
var _shadow: Sprite2D
var _emission := 0.0
var _tree_timer := 0.0
var _near_trees := false
var _surface_kind := "dust"
var _ground := Color("b5a17a")
func _ready() -> void:
name = "SurfaceFlightEffects"
z_index = 21
texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
_rng.seed = source.progress.visit_seed ^ 0x44555354
_ground = (source.world.data.landscape.sand as Color).lerp(source.world.data.landscape.low,0.25)
var gradient := Gradient.new()
gradient.set_color(0,Color.WHITE)
gradient.set_color(1,Color(1,1,1,0))
_soft = GradientTexture2D.new()
_soft.gradient = gradient
_soft.width = 64
_soft.height = 64
_soft.fill = GradientTexture2D.FILL_RADIAL
_soft.fill_from = Vector2(0.5,0.5)
_soft.fill_to = Vector2(0.5,1)
_shadow = Sprite2D.new()
_shadow.name = "LanderShadow"
_shadow.texture = source.lander.texture
_shadow.scale = source.lander.scale*0.76
_shadow.z_index = -1
var material := ShaderMaterial.new()
material.shader = preload("res://resources/effects/lander_shadow.gdshader")
_shadow.material = material
add_child(_shadow)
func surface_kind(point: Vector2) -> String:
if int(source.world.data.landscape.index) == 5: return "snow"
var h: float = weather.terrain_height(point)
if h < 0.29 or (int(source.world.data.landscape.index) == 2 and h < 0.37): return "spray"
return "rock" if h > 0.64 else "dust"
func _process(delta: float) -> void:
if not is_instance_valid(source): return
visible = not source._ending
if source._ending: return
var pose: Transform2D = source.lander.global_transform
pose.origin = source._previous_position.lerp(source.lander.position,Engine.get_physics_interpolation_fraction())
var point := pose.origin
_shadow.position = point+Vector2(48,64)
_shadow.rotation = pose.get_rotation()
_shadow.visible = source.lander.visible
_tree_timer -= delta
if _tree_timer <= 0:
_tree_timer = 0.4
_near_trees = false
for tree in source.world.data.trees:
if point.distance_squared_to(tree.position) < 170*170:
_near_trees = true
break
_surface_kind = surface_kind(point)
var thrust: bool = source.engine_thrust_active()
var brake: bool = not source._dialog.visible and Input.is_action_pressed("ship_brake") and source._motion.velocity.length() > 12
var boost: bool = source._motion.boost_active and thrust
if thrust or brake:
var rate := 90.0 if boost else (46.0 if thrust else 30.0)
if _surface_kind == "rock": rate *= 0.45
_emission += delta*rate
while _emission >= 1:
_emission -= 1
if _particles.size() < LIMIT: _emit(point,pose.get_rotation(),boost)
else: _emission = 0
for index in range(_particles.size()-1,-1,-1):
var particle: Dictionary = _particles[index]
particle.age += delta
particle.position += (particle.velocity+weather.wind*0.7)*delta
particle.velocity *= exp(-delta*1.3)
if particle.age > particle.life: _particles.remove_at(index)
queue_redraw()
func _emit(point: Vector2, angle: float, boost: bool) -> void:
var kind := _surface_kind
if _near_trees and kind == "dust" and _rng.randf() < 0.20: kind = "leaf"
var nozzle := Vector2(_rng.randf_range(-29,29),_rng.randf_range(22,42)).rotated(angle)
var scatter := Vector2(_rng.randf_range(-48,48),_rng.randf_range(20,65)).rotated(angle)
_particles.append({"position":point+nozzle,"velocity":scatter+source._motion.velocity*0.1,"age":0.0,"life":_rng.randf_range(1.5,2.8),"size":_rng.randf_range(15,25)*(1.55 if boost else 1.0),"kind":kind,"angle":_rng.randf_range(-PI,PI)})
func _draw() -> void:
for particle in _particles:
var t := clampf(particle.age/particle.life,0,1)
var alpha := sin(t*PI)
var kind: String = particle.kind
var radius: float = particle.size*(1.0+t*1.9)
var color := _ground
color.a = alpha*0.32
if kind == "rock": color = Color(0.65,0.65,0.59,alpha*0.19)
if kind == "snow": color = Color(0.88,0.95,0.95,alpha*0.38)
if kind == "spray": color = Color(0.66,0.83,0.80,alpha*0.30)
if kind == "leaf":
draw_set_transform(particle.position,particle.angle+t*2,Vector2(1,0.45))
draw_circle(Vector2.ZERO,2.5,Color(0.49,0.35,0.17,alpha*0.7),true,-1,true)
draw_set_transform(Vector2.ZERO)
else:
draw_texture_rect(_soft,Rect2(particle.position-Vector2.ONE*radius,Vector2.ONE*radius*2),false,color)
if kind in ["spray","snow"]:
draw_circle(particle.position+Vector2(4,-7)*t,1.4,Color(color,alpha*0.38),true,-1,true)