131 lines
5.5 KiB
GDScript
131 lines
5.5 KiB
GDScript
extends Node2D
|
|
## World-space weather: bounded particle pool, slow transitions, no screen-space noise.
|
|
const LIMIT := 190
|
|
var source: Control
|
|
var intensity := 0.15
|
|
var target_intensity := 0.2
|
|
var wind := Vector2(18,6)
|
|
var mode := "wind"
|
|
var _rng := RandomNumberGenerator.new()
|
|
var _time := 0.0
|
|
var _transition := 36.0
|
|
var _storm_timer := 40.0
|
|
var _flash := 0.0
|
|
var _emission := 0.0
|
|
var _particles: Array[Dictionary] = []
|
|
var _fog: Array[Sprite2D] = []
|
|
var _biome := 0
|
|
var _bolt := PackedVector2Array()
|
|
|
|
func _ready() -> void:
|
|
name = "SurfaceWeather"
|
|
z_index = 80
|
|
texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
|
_rng.seed = source.progress.visit_seed ^ 0x57454154
|
|
_biome = int(source.world.data.landscape.index)
|
|
mode = ["rain","leaves","rain","wind","dust","snow"][_biome]
|
|
target_intensity = 0.38 if _biome in [2,5] else 0.18
|
|
var material := ShaderMaterial.new()
|
|
material.shader = preload("res://resources/effects/cloud_mist.gdshader")
|
|
for index in 12:
|
|
var fog := Sprite2D.new()
|
|
fog.texture = preload("res://assets/planets/cloud_mist.png")
|
|
fog.material = material
|
|
fog.position = Vector2(index%4*1100-1650,index/4*1100-1100)
|
|
fog.rotation = _rng.randf_range(-PI,PI)
|
|
fog.scale = Vector2.ONE*_rng.randf_range(650,1100)/fog.texture.get_width()
|
|
fog.z_as_relative = false
|
|
fog.z_index = 18
|
|
fog.modulate = Color(0.79,0.84,0.79,0.0)
|
|
add_child(fog)
|
|
_fog.append(fog)
|
|
|
|
func _center() -> Vector2:
|
|
return source.camera.get_screen_center_position()
|
|
|
|
func _extent() -> Vector2:
|
|
return Vector2(get_viewport_rect().size)/source.camera.zoom*0.5+Vector2(140,140)
|
|
|
|
func _process(delta: float) -> void:
|
|
if not is_instance_valid(source) or source._ending: return
|
|
_time += delta
|
|
_transition -= delta
|
|
if _transition <= 0:
|
|
_transition = _rng.randf_range(38,85)
|
|
target_intensity = _rng.randf_range(0.12,0.85) if _biome in [2,4,5] else _rng.randf_range(0.0,0.58)
|
|
intensity = move_toward(intensity,target_intensity,delta*0.018)
|
|
var gust := 0.75+0.25*sin(_time*0.19)+0.12*sin(_time*0.57)
|
|
wind = Vector2(22,7).rotated(sin(_time*0.045)*0.25)*(0.7+intensity*1.4)*gust
|
|
if is_instance_valid(source.world.tree_canopy):
|
|
source.world.tree_canopy.wind_material.set_shader_parameter("wind_direction",wind.normalized())
|
|
source.world.tree_canopy.wind_material.set_shader_parameter("wind_strength",0.5+intensity*1.4)
|
|
for index in _fog.size():
|
|
var fog := _fog[index]
|
|
fog.position += wind*delta*0.24
|
|
fog.position.x = wrapf(fog.position.x,-2350,2350)
|
|
fog.position.y = wrapf(fog.position.y,-2100,2100)
|
|
var h := terrain_height(fog.position)
|
|
var valley := 1.0-smoothstep(0.42,0.65,h)
|
|
fog.modulate.a = (0.035+intensity*0.14)*valley*(1.0 if _biome in [0,1,2,5] else 0.3)
|
|
if _biome == 4:
|
|
for fog in _fog: fog.modulate = Color(0.76,0.62,0.39,fog.modulate.a+intensity*0.04)
|
|
_emission += delta*([13,12,34,8,24,34][_biome])*intensity
|
|
while _emission >= 1:
|
|
_emission -= 1
|
|
if _particles.size() < LIMIT: _spawn()
|
|
var center := _center()
|
|
var extent := _extent()
|
|
for index in range(_particles.size()-1,-1,-1):
|
|
var p: Dictionary = _particles[index]
|
|
p.age += delta
|
|
p.position += (p.velocity+wind)*delta
|
|
if p.age > p.life or absf(p.position.x-center.x) > extent.x*1.3 or absf(p.position.y-center.y) > extent.y*1.3:
|
|
_particles.remove_at(index)
|
|
_flash = move_toward(_flash,0,delta*0.8)
|
|
_storm_timer -= delta
|
|
if mode == "rain" and intensity > 0.66 and _storm_timer <= 0:
|
|
_storm_timer = _rng.randf_range(28,65)
|
|
_flash = 0.045
|
|
var point := center+Vector2(_rng.randf_range(-extent.x*0.8,extent.x*0.8),-extent.y*0.7)
|
|
_bolt = PackedVector2Array([point,point+Vector2(15,30),point+Vector2(4,45),point+Vector2(31,80)])
|
|
queue_redraw()
|
|
|
|
func terrain_height(point: Vector2) -> float:
|
|
var x := clampi(int((point.x+1920)/40),0,95)
|
|
var y := clampi(int((point.y+1920)/40),0,95)
|
|
return float(source.world.data.heights[y*96+x])
|
|
|
|
func _spawn() -> void:
|
|
var extent := _extent()
|
|
var point := _center()+Vector2(_rng.randf_range(-extent.x,extent.x),_rng.randf_range(-extent.y,extent.y))
|
|
var velocity := Vector2(-25,250) if mode == "rain" else Vector2(_rng.randf_range(-8,8),_rng.randf_range(7,22))
|
|
_particles.append({"position":point,"velocity":velocity,"age":0.0,"life":_rng.randf_range(3,6),"size":_rng.randf_range(1.1,2.8),"phase":_rng.randf_range(0,TAU)})
|
|
|
|
func _draw() -> void:
|
|
for p in _particles:
|
|
var alpha := sin(clampf(p.age/p.life,0,1)*PI)
|
|
var point: Vector2 = p.position+Vector2(sin(_time*1.6+p.phase)*3,0)
|
|
match mode:
|
|
"rain":
|
|
draw_line(point,point+Vector2(-2,12),Color(0.73,0.83,0.86,alpha*0.26),0.8,true)
|
|
if terrain_height(point) < 0.32: draw_arc(point+Vector2(-2,12),p.size*1.5,0,TAU,12,Color(0.73,0.83,0.86,alpha*0.10),0.7,true)
|
|
"snow": draw_circle(point,p.size,Color(0.91,0.96,0.97,alpha*0.55),true,-1,true)
|
|
"leaves":
|
|
draw_set_transform(point,sin(_time+p.phase),Vector2(1,0.45))
|
|
draw_circle(Vector2.ZERO,p.size,Color(0.61,0.43,0.19,alpha*0.55),true,-1,true)
|
|
_draw_reset()
|
|
_: draw_line(point,point+wind.normalized()*p.size*7,Color(0.80,0.72,0.53,alpha*0.11),1,true)
|
|
var center := _center()
|
|
var extent := _extent()
|
|
# Very faint broad sun shafts, confined to damp wooded climates.
|
|
if _biome in [0,1,2]:
|
|
for index in 2:
|
|
var start := center+Vector2(-extent.x*0.7+index*extent.x*0.9,-extent.y)
|
|
draw_colored_polygon(PackedVector2Array([start,start+Vector2(50,0),start+Vector2(380,extent.y*2),start+Vector2(210,extent.y*2)]),Color(0.95,0.87,0.62,0.012*(1.0-intensity)))
|
|
if _flash > 0:
|
|
draw_rect(Rect2(center-extent,extent*2),Color(0.78,0.84,1.0,_flash))
|
|
draw_polyline(_bolt,Color(0.83,0.90,1.0,_flash*6),1.2,true)
|
|
|
|
func _draw_reset() -> void:
|
|
draw_set_transform(Vector2.ZERO)
|