diff --git a/scenes/Grid/grid_field.tscn b/scenes/Grid/grid_field.tscn index 5653df4..0a43f97 100644 --- a/scenes/Grid/grid_field.tscn +++ b/scenes/Grid/grid_field.tscn @@ -66,6 +66,7 @@ cast_shadow = 0 mesh = SubResource("ArrayMesh_q3k88") [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +unique_name_in_owner = true transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 5, 0) shadow_enabled = true diff --git a/scenes/Grid/grid_plane_manager.gd b/scenes/Grid/grid_plane_manager.gd index 01704e5..b2be452 100644 --- a/scenes/Grid/grid_plane_manager.gd +++ b/scenes/Grid/grid_plane_manager.gd @@ -71,6 +71,31 @@ var _ground_padding: float = 20.0 get: return _ground_padding +var _day_length_hours: float = 12.0 +@export_range(1.0, 48.0, 0.5) var day_length_hours: float = 12.0: + set(value): + value = max(value, 1.0) + if is_equal_approx(value, _day_length_hours): + return + _day_length_hours = value + _time_of_day_hours = clamp(_time_of_day_hours, 0.0, _day_length_hours) + _apply_sun_lighting() + get: + return _day_length_hours + +var _seconds_per_game_hour: float = 60.0 +@export_range(1.0, 600.0, 1.0) var real_seconds_per_game_hour: float = 60.0: + set(value): + value = clamp(value, 1.0, 600.0) + if is_equal_approx(value, _seconds_per_game_hour): + return + _seconds_per_game_hour = value + get: + return _seconds_per_game_hour + +@export_range(0.0, 48.0, 0.25) var start_time_of_day_hours: float = 6.0 +var _time_of_day_hours: float = 0.0 + var _zoom_factor: float = 1.0 var _zoom_min_internal: float = 0.5 var _zoom_max_internal: float = 3.0 @@ -128,6 +153,7 @@ const _SQRT3 := 1.7320508075688772 @onready var _grid_lines: MeshInstance3D = %GridLines @onready var _camera: Camera3D = %Camera3D @onready var _hover_highlight: MeshInstance3D = %HoverHighlight +@onready var _sun_light: DirectionalLight3D = %DirectionalLight3D var _grid_size: Vector2 = Vector2.ZERO var _cells: Dictionary = {} @@ -138,6 +164,7 @@ var _hex_center_offset_local: Vector3 = Vector3.ZERO func _ready() -> void: set_process(true) _zoom_factor = clamp(_zoom_factor, _zoom_min_internal, _zoom_max_internal) + _time_of_day_hours = clamp(start_time_of_day_hours, 0.0, _day_length_hours) _queue_rebuild() func get_cells() -> Dictionary: @@ -181,6 +208,7 @@ func _rebuild_grid() -> void: _update_highlight_mesh() _update_camera_view() _update_ground_assets() + _apply_sun_lighting() emit_signal("grid_layout_changed", _cells) func _update_ground_assets() -> void: @@ -428,11 +456,45 @@ func _compute_required_ground_size() -> Vector2: var padding_vec := Vector2.ONE * _ground_padding return (half_extents + padding_vec) * 2.0 +func _update_day_cycle(delta: float) -> void: + if _day_length_hours <= 0.0 or _seconds_per_game_hour <= 0.0: + return + _time_of_day_hours = fposmod(_time_of_day_hours + delta / _seconds_per_game_hour, _day_length_hours) + _apply_sun_lighting() + +func _apply_sun_lighting() -> void: + if not is_instance_valid(_sun_light): + return + if _day_length_hours <= 0.0: + return + var cycle: float = 0.0 + if _day_length_hours > 0.0: + cycle = fposmod(_time_of_day_hours / _day_length_hours, 1.0) + var sun_angle: float = cycle * TAU + var rotation_axis: Vector3 = Vector3(1.0, 0.0, -1.0).normalized() + if rotation_axis.length() == 0.0: + rotation_axis = Vector3.RIGHT + var direction: Vector3 = Vector3.UP.rotated(rotation_axis, sun_angle) + direction = direction.rotated(Vector3.UP, deg_to_rad(35.0)).normalized() + var target: Vector3 = global_transform.origin + var sun_distance: float = 60.0 + var sun_position: Vector3 = target - direction * sun_distance + _sun_light.look_at_from_position(sun_position, target, Vector3.UP) + var daylight: float = clamp(direction.y * 0.5 + 0.5, 0.0, 1.0) + var dawn_color: Color = Color(0.95, 0.58, 0.32) + var night_color: Color = Color(0.12, 0.18, 0.35) + var day_color: Color = Color(1.0, 0.96, 0.88) + var warm_mix: Color = dawn_color.lerp(day_color, clamp((daylight - 0.25) / 0.5, 0.0, 1.0)) + _sun_light.light_color = night_color.lerp(warm_mix, daylight) + _sun_light.light_energy = lerp(0.05, 1.25, daylight) + _sun_light.shadow_enabled = daylight > 0.1 + func _process(_delta: float) -> void: if Engine.is_editor_hint(): return var mouse_position: Vector2 = get_viewport().get_mouse_position() _update_hovered_cell(mouse_position) + _update_day_cycle(_delta) func _unhandled_input(event: InputEvent) -> void: if Engine.is_editor_hint(): @@ -445,7 +507,7 @@ func _unhandled_input(event: InputEvent) -> void: _adjust_zoom(_zoom_step_internal) func _adjust_zoom(delta: float) -> void: - var previous := _zoom_factor + var previous: float = _zoom_factor _zoom_factor = clamp(_zoom_factor + delta, _zoom_min_internal, _zoom_max_internal) if is_equal_approx(previous, _zoom_factor): return