class_name DayNightCycleComponent extends Node signal end_of_day signal pause_time signal resume_time signal set_day_length(length_in_seconds: float) signal set_rate_of_time(rate: float) ## 2.0 for 2x signal set_time(time: float) ## Time should be between 0 and 1 @export var day_length: float = 60.0 ## Day length in seconds @export var start_time: float = 0.3 ## Between 0-1 (0.3 is morning, 0.5 noon) @export var time_paused: bool = false @export_group("Colors and Intensity") @export var moon_color: Gradient @export var moon_intensity: Curve @export var sun_color: Gradient @export var sun_intensity: Curve @export var sky_top_color: Gradient @export var sky_horizon_color: Gradient @export var ground_bottom_color: Gradient @export var ground_horizon_color: Gradient @export_group("Node Exports") @export var environment: WorldEnvironment @export var sun: DirectionalLight3D @export var moon: DirectionalLight3D @onready var tick_rate: float = 1.0 / day_length @onready var time: float = start_time ## Between 0-1 (0.5 - noon) func _process(delta: float) -> void: if time_paused: return time += tick_rate * delta if time >= 1.0: time = 0.0 end_of_day.emit() # 90 to fix alignment sun.rotation_degrees.x = time * 360 + 90 sun.light_color = sun_color.sample(time) sun.light_energy = sun_intensity.sample(time) # 90 to fix alignment moon.rotation_degrees.x = time * 360 + 90 + 180 # 180 for opposite of sun moon.light_color = moon_color.sample(time) moon.light_energy = moon_intensity.sample(time) # Show / Hide Sun and Moon sun.visible = sun.light_energy > 0 moon.visible = moon.light_energy > 0 # Sky and Ground Colors environment.environment.sky.sky_material.set("sky_top_color", sky_top_color.sample(time)) environment.environment.sky.sky_material.set("sky_horizon_color", sky_horizon_color.sample(time)) environment.environment.sky.sky_material.set("ground_bottom_color", ground_bottom_color.sample(time)) environment.environment.sky.sky_material.set("ground_horizon_color", ground_horizon_color.sample(time)) func _ready() -> void: pause_time.connect(_on_pause_time) resume_time.connect(_on_resume_time) set_day_length.connect(_on_set_day_length) set_rate_of_time.connect(_on_set_rate_of_time) set_time.connect(_on_set_time) func update_tick_rate(new_rate: float = 1.0) -> void: tick_rate = new_rate / day_length func _on_pause_time() -> void: time_paused = true func _on_resume_time() -> void: time_paused = true func _on_set_day_length(seconds: float) -> void: day_length = seconds update_tick_rate() func _on_set_rate_of_time(new_rate: float) -> void: update_tick_rate(new_rate) func _on_set_time(new_time: float) -> void: time = new_time