Files
Trinittu/dynamic-sky/scripts/day_night_controller.gd
Overside srl b158a646c3 revert
2026-02-17 08:37:55 +01:00

370 lines
11 KiB
GDScript

@tool
class_name DayNightController
extends Node
signal time_changed(time_of_day: float)
signal hour_changed(hour: int)
signal day_changed(day: int)
signal sunrise_started()
signal sunset_started()
signal night_started()
signal noon_reached()
const HOURS_PER_DAY := 24.0
const SUNRISE_START := 0.2 # ~5 AM
const SUNRISE_END := 0.3 # ~7 AM
const SUNSET_START := 0.75 # ~6 PM
const SUNSET_END := 0.85 # ~8 PM
const NOON := 0.5
@export_group("Time Settings")
@export var time_of_day: float = 0.25:
set(value):
var old_hour := get_current_hour()
time_of_day = wrapf(value, 0.0, 1.0)
var new_hour := get_current_hour()
if old_hour != new_hour:
hour_changed.emit(new_hour)
time_changed.emit(time_of_day)
_check_time_events(old_hour, new_hour)
@export var day_length_minutes: float = 30.0:
set(value):
day_length_minutes = clampf(value, 1.0, 1440.0)
@export var paused: bool = false
@export var time_scale: float = 1.0
@export var current_day: int = 1
@export_group("Sun Arc")
@export var sun_arc_tilt: float = 23.5
@export var sun_arc_offset: float = 0.0
@export_group("Moon Arc")
@export var moon_arc_tilt: float = 15.0
@export var moon_arc_offset: float = 180.0
@export var moon_phase: float = 0.0
@export_group("Sun Curves")
@export var sun_color_curve: Gradient
@export var sun_intensity_curve: Curve
@export_group("Moon Curves")
@export var moon_color_curve: Gradient
@export var moon_intensity_curve: Curve
@export_group("Ambient Curves")
@export var ambient_color_curve: Gradient
@export var ambient_intensity_curve: Curve
@export_group("Fog Curves")
@export var fog_color_curve: Gradient
@export var fog_density_curve: Curve
@export_group("Sky Gradient Curves")
@export var sky_top_color_curve: Gradient
@export var sky_horizon_color_curve: Gradient
@export var sky_bottom_color_curve: Gradient
@export_group("Stars")
@export var stars_visibility_curve: Curve
var _last_hour: int = -1
var _sunrise_emitted := false
var _sunset_emitted := false
var _night_emitted := false
var _noon_emitted := false
func _ready() -> void:
_initialize_default_curves()
_last_hour = get_current_hour()
func _process(delta: float) -> void:
if paused:
return
var time_increment := delta / (day_length_minutes * 60.0) * time_scale
var old_time := time_of_day
time_of_day += time_increment
if time_of_day < old_time:
current_day += 1
day_changed.emit(current_day)
_reset_time_events()
func _initialize_default_curves() -> void:
if sun_color_curve == null:
sun_color_curve = Gradient.new()
sun_color_curve.set_color(0, Color(1.0, 0.6, 0.4)) # Dawn
sun_color_curve.add_point(0.25, Color(1.0, 0.95, 0.85)) # Morning
sun_color_curve.add_point(0.5, Color(1.0, 1.0, 0.95)) # Noon
sun_color_curve.add_point(0.75, Color(1.0, 0.7, 0.4)) # Sunset
sun_color_curve.set_color(1, Color(1.0, 0.5, 0.3)) # Dusk
if sun_intensity_curve == null:
sun_intensity_curve = Curve.new()
sun_intensity_curve.add_point(Vector2(0.0, 0.0))
sun_intensity_curve.add_point(Vector2(0.2, 0.0))
sun_intensity_curve.add_point(Vector2(0.3, 0.8))
sun_intensity_curve.add_point(Vector2(0.5, 1.0))
sun_intensity_curve.add_point(Vector2(0.7, 0.8))
sun_intensity_curve.add_point(Vector2(0.85, 0.0))
sun_intensity_curve.add_point(Vector2(1.0, 0.0))
if moon_color_curve == null:
moon_color_curve = Gradient.new()
moon_color_curve.set_color(0, Color(0.7, 0.8, 1.0))
moon_color_curve.set_color(1, Color(0.7, 0.8, 1.0))
if moon_intensity_curve == null:
moon_intensity_curve = Curve.new()
moon_intensity_curve.add_point(Vector2(0.0, 0.4))
moon_intensity_curve.add_point(Vector2(0.15, 0.3))
moon_intensity_curve.add_point(Vector2(0.22, 0.0))
moon_intensity_curve.add_point(Vector2(0.85, 0.0))
moon_intensity_curve.add_point(Vector2(0.92, 0.3))
moon_intensity_curve.add_point(Vector2(1.0, 0.4))
if ambient_color_curve == null:
ambient_color_curve = Gradient.new()
ambient_color_curve.set_color(0, Color(0.15, 0.18, 0.3)) # Night
ambient_color_curve.add_point(0.25, Color(0.5, 0.55, 0.65)) # Morning
ambient_color_curve.add_point(0.5, Color(0.6, 0.65, 0.75)) # Noon
ambient_color_curve.add_point(0.75, Color(0.55, 0.5, 0.55)) # Evening
ambient_color_curve.set_color(1, Color(0.15, 0.18, 0.3)) # Night
if ambient_intensity_curve == null:
ambient_intensity_curve = Curve.new()
ambient_intensity_curve.add_point(Vector2(0.0, 0.05))
ambient_intensity_curve.add_point(Vector2(0.2, 0.1))
ambient_intensity_curve.add_point(Vector2(0.3, 0.5))
ambient_intensity_curve.add_point(Vector2(0.5, 0.6))
ambient_intensity_curve.add_point(Vector2(0.7, 0.5))
ambient_intensity_curve.add_point(Vector2(0.85, 0.1))
ambient_intensity_curve.add_point(Vector2(1.0, 0.05))
if fog_color_curve == null:
fog_color_curve = Gradient.new()
fog_color_curve.set_color(0, Color(0.1, 0.12, 0.2))
fog_color_curve.add_point(0.25, Color(0.6, 0.65, 0.75))
fog_color_curve.add_point(0.5, Color(0.7, 0.75, 0.85))
fog_color_curve.add_point(0.75, Color(0.7, 0.55, 0.5))
fog_color_curve.set_color(1, Color(0.1, 0.12, 0.2))
if fog_density_curve == null:
fog_density_curve = Curve.new()
fog_density_curve.add_point(Vector2(0.0, 0.02))
fog_density_curve.add_point(Vector2(0.25, 0.015))
fog_density_curve.add_point(Vector2(0.5, 0.01))
fog_density_curve.add_point(Vector2(0.75, 0.015))
fog_density_curve.add_point(Vector2(1.0, 0.02))
if sky_top_color_curve == null:
sky_top_color_curve = Gradient.new()
sky_top_color_curve.set_color(0, Color(0.01, 0.01, 0.04)) # Midnight
sky_top_color_curve.add_point(0.2, Color(0.03, 0.05, 0.1)) # Pre-dawn
sky_top_color_curve.add_point(0.3, Color(0.18, 0.35, 0.8)) # Morning
sky_top_color_curve.add_point(0.5, Color(0.15, 0.35, 0.82)) # Noon
sky_top_color_curve.add_point(0.75, Color(0.12, 0.15, 0.4)) # Sunset
sky_top_color_curve.add_point(0.85, Color(0.02, 0.02, 0.06)) # Dusk end
sky_top_color_curve.set_color(1, Color(0.01, 0.01, 0.04)) # Midnight
if sky_horizon_color_curve == null:
sky_horizon_color_curve = Gradient.new()
sky_horizon_color_curve.set_color(0, Color(0.03, 0.04, 0.08)) # Midnight
sky_horizon_color_curve.add_point(0.2, Color(0.3, 0.22, 0.28)) # Pre-dawn
sky_horizon_color_curve.add_point(0.25, Color(0.85, 0.55, 0.45))# Dawn
sky_horizon_color_curve.add_point(0.35, Color(0.45, 0.6, 0.85))# Morning
sky_horizon_color_curve.add_point(0.5, Color(0.5, 0.65, 0.88)) # Noon
sky_horizon_color_curve.add_point(0.75, Color(0.95, 0.45, 0.25))# Sunset
sky_horizon_color_curve.add_point(0.85, Color(0.06, 0.06, 0.1))# Dusk end
sky_horizon_color_curve.set_color(1, Color(0.03, 0.04, 0.08)) # Midnight
if sky_bottom_color_curve == null:
sky_bottom_color_curve = Gradient.new()
sky_bottom_color_curve.set_color(0, Color(0.02, 0.02, 0.05)) # Midnight
sky_bottom_color_curve.add_point(0.2, Color(0.12, 0.1, 0.15)) # Pre-dawn
sky_bottom_color_curve.add_point(0.3, Color(0.35, 0.45, 0.55)) # Morning
sky_bottom_color_curve.add_point(0.5, Color(0.35, 0.45, 0.55)) # Noon
sky_bottom_color_curve.add_point(0.75, Color(0.3, 0.2, 0.2)) # Sunset
sky_bottom_color_curve.add_point(0.85, Color(0.03, 0.03, 0.06))# Dusk end
sky_bottom_color_curve.set_color(1, Color(0.02, 0.02, 0.05)) # Midnight
if stars_visibility_curve == null:
stars_visibility_curve = Curve.new()
stars_visibility_curve.add_point(Vector2(0.0, 1.0))
stars_visibility_curve.add_point(Vector2(0.2, 0.8))
stars_visibility_curve.add_point(Vector2(0.3, 0.0))
stars_visibility_curve.add_point(Vector2(0.7, 0.0))
stars_visibility_curve.add_point(Vector2(0.85, 0.8))
stars_visibility_curve.add_point(Vector2(1.0, 1.0))
func _check_time_events(old_hour: int, new_hour: int) -> void:
if time_of_day >= SUNRISE_START and time_of_day < SUNRISE_END and not _sunrise_emitted:
_sunrise_emitted = true
sunrise_started.emit()
if time_of_day >= SUNSET_START and time_of_day < SUNSET_END and not _sunset_emitted:
_sunset_emitted = true
sunset_started.emit()
if time_of_day >= SUNSET_END and not _night_emitted:
_night_emitted = true
night_started.emit()
if time_of_day >= NOON - 0.01 and time_of_day < NOON + 0.01 and not _noon_emitted:
_noon_emitted = true
noon_reached.emit()
func _reset_time_events() -> void:
_sunrise_emitted = false
_sunset_emitted = false
_night_emitted = false
_noon_emitted = false
func get_current_hour() -> int:
return int(time_of_day * HOURS_PER_DAY)
func get_current_hour_float() -> float:
return time_of_day * HOURS_PER_DAY
func set_time_from_hours(hours: float) -> void:
time_of_day = fmod(hours, HOURS_PER_DAY) / HOURS_PER_DAY
func get_sun_direction() -> Vector3:
var angle := (time_of_day - 0.25) * TAU
var tilt_rad := deg_to_rad(sun_arc_tilt)
var offset_rad := deg_to_rad(sun_arc_offset)
var direction := Vector3(
cos(angle + offset_rad),
sin(angle),
sin(angle) * sin(tilt_rad)
).normalized()
return direction
func get_moon_direction() -> Vector3:
var angle := (time_of_day + 0.25) * TAU
var tilt_rad := deg_to_rad(moon_arc_tilt)
var offset_rad := deg_to_rad(moon_arc_offset)
var direction := Vector3(
cos(angle + offset_rad),
sin(angle),
sin(angle) * sin(tilt_rad)
).normalized()
return direction
func get_sun_color() -> Color:
if sun_color_curve:
return sun_color_curve.sample(time_of_day)
return Color.WHITE
func get_sun_intensity() -> float:
if sun_intensity_curve:
return sun_intensity_curve.sample(time_of_day)
return 1.0
func get_moon_color() -> Color:
if moon_color_curve:
return moon_color_curve.sample(time_of_day)
return Color(0.7, 0.8, 1.0)
func get_moon_intensity() -> float:
var base_intensity := 1.0
if moon_intensity_curve:
base_intensity = moon_intensity_curve.sample(time_of_day)
var phase_factor := 0.5 + 0.5 * cos(moon_phase * TAU)
return base_intensity * phase_factor
func get_ambient_color() -> Color:
if ambient_color_curve:
return ambient_color_curve.sample(time_of_day)
return Color(0.5, 0.55, 0.65)
func get_ambient_intensity() -> float:
if ambient_intensity_curve:
return ambient_intensity_curve.sample(time_of_day)
return 0.5
func get_fog_color() -> Color:
if fog_color_curve:
return fog_color_curve.sample(time_of_day)
return Color(0.7, 0.75, 0.85)
func get_fog_density() -> float:
if fog_density_curve:
return fog_density_curve.sample(time_of_day)
return 0.01
func get_stars_visibility() -> float:
if stars_visibility_curve:
return stars_visibility_curve.sample(time_of_day)
return 0.0
func get_sky_top_color() -> Color:
if sky_top_color_curve:
return sky_top_color_curve.sample(time_of_day)
return Color(0.2, 0.4, 0.8)
func get_sky_horizon_color() -> Color:
if sky_horizon_color_curve:
return sky_horizon_color_curve.sample(time_of_day)
return Color(0.6, 0.7, 0.9)
func get_sky_bottom_color() -> Color:
if sky_bottom_color_curve:
return sky_bottom_color_curve.sample(time_of_day)
return Color(0.4, 0.5, 0.6)
func is_daytime() -> bool:
return time_of_day >= SUNRISE_END and time_of_day < SUNSET_START
func is_nighttime() -> bool:
return time_of_day < SUNRISE_START or time_of_day >= SUNSET_END
func is_dawn() -> bool:
return time_of_day >= SUNRISE_START and time_of_day < SUNRISE_END
func is_dusk() -> bool:
return time_of_day >= SUNSET_START and time_of_day < SUNSET_END
func get_time_period() -> String:
if is_dawn():
return "dawn"
elif is_dusk():
return "dusk"
elif is_daytime():
return "day"
else:
return "night"