class_name WeatherController extends Node var thunder_audio_player: AudioStreamPlayer var thunder_sounds: Array[AudioStream] var rain_sounds: Array[AudioStream] var rain_audio_player: AudioStreamPlayer var particles_wind: GPUParticles3D var particles_snow: GPUParticles3D var particles_fireflies: GPUParticles3D var particles_rain: GPUParticles3D var godray: PackedScene var environment_dust: ColorRect var blur: ColorRect var environment_shadows: MeshInstance3D var fog: Node3D var sun: DirectionalLight3D var environment: WorldEnvironment var environment_config: EnvironmentConfig var camera: Camera3D var camera_pivot: Node3D var day_time: float = 0.0 var lightning_sprite: Sprite3D var lightning_light = DirectionalLight3D.new(); var timer_next_lightning: float = 0.0 var is_raining: bool = false var rain_intensity: float = 0.0 var rain_tween: Tween var rain_audio_tween: Tween var puddle_tween: Tween var puddle_amount: float = 0.0 var snow_tween: Tween var snow_particles_tween: Tween var is_snowing: bool = false var is_snow_accumulated: bool = false var actual_snow_amount: float = 0.0 var is_storm: bool = false var cold_tween: Tween var wind_tween: Tween var is_windy: bool = false var thereare_fireflies: bool = false var current_wind_speed: float = 0.0 var current_wind_strength: float = 0.0 var current_wind_fade: float = 0.0 var max_wind_amount: int = 0 var random_weather_restore_tween: Tween var random_event_remaining: float = 0.0 var random_event_label_seconds: int = -1 func _init(wind: GPUParticles3D, snow: GPUParticles3D, fireflies: GPUParticles3D, rain: GPUParticles3D, ray: PackedScene, dust: ColorRect, blurr: ColorRect, thefog: Node3D, envshadows: MeshInstance3D, thesun: DirectionalLight3D, theenvironment: WorldEnvironment, environmentconfig: EnvironmentConfig, thecamera: Camera3D, thecamerapivot: Node3D, thundersounds: Array[AudioStream], rainsounds: Array[AudioStream]) -> void: particles_wind = wind particles_snow = snow particles_fireflies = fireflies particles_rain = rain godray = ray sun = thesun environment_dust = dust blur = blurr fog = thefog environment_shadows = envshadows environment = theenvironment environment_config = environmentconfig max_wind_amount = environment_config.wind_amount if environment_config != null else 0 camera = thecamera camera_pivot = thecamerapivot thunder_sounds = thundersounds rain_sounds = rainsounds init_rain() init_fireflies() init_wind() init_snow() init_lightning() create_sound_players() toggle_dust(environment_config.enable_dust) toggle_blur(environment_config.enable_blur) toggle_fog(environment_config.enable_fog) #set camera pivot if available if camera_pivot: camera_pivot.get_node("pivot").camera_changed.connect(_set_camera) func _ready() -> void: #connect events UIEvents.toggle_rain.connect(toggle_rain) UIEvents.toggle_snow.connect(toggle_snow) UIEvents.toggle_wind.connect(toggle_wind) UIEvents.wind_change.connect(change_wind_strength) UIEvents.trigger_random_weather.connect(trigger_random_weather_event) UIEvents.toggle_fireflies.connect(toggle_fireflies) UIEvents.toggle_storm.connect(toggle_storm) UIEvents.toggle_dust.connect(toggle_dust) UIEvents.toggle_blur.connect(toggle_blur) UIEvents.toggle_fog.connect(toggle_fog) UIEvents.toggle_shadows.connect(toggle_shadows) _emit_weather_event_label() func _process(delta: float) -> void: _update_random_event_label(delta) _follow_camera() var is_night = day_time >= 2.5 if particles_fireflies: particles_fireflies.emitting = thereare_fireflies and is_night var base_tint: Color var base_sky_top: Color var base_sky_horizon: Color var base_fog_color: Color var base_fog_density: float var base_bloom: float var base_exposure: float var base_grad_top: Color var base_grad_bot: Color var base_grad_intensity: float var base_water_color: Color var base_rotation_sun: Vector3 if is_raining: var target_rain = environment_config.storm_rain_intensity_multiplier if is_storm else 1.0 rain_intensity = move_toward(rain_intensity, target_rain, delta * 0.5) if is_storm: timer_next_lightning -= delta if timer_next_lightning <= 0.0: start_lightning() init_lightning_timer() else: rain_intensity = move_toward(rain_intensity, 0.0, delta * 0.5) RenderingServer.global_shader_parameter_set("global_rain_intensity", rain_intensity) if day_time <= 2.0: var t = day_time - 1.0 base_tint = environment_config.morning_color.lerp(environment_config.afternoon_color, t) base_sky_top = environment_config.sky_top_morning.lerp(environment_config.sky_top_afternoon, t) base_sky_horizon = environment_config.sky_horizon_morning.lerp(environment_config.sky_horizon_afternoon, t) base_fog_color = environment_config.fog_color_morning.lerp(environment_config.fog_color_afternoon, t) base_fog_density = lerp(environment_config.fog_density_morning, environment_config.fog_density_afternoon, t) base_bloom = lerp(environment_config.glow_morning, environment_config.glow_afternoon, t) base_exposure = lerp(environment_config.exposure_morning, environment_config.exposure_afternoon, t) base_grad_top = environment_config.grad_top_morning.lerp(environment_config.grad_top_afternoon, t) base_grad_bot = environment_config.grad_top_morning.lerp(environment_config.grad_bot_afternoon, t) base_grad_intensity = lerp(environment_config.grad_intensity_morning, environment_config.grad_intensity_afternoon, t) base_water_color = environment_config.water_color_morning.lerp(environment_config.water_color_afternoon, t) base_rotation_sun = environment_config.sun_rotation_morning.lerp(environment_config.sun_rotation_afternoon, t) else: var t = day_time - 2.0 base_tint = environment_config.afternoon_color.lerp(environment_config.night_color, t) base_sky_top = environment_config.sky_top_afternoon.lerp(environment_config.sky_top_night, t) base_sky_horizon = environment_config.sky_horizon_afternoon.lerp(environment_config.sky_horizon_night, t) base_fog_color = environment_config.fog_color_afternoon.lerp(environment_config.fog_color_night, t) base_fog_density = lerp(environment_config.fog_density_afternoon, environment_config.fog_density_night, t) base_bloom = lerp(environment_config.glow_afternoon, environment_config.glow_night, t) base_exposure = lerp(environment_config.exposure_afternoon, environment_config.exposure_night, t) base_grad_top = environment_config.grad_top_afternoon.lerp(environment_config.grad_top_night, t) base_grad_bot = environment_config.grad_bot_afternoon.lerp(environment_config.grad_bot_night, t) base_grad_intensity = lerp(environment_config.grad_intensity_afternoon, environment_config.grad_intensity_night, t) base_water_color = environment_config.water_color_afternoon.lerp(environment_config.water_color_night, t) base_rotation_sun = environment_config.sun_rotation_afternoon.lerp(environment_config.sun_rotation_night, t) var weather_color = environment_config.rain_mode_color if is_storm: var storm_blend = clamp((rain_intensity - 1.0) / (environment_config.storm_rain_intensity_multiplier - 1.0), 0.0, 1.0) weather_color = weather_color.lerp(environment_config.storm_mode_color, storm_blend) var final_tint = base_tint.lerp(base_tint * weather_color, clamp(rain_intensity, 0.0, 1.0)) var final_sky_top = base_sky_top.lerp(base_sky_top * weather_color, clamp(rain_intensity, 0.0, 1.0)) var final_sky_horizon = base_sky_horizon.lerp(base_sky_horizon * weather_color, clamp(rain_intensity, 0.0, 1.0)) var final_fog_color = base_fog_color.lerp(base_fog_color * weather_color, clamp(rain_intensity, 0.0, 1.0)) var final_fog_density = lerp(base_fog_density, base_fog_density * 4.0, clamp(rain_intensity, 0.0, 1.0)) var final_water_color = base_water_color.darkened(clamp(environment_config.water_darkening_rain, 0.0, 1.0) * clamp(rain_intensity, 0.0, 1.0)) final_tint = final_tint.lerp(final_tint * environment_config.snow_mode_color, actual_snow_amount) final_sky_top = final_sky_top.lerp(final_sky_top * environment_config.snow_mode_color, actual_snow_amount) final_sky_horizon = final_sky_horizon.lerp(final_sky_horizon * environment_config.snow_mode_color, actual_snow_amount) final_fog_color = final_fog_color.lerp(final_fog_color * environment_config.snow_mode_color, actual_snow_amount) #Shader parameters for global trunk_shader var final_grad_top = base_grad_top.lerp(base_grad_top * weather_color, clamp(rain_intensity, 0.0, 1.0)) var final_grad_bot = base_grad_bot.lerp(base_grad_bot * weather_color, clamp(rain_intensity, 0.0, 1.0)) RenderingServer.global_shader_parameter_set("global_gradient_color_top", final_grad_top) RenderingServer.global_shader_parameter_set("global_gradient_color_bot", final_grad_bot) RenderingServer.global_shader_parameter_set("global_gradient_intensity", base_grad_intensity) RenderingServer.global_shader_parameter_set("global_water_color", final_water_color) var night_val = clamp(day_time - 2.0, 0.0, 1.0) #Snow exposure compensation var snow_light_attenuation = lerp(1.0, 0.55, actual_snow_amount * (1.0 - night_val)) var snow_glow_attenuation = lerp(1.0, 0.5, actual_snow_amount) var final_bloom = lerp(base_bloom, base_bloom * 0.5, rain_intensity) * snow_glow_attenuation # We calculate the final exposure by applying snow damping directly to the camera exposure var final_exposure = base_exposure * snow_light_attenuation var reflected_color = Color(0.4, 0.5, 0.6, 1.0) var drops_color = final_sky_horizon.lerp(reflected_color, 0.15) drops_color = drops_color.lerp(drops_color * 0.4, night_val) if environment_config.material_drops: environment_config.material_drops.albedo_color = drops_color if sun: sun.light_color = final_tint sun.rotation_degrees = base_rotation_sun var target_energy = lerp(1.0, environment_config.night_light_energy, night_val) # Sunlight scales based on weather/night sun.light_energy = lerp(target_energy, target_energy * 0.4, rain_intensity) if environment and environment.environment: environment.environment.ambient_light_color = final_tint # Apply fog environment.environment.fog_enabled = true environment.environment.fog_light_color = final_fog_color environment.environment.fog_density = final_fog_density # Apply glow environment.environment.glow_enabled = true environment.environment.glow_intensity = final_bloom environment.environment.tonemap_exposure = final_exposure var sky_mat = environment.environment.sky.sky_material as ShaderMaterial if sky_mat: sky_mat.set_shader_parameter("sky_top_color", final_sky_top) sky_mat.set_shader_parameter("sky_horizon_color", final_sky_horizon) sky_mat.set_shader_parameter("sun_color", final_tint) sky_mat.set_shader_parameter("night_intensity", night_val) if environment_config.material_clouds: var current_density = lerp(0.4, 1.0, rain_intensity) environment_config.material_clouds.set_shader_parameter("cloud_density", current_density) var current_sharpness = lerp(0.14, 0.0, rain_intensity) environment_config.material_clouds.set_shader_parameter("center_sharpness", current_sharpness) if environment_config.material_fog: environment_config.material_fog.set_shader_parameter("night_intensity", night_val) environment_config.material_fog.set_shader_parameter("sun_color", final_tint) func create_sound_players(): rain_audio_player = AudioStreamPlayer.new() rain_audio_player.name = "RainAudioPlayer" rain_audio_player.volume_db = environment_config.rain_audio_volume_db rain_audio_player.finished.connect(_on_rain_audio_player_finished) add_child(rain_audio_player) thunder_audio_player = AudioStreamPlayer.new() thunder_audio_player.name = "ThunderAudioPlayer" thunder_audio_player.volume_db = environment_config.thunder_audio_volume_db add_child(thunder_audio_player) #region camera func _set_camera(curr_camera: Camera3D): camera = curr_camera func _get_weather_anchor_position() -> Variant: if camera_pivot and is_instance_valid(camera_pivot): return camera_pivot.global_position if camera and is_instance_valid(camera): return camera.global_position return null func _get_weather_anchor_basis() -> Variant: var source_basis: Basis if camera_pivot and is_instance_valid(camera_pivot): source_basis = camera_pivot.global_basis elif camera and is_instance_valid(camera): source_basis = camera.global_basis else: return null var forward := -source_basis.z forward.y = 0.0 if forward.length_squared() <= 0.0001: return Basis.IDENTITY forward = forward.normalized() var right := forward.cross(Vector3.UP).normalized() return Basis(right, Vector3.UP, -forward) func _follow_camera() -> void: var cam_pos = _get_weather_anchor_position() if cam_pos == null: return if particles_rain: particles_rain.global_position = Vector3(cam_pos.x, particles_rain.position.y, cam_pos.z) if particles_snow: particles_snow.global_position = Vector3(cam_pos.x, particles_snow.position.y, cam_pos.z) if particles_wind: particles_wind.global_position = Vector3(cam_pos.x, cam_pos.y, cam_pos.z) if particles_fireflies: particles_fireflies.global_position = Vector3(cam_pos.x, particles_fireflies.position.y, cam_pos.z) if fog: fog.global_position = Vector3(cam_pos.x, fog.global_position.y, cam_pos.z) #used to follow camera pivot or camera var anchor_basis = _get_weather_anchor_basis() if anchor_basis != null: fog.global_basis = anchor_basis #endregion #region Fireflies func toggle_fireflies(value: bool): thereare_fireflies = value var is_night = day_time >= 2.5 if particles_fireflies: particles_fireflies.emitting = thereare_fireflies and is_night #disable fireflies and set default values and materials func init_fireflies(): if particles_fireflies: particles_fireflies.visible = true particles_fireflies.emitting = false particles_fireflies.amount = environment_config.fireflies_amount var proc_mat = particles_fireflies.process_material as ParticleProcessMaterial if proc_mat: proc_mat.emission_box_extents = Vector3(environment_config.fireflies_spawn_ray, environment_config.fireflies_spawn_height, environment_config.fireflies_spawn_ray) #endregion #region Wind func toggle_wind(value: bool): is_windy = value if particles_wind: particles_wind.emitting = is_windy _apply_wind_state() _emit_weather_event_label() #disable wind and set default values and materials func init_wind(): _update_wind_amount_from_strength(environment_config.wind_strength) if particles_wind: particles_wind.visible = true particles_wind.emitting = false particles_wind.amount = environment_config.wind_amount var proc_mat_wind = particles_wind.process_material as ParticleProcessMaterial if proc_mat_wind: proc_mat_wind.emission_box_extents = Vector3(environment_config.wind_spawn_ray, environment_config.wind_spawn_height, environment_config.wind_spawn_ray) if environment_config: _apply_cloud_config() _apply_wind_config() _apply_dust_config() func _apply_wind_config() -> void: RenderingServer.global_shader_parameter_set("global_wind_direction", environment_config.wind_direction) RenderingServer.global_shader_parameter_set("global_wind_scale", environment_config.wind_scale) if particles_wind: var proc_mat_wind = particles_wind.process_material as ParticleProcessMaterial if proc_mat_wind: var wind_direction_3d := Vector3(environment_config.wind_direction.x, 0.0, environment_config.wind_direction.y) if wind_direction_3d.length_squared() > 0.0: var wind_axis := wind_direction_3d.normalized() var wind_cross := wind_axis.cross(Vector3.UP) if wind_cross.length_squared() == 0.0: wind_cross = Vector3.FORWARD else: wind_cross = wind_cross.normalized() var wind_up := wind_cross.cross(wind_axis).normalized() proc_mat_wind.direction = wind_axis particles_wind.global_transform = Transform3D(Basis(wind_cross, wind_axis, wind_up), particles_wind.global_position) _apply_wind_state(true) func _apply_wind_state(immediate: bool = false) -> void: if environment_config == null: return if wind_tween and wind_tween.is_valid(): wind_tween.kill() var active_wind_speed := environment_config.wind_speed if is_windy else 0.0 var active_wind_strength := environment_config.wind_strength if is_windy else 0.0 var active_wind_fade := 1.0 if is_windy else 0.0 if immediate: _set_current_wind_speed(active_wind_speed) _set_current_wind_strength(active_wind_strength) _set_current_wind_fade(active_wind_fade) return _set_current_wind_speed(environment_config.wind_speed) _set_current_wind_strength(environment_config.wind_strength) wind_tween = create_tween() wind_tween.tween_method(_set_current_wind_fade, current_wind_fade, active_wind_fade, environment_config.wind_fade_in_out_time) wind_tween.tween_callback(_finish_wind_fade_out) func _set_current_wind_speed(value: float) -> void: current_wind_speed = value RenderingServer.global_shader_parameter_set("global_wind_speed", value) func _set_current_wind_strength(value: float) -> void: current_wind_strength = value RenderingServer.global_shader_parameter_set("global_wind_strength", value) func _set_current_wind_fade(value: float) -> void: current_wind_fade = value RenderingServer.global_shader_parameter_set("global_wind_fade", value) func _finish_wind_fade_out() -> void: if is_windy: return _set_current_wind_speed(0.0) _set_current_wind_strength(0.0) _set_current_wind_fade(0.0) func change_wind_strength(value: float) -> void: if environment_config == null: return environment_config.wind_strength = value _update_wind_amount_from_strength(value) if is_windy or current_wind_fade > 0.0: _set_current_wind_strength(value) if particles_wind: particles_wind.amount = environment_config.wind_amount func _update_wind_amount_from_strength(value: float) -> void: if environment_config == null: return if max_wind_amount <= 0: max_wind_amount = max(environment_config.wind_amount, 1) var normalized_strength: float = clamp(value, 0.0, 1.0) var amount_ratio: float = normalized_strength if normalized_strength > 0.0 and normalized_strength < 0.3: amount_ratio = lerp(0.08, 0.25, normalized_strength / 0.3) environment_config.wind_amount = roundi(max_wind_amount * amount_ratio) func trigger_random_weather_event(duration: float = 0.0) -> void: if random_weather_restore_tween and random_weather_restore_tween.is_valid(): random_weather_restore_tween.kill() random_event_remaining = 0.0 random_event_label_seconds = -1 var previous_rain: bool = is_raining var previous_snow: bool = is_snowing var previous_wind: bool = is_windy var previous_storm: bool = is_storm var random_event_index: int = randi_range(0, 3) match random_event_index: 0: _apply_weather_event_state(false, true, false, false) 1: _apply_weather_event_state(true, false, false, false) 2: _apply_weather_event_state(false, false, true, false) _: _apply_weather_event_state(true, false, false, true) if duration > 0.0: random_event_remaining = duration _emit_weather_event_label() random_weather_restore_tween = create_tween() random_weather_restore_tween.tween_interval(duration) random_weather_restore_tween.tween_callback(func(): random_event_remaining = 0.0 random_event_label_seconds = -1 _apply_weather_event_state(previous_rain, previous_snow, previous_wind, previous_storm) ) func _update_random_event_label(delta: float) -> void: if random_event_remaining <= 0.0: return random_event_remaining = maxf(random_event_remaining - delta, 0.0) var display_seconds: int = ceili(random_event_remaining) if display_seconds != random_event_label_seconds: random_event_label_seconds = display_seconds _emit_weather_event_label() func _apply_weather_event_state(rain_enabled: bool, snow_enabled: bool, wind_enabled: bool, storm_enabled: bool = false) -> void: if is_storm and not storm_enabled: toggle_storm(false) if is_raining and not rain_enabled: toggle_rain(false) if is_snowing and not snow_enabled: toggle_snow(false) if is_windy and not wind_enabled: toggle_wind(false) if not is_raining and rain_enabled: toggle_rain(true) if not is_snowing and snow_enabled: toggle_snow(true) if not is_windy and wind_enabled: toggle_wind(true) if not is_storm and storm_enabled: toggle_storm(true) func _apply_cloud_config() -> void: var dir = environment_config.wind_direction var cloud_scale = environment_config.cloud_scale var cloud_speed = environment_config.cloud_speed var envshadows_scale_rate = environment_config.cloud_scale_envshadows_rate var envshadows_speed_rate = environment_config.cloud_speed_envshadows_rate if environment and environment.environment and environment.environment.sky: var sky_mat = environment.environment.sky.sky_material as ShaderMaterial if sky_mat: sky_mat.set_shader_parameter("cloud_direction", dir) sky_mat.set_shader_parameter("cloud_scale", cloud_scale) sky_mat.set_shader_parameter("cloud_speed", cloud_speed) var env_shadow_mat = environment_shadows.get_surface_override_material(0) if environment_shadows else null if env_shadow_mat: env_shadow_mat.set_shader_parameter("direction", dir) env_shadow_mat.set_shader_parameter("cloud_scale", cloud_scale * envshadows_scale_rate) env_shadow_mat.set_shader_parameter("cloud_speed", cloud_speed * envshadows_speed_rate) if environment_config.material_clouds: environment_config.material_clouds.set_shader_parameter("direction", dir) environment_config.material_clouds.set_shader_parameter("cloud_scale", cloud_scale * envshadows_scale_rate) environment_config.material_clouds.set_shader_parameter("cloud_speed", cloud_speed * envshadows_speed_rate) #endregion #region Lightning func toggle_storm(value: bool): is_storm = value _emit_weather_event_label() #set lightning func init_lightning(): lightning_light.name = "Lightning Light" lightning_light.transform = Transform3D( Vector3(-0.6238797, -0.342596, 0.7024259), # asse X Vector3(0.0, 0.89879405, 0.43837115), # asse Y Vector3(-0.7815204, 0.27349085, -0.56073934), # asse Z Vector3(0.0, 0.0, 30.411049) # origine ) lightning_light.light_color = Color(0.8, 1.0, 1.0, 1.0) lightning_light.light_energy = 0.0 lightning_light.shadow_enabled = true add_child(lightning_light) create_lightning_sprite() init_lightning_timer() func create_lightning_sprite(): lightning_sprite = Sprite3D.new() lightning_sprite.name = "Lightning Sprite" lightning_sprite.transform = Transform3D( Basis( Vector3(4, 0, 0), Vector3(0, 7.32, 0), Vector3(0, 0, 7.3) ), Vector3(0, 17.324, 30.411049) ) lightning_sprite.modulate = Color(1, 1, 1, 0) lightning_sprite.billboard = BaseMaterial3D.BILLBOARD_ENABLED lightning_sprite.alpha_cut = SpriteBase3D.ALPHA_CUT_DISCARD #Add Texture lightning_sprite.texture = load(environment_config.lightning_texture) add_child(lightning_sprite) #set next lightning timer func init_lightning_timer(): timer_next_lightning = randf_range(environment_config.lightning_min_time, environment_config.lightning_max_time) func start_lightning(): if lightning_light: var tween_lighting = create_tween() lightning_light.light_energy = 5.0 tween_lighting.tween_interval(0.05) tween_lighting.tween_callback(func(): lightning_light.light_energy = 0.0) tween_lighting.tween_interval(0.05) tween_lighting.tween_callback(func(): lightning_light.light_energy = 2.0) tween_lighting.tween_method(func(val): lightning_light.light_energy = val, 2.0, 0.0, 0.2) var lightning_number = randi_range(environment_config.lightning_min, environment_config.lightning_max) for i in lightning_number: if lightning_sprite: var random_angle = randf() * TAU var distance = randf_range(10.0, 40.0) lightning_sprite.position = Vector3(cos(random_angle) * distance, 10.0, sin(random_angle) * distance) lightning_sprite.modulate = environment_config.lightning_color lightning_sprite.modulate.a = 1.0 var s = randf_range(environment_config.lightning_scale_min, environment_config.lightning_scale_max) lightning_sprite.scale = Vector3(s, s, s) var tween_sprite = create_tween() tween_sprite.tween_interval(0.2) tween_sprite.tween_property(lightning_sprite, "modulate:a", 0.0, 0.4) #Thunder sound; separated routine to do not stop the loop _play_thunder_delayed(randf_range(0.5, 2.5)) if lightning_number > 1: await get_tree().create_timer(randf_range(0.05, 0.15)).timeout func _play_thunder_delayed(delay: float): await get_tree().create_timer(delay).timeout if thunder_sounds.is_empty() or not thunder_audio_player: return thunder_audio_player.stream = thunder_sounds[randi() % thunder_sounds.size()] thunder_audio_player.pitch_scale = randf_range(0.9, 1.1) thunder_audio_player.play() #endregion #region Rain #disable rain func init_rain(): if particles_rain: particles_rain.visible = true particles_rain.emitting = false if rain_audio_player: rain_audio_player.volume_db = environment_config.rain_audio_volume_db rain_audio_player.stop() RenderingServer.global_shader_parameter_set("global_rain_puddle_amount", 0.0) func set_puddle_amount(value: float): puddle_amount = value RenderingServer.global_shader_parameter_set("global_rain_puddle_amount", value) func toggle_rain(value: bool): is_raining = value if not particles_rain: _emit_weather_event_label() return if is_raining and is_snowing: toggle_snow(false) if rain_tween and rain_tween.is_valid(): rain_tween.kill() if puddle_tween and puddle_tween.is_valid(): puddle_tween.kill() if is_raining: particles_rain.amount_ratio = 0.0 particles_rain.emitting = true if rain_audio_player: if not rain_audio_player.playing: rain_audio_player.volume_db = -80.0 _play_random_rain_sound() _fade_rain_audio(environment_config.rain_audio_volume_db, false) rain_tween = create_tween() rain_tween.tween_property(particles_rain, "amount_ratio", 1.0, environment_config.rain_fade_time) puddle_tween = create_tween() puddle_tween.tween_method(set_puddle_amount, puddle_amount, 1.0, environment_config.puddle_form_time) else: if rain_audio_player: _fade_rain_audio(-80.0, true) rain_tween = create_tween() rain_tween.tween_property(particles_rain, "amount_ratio", 0.0, environment_config.rain_fade_time) rain_tween.tween_callback(func(): particles_rain.emitting = false trigger_after_rain()) puddle_tween = create_tween() puddle_tween.tween_method(set_puddle_amount, puddle_amount, 0.0, environment_config.puddle_dry_time) _emit_weather_event_label() func trigger_morning() -> void: spawn_single_godray() func trigger_after_rain() -> void: if day_time < 2.5: var count: int = randi_range(1, environment_config.godray_max_rain) for i in count: spawn_single_godray() func spawn_single_godray() -> void: var ray: Node3D = godray.instantiate() get_tree().current_scene.add_child(ray) var random_x: float = randf_range(-environment_config.godray_spawn_radius, environment_config.godray_spawn_radius) var random_z: float = randf_range(-environment_config.godray_spawn_radius, environment_config.godray_spawn_radius) var center := Vector3.ZERO var anchor_pos = _get_weather_anchor_position() if anchor_pos != null: center = anchor_pos ray.global_position = Vector3(center.x + random_x, environment_config.godray_spawn_height, center.z + random_z) if ray.has_method("set_visual_rotation_degrees"): ray.call("set_visual_rotation_degrees", environment_config.godray_rotation_degrees) else: ray.rotation_degrees = environment_config.godray_rotation_degrees if ray.has_method("set_visual_scale"): ray.call("set_visual_scale", environment_config.godray_scale) else: ray.scale = environment_config.godray_scale if ray.has_method("orient_to_camera"): ray.call("orient_to_camera") func _play_random_rain_sound() -> void: if rain_sounds.is_empty() or rain_audio_player == null: return rain_audio_player.stream = rain_sounds[randi() % rain_sounds.size()] rain_audio_player.pitch_scale = 1.0 rain_audio_player.volume_db = minf(rain_audio_player.volume_db, environment_config.rain_audio_volume_db) rain_audio_player.play() func _on_rain_audio_player_finished() -> void: if is_raining: _play_random_rain_sound() func _fade_rain_audio(target_volume_db: float, stop_after_fade: bool) -> void: if rain_audio_player == null: return if rain_audio_tween and rain_audio_tween.is_valid(): rain_audio_tween.kill() rain_audio_tween = create_tween() rain_audio_tween.tween_property( rain_audio_player, "volume_db", target_volume_db, environment_config.rain_fade_time #same value of the rain particles ) if stop_after_fade: rain_audio_tween.tween_callback(func(): rain_audio_player.stop()) #endregion #region Snow func toggle_snow(value: bool): is_snowing = value if is_snowing and is_raining: toggle_rain(false) # Fade particelle neve if particles_snow: if snow_particles_tween and snow_particles_tween.is_valid(): snow_particles_tween.kill() if is_snowing: particles_snow.amount_ratio = 0.0 particles_snow.visible = true particles_snow.emitting = true snow_particles_tween = create_tween() snow_particles_tween.tween_property(particles_snow, "amount_ratio", 1.0, environment_config.snow_fade_time) start_snow_accumulation() else: snow_particles_tween = create_tween() snow_particles_tween.tween_property(particles_snow, "amount_ratio", 0.0, environment_config.snow_fade_time) snow_particles_tween.tween_callback(func(): particles_snow.emitting = false) start_snow_melt() var target_snow_amount: float = 1.0 if is_snowing else 0.0 if snow_tween and snow_tween.is_valid(): snow_tween.kill() snow_tween = create_tween() snow_tween.tween_method(init_snow_amount, actual_snow_amount, target_snow_amount, environment_config.snow_transaction_time) _emit_weather_event_label() func _emit_weather_event_label() -> void: var weather_label := "Weather: Clear" if is_storm: weather_label = "Weather: Storm" else: var active_events: Array[String] = [] if is_snowing: active_events.append("Snow") if is_raining: active_events.append("Rain") if is_windy: active_events.append("Wind") if not active_events.is_empty(): weather_label = "Weather: %s" % " + ".join(active_events) if random_event_remaining > 0.0: weather_label += " (%s'')" % ceili(random_event_remaining) UIEvents.weather_event_changed.emit(weather_label) #disable snow and set default values and shader func init_snow(value: float = 0.0): actual_snow_amount = value RenderingServer.global_shader_parameter_set("global_snow_amount", value) if particles_snow: particles_snow.emitting = false if environment_config: RenderingServer.global_shader_parameter_set("global_snow_threshold", environment_config.snow_threshold) RenderingServer.global_shader_parameter_set("global_snow_color", environment_config.snow_color) RenderingServer.global_shader_parameter_set("global_snow_accumulation_speed", environment_config.snow_accumulation_speed) RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed) RenderingServer.global_shader_parameter_set("global_snow_max_accumulation", environment_config.snow_max_accumulation) RenderingServer.global_shader_parameter_set("global_snow_cap_enabled", environment_config.show_snow_accumulation_volume) RenderingServer.global_shader_parameter_set("global_snow_cap_height", environment_config.snow_cap_height) RenderingServer.global_shader_parameter_set("global_snow_cap_flatness_start", environment_config.snow_cap_flatness_start) RenderingServer.global_shader_parameter_set("global_snow_cap_flatness_end", environment_config.snow_cap_flatness_end) RenderingServer.global_shader_parameter_set("global_snow_cap_noise_scale", environment_config.snow_cap_noise_scale) RenderingServer.global_shader_parameter_set("global_snow_cap_noise_strength", environment_config.snow_cap_noise_strength) RenderingServer.global_shader_parameter_set("global_snow_start_time", -1.0) RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0) func init_snow_amount(value: float): actual_snow_amount = value RenderingServer.global_shader_parameter_set("global_snow_amount", value) func start_snow_accumulation() -> void: RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0) RenderingServer.global_shader_parameter_set("global_snow_start_time", Time.get_ticks_msec() / 1000.0) func start_snow_melt() -> void: RenderingServer.global_shader_parameter_set("global_snow_melt_time", Time.get_ticks_msec() / 1000.0) RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed) #endregion #region Post-Process func toggle_dust(value: bool) -> void: if environment_dust: environment_dust.visible = value func toggle_blur(value: bool) -> void: if blur: blur.visible = value ApplyPostProcessBlurConfig() func toggle_fog(value: bool) -> void: if fog: fog.visible = value func toggle_shadows(value: bool) -> void: if environment_shadows: environment_shadows.visible = value func ApplyPostProcessBlurConfig() -> void: if blur == null: return var blur_material := blur.material as ShaderMaterial if blur_material: blur_material.set_shader_parameter("blur_amount", environment_config.blur_amount) func _apply_dust_config() -> void: var dust_color: Color = environment_config.dust_color var dust_speed: float = environment_config.dust_speed var dust_density: float = environment_config.dust_density var dust_size_min: float = environment_config.dust_size_min var dust_size_max: float = environment_config.dust_size_max if environment_dust: var dust_mat = environment_dust.material as ShaderMaterial if dust_mat: dust_mat.set_shader_parameter("dust_color", dust_color) dust_mat.set_shader_parameter("dust_speed", dust_speed) dust_mat.set_shader_parameter("dust_density", dust_density) dust_mat.set_shader_parameter("dust_size_min", dust_size_min) dust_mat.set_shader_parameter("dust_size_max", dust_size_max) #endregion