diff --git a/scenes/Grid/day_night_controller.gd b/scenes/Grid/day_night_controller.gd index 1843312..32b6eda 100644 --- a/scenes/Grid/day_night_controller.gd +++ b/scenes/Grid/day_night_controller.gd @@ -2,6 +2,8 @@ extends DirectionalLight3D class_name DayNightController +signal time_changed(current_hours: float) + @export var grid_manager_path: NodePath @export_range(1.0, 48.0, 0.5) var day_length_hours: float = 12.0 @export_range(1.0, 600.0, 1.0) var real_seconds_per_game_hour: float = 60.0 @@ -11,12 +13,17 @@ class_name DayNightController var _grid_manager: Node3D = null var _time_of_day_hours: float = 0.0 +var _initial_environment_settings: Dictionary = {} +var _sunlight_multiplier: float = 1.0 func _ready() -> void: set_process(true) _resolve_references() _time_of_day_hours = clamp(start_time_of_day_hours, 0.0, day_length_hours) _apply_sun_lighting() + _emit_time_changed() + _capture_initial_environment() + _update_environment() func _process(delta: float) -> void: if Engine.is_editor_hint(): @@ -25,6 +32,8 @@ func _process(delta: float) -> void: return _time_of_day_hours = fposmod(_time_of_day_hours + delta / real_seconds_per_game_hour, day_length_hours) _apply_sun_lighting() + _emit_time_changed() + _update_environment() func _resolve_references() -> void: if grid_manager_path != NodePath(): @@ -51,7 +60,8 @@ func _apply_sun_lighting() -> void: if direction.is_equal_approx(up_vector) or direction.is_equal_approx(-up_vector): up_vector = Vector3.FORWARD look_at_from_position(sun_position, target, up_vector) - var daylight: float = clamp(direction.y * 0.5 + 0.5, 0.0, 1.0) + var daylight_phase: float = sin((sun_angle - TAU * 0.25)) + var daylight: float = clamp(daylight_phase * 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) @@ -59,3 +69,41 @@ func _apply_sun_lighting() -> void: light_color = night_color.lerp(warm_mix, daylight) light_energy = lerp(0.05, 1.25, daylight) shadow_enabled = daylight > 0.1 + _sunlight_multiplier = daylight + +func get_time_of_day_hours() -> float: + return _time_of_day_hours + +func get_day_length_hours() -> float: + return day_length_hours + +func _emit_time_changed() -> void: + emit_signal("time_changed", _time_of_day_hours) + +func _capture_initial_environment() -> void: + var world: World3D = get_world_3d() + if not world: + return + var env: Environment = world.environment + if env: + _initial_environment_settings = { + "ambient_light_color": env.ambient_light_color, + "ambient_light_energy": env.ambient_light_energy, + "background_color": env.background_color + } + +func _update_environment() -> void: + var world: World3D = get_world_3d() + if not world: + return + var env: Environment = world.environment + if not env: + return + var daylight: float = clamp(_sunlight_multiplier, 0.0, 1.0) + var ambient_day: Color = Color(0.6, 0.7, 0.85) + var ambient_night: Color = Color(0.02, 0.05, 0.1) + var background_day: Color = Color(0.5, 0.75, 1.0) + var background_night: Color = Color(0.01, 0.02, 0.08) + env.ambient_light_color = ambient_night.lerp(ambient_day, daylight) + env.ambient_light_energy = lerp(0.15, 1.5, daylight) + env.background_color = background_night.lerp(background_day, daylight) diff --git a/scenes/Grid/grid_character_controller.gd b/scenes/Grid/grid_character_controller.gd index 5ff3126..1df0420 100644 --- a/scenes/Grid/grid_character_controller.gd +++ b/scenes/Grid/grid_character_controller.gd @@ -7,12 +7,14 @@ class_name GridCharacterController @export var start_cell: Vector2i = Vector2i.ZERO @export_range(0.1, 20.0, 0.1) var move_speed: float = 4.0 @export_range(0.0, 2.0, 0.01) var height_offset: float = 0.3 +@export var home_marker_scene: PackedScene var _grid_manager: GridPlaneManager = null var _camera: Camera3D = null var _current_cell: Vector2i = Vector2i(-1, -1) var _target_position: Vector3 var _is_moving: bool = false +var _home_instance: Node3D = null func _ready() -> void: set_physics_process(true) @@ -21,6 +23,7 @@ func _ready() -> void: if _grid_manager: _grid_manager.grid_layout_changed.connect(_on_grid_layout_changed) _move_to_cell(start_cell, true) + _spawn_home() func _physics_process(delta: float) -> void: if not _is_moving: @@ -89,6 +92,7 @@ func _on_grid_layout_changed(_cells: Dictionary) -> void: clamp(_current_cell.y, 0, _grid_manager.rows - 1) ) _move_to_cell(_current_cell, true) + _update_home_position() func _resolve_references() -> void: if grid_manager_path != NodePath(): @@ -97,3 +101,37 @@ func _resolve_references() -> void: _grid_manager = get_parent() as GridPlaneManager if camera_path != NodePath(): _camera = get_node_or_null(camera_path) as Camera3D + if not _home_instance and home_marker_scene: + _spawn_home() + +func _spawn_home() -> void: + if not home_marker_scene or not _grid_manager: + return + if _home_instance and is_instance_valid(_home_instance): + _home_instance.queue_free() + var new_home := home_marker_scene.instantiate() + if not new_home: + return + if not (new_home is Node3D): + new_home.queue_free() + return + _home_instance = new_home + var parent := get_parent() + if parent: + call_deferred("_add_home_to_parent", parent) + +func _add_home_to_parent(parent: Node) -> void: + if not parent or not _home_instance: + return + if _home_instance.get_parent() == parent: + _update_home_position() + return + parent.add_child(_home_instance) + _update_home_position() + +func _update_home_position() -> void: + if not _home_instance or not _grid_manager or not _grid_manager.has_cell(start_cell): + return + var local_center := _grid_manager.cell_to_world(start_cell) + var world_center := _grid_manager.to_global(local_center) + _home_instance.global_position = world_center + Vector3.UP * 0.01 diff --git a/scenes/Grid/grid_field.tscn b/scenes/Grid/grid_field.tscn index f1cf7e4..534a952 100644 --- a/scenes/Grid/grid_field.tscn +++ b/scenes/Grid/grid_field.tscn @@ -1,19 +1,21 @@ -[gd_scene load_steps=14 format=4 uid="uid://qd6xvgwrd00g"] +[gd_scene load_steps=17 format=4 uid="uid://qd6xvgwrd00g"] -[ext_resource type="Script" path="res://scenes/Grid/grid_plane_manager.gd" id="1_72cxc"] -[ext_resource type="Script" path="res://scenes/Grid/grid_camera_controller.gd" id="2_o2iv9"] -[ext_resource type="Script" path="res://scenes/Grid/grid_highlight_controller.gd" id="3_n2b7o"] -[ext_resource type="Script" path="res://scenes/Grid/day_night_controller.gd" id="4_u8bvi"] -[ext_resource type="Script" path="res://scenes/Grid/grid_character_controller.gd" id="5_n4d0h"] +[ext_resource type="Script" uid="uid://3goclr4srt7k" path="res://scenes/Grid/grid_plane_manager.gd" id="1_72cxc"] +[ext_resource type="Script" uid="uid://5p4mcxw7wann" path="res://scenes/Grid/grid_camera_controller.gd" id="2_o2iv9"] +[ext_resource type="Script" uid="uid://ehef5rrel4d6" path="res://scenes/Grid/grid_highlight_controller.gd" id="3_n2b7o"] +[ext_resource type="Script" uid="uid://oy8cl8dscrh2" path="res://scenes/Grid/day_night_controller.gd" id="4_u8bvi"] +[ext_resource type="Script" uid="uid://6asq70b60kif" path="res://scenes/Grid/grid_character_controller.gd" id="5_n4d0h"] +[ext_resource type="Script" uid="uid://24uoe7hanwp2" path="res://scenes/Grid/time_display.gd" id="6_8n3rl"] +[ext_resource type="PackedScene" path="res://scenes/Grid/grid_home_marker.tscn" id="7_1vmu7"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ground"] albedo_color = Color(0.211765, 0.364706, 0.211765, 1) [sub_resource type="PlaneMesh" id="PlaneMesh_ground"] -size = Vector2(146.06345, 116.8072) +size = Vector2(166.33133, 166.33133) [sub_resource type="BoxShape3D" id="BoxShape3D_ground"] -size = Vector3(146.06345, 0.4, 116.8072) +size = Vector3(166.33133, 0.4, 166.33133) [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_grid"] no_depth_test = true @@ -21,7 +23,7 @@ shading_mode = 0 vertex_color_use_as_albedo = true albedo_color = Color(0.811765, 0.917647, 1, 0.74902) -[sub_resource type="ArrayMesh" id="ArrayMesh_pxg5e"] +[sub_resource type="ArrayMesh" id="ArrayMesh_ot7o0"] _surfaces = [{ "aabb": AABB(-5, 0.02, -5, 10, 1e-05, 10), "attribute_data": PackedByteArray("M7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6Uzsv+lM7L/pTOy/6U="), @@ -38,15 +40,15 @@ no_depth_test = true shading_mode = 0 albedo_color = Color(0.976471, 0.843137, 0.333333, 0.6) -[sub_resource type="PlaneMesh" id="PlaneMesh_dce6m"] +[sub_resource type="PlaneMesh" id="PlaneMesh_1wejn"] size = Vector2(1, 1) -[sub_resource type="SphereMesh" id="SphereMesh_character"] -radius = 0.35 - [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_character"] albedo_color = Color(0.941176, 0.403922, 0.262745, 1) +[sub_resource type="SphereMesh" id="SphereMesh_character"] +radius = 0.35 + [node name="GridField" type="Node3D"] script = ExtResource("1_72cxc") columns = 10 @@ -73,15 +75,17 @@ shape = SubResource("BoxShape3D_ground") unique_name_in_owner = true material_override = SubResource("StandardMaterial3D_grid") cast_shadow = 0 -mesh = SubResource("ArrayMesh_pxg5e") +mesh = SubResource("ArrayMesh_ot7o0") [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] unique_name_in_owner = true -transform = Transform3D(-4.37114e-08, -1.0000001, -4.3711392e-08, 0, -4.3711392e-08, 1.0000001, -1.0000002, 4.3711392e-08, 1.9106857e-15, 5.165678e-06, 60, 9.1084837e-07) +transform = Transform3D(1.0000002, 1.306986e-15, 5.713018e-23, 0, -4.3711392e-08, 1.0000001, 1.3069862e-15, -1.0000001, -4.3711392e-08, 5.165678e-06, 60, 9.1084837e-07) light_color = Color(0.12, 0.18, 0.35, 1) light_energy = 0.05 script = ExtResource("4_u8bvi") grid_manager_path = NodePath("..") +day_length_hours = 24.0 +real_seconds_per_game_hour = 5.0 [node name="Camera3D" type="Camera3D" parent="."] unique_name_in_owner = true @@ -98,19 +102,38 @@ unique_name_in_owner = true visible = false material_override = SubResource("StandardMaterial3D_highlight") cast_shadow = 0 -mesh = SubResource("PlaneMesh_dce6m") +mesh = SubResource("PlaneMesh_1wejn") script = ExtResource("3_n2b7o") grid_manager_path = NodePath("..") camera_path = NodePath("../Camera3D") [node name="GridCharacter" type="Node3D" parent="."] unique_name_in_owner = true +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.5, 0.3, -4.5) script = ExtResource("5_n4d0h") grid_manager_path = NodePath("..") camera_path = NodePath("../Camera3D") -start_cell = Vector2i(0, 0) move_speed = 5.0 +home_marker_scene = ExtResource("7_1vmu7") [node name="Mesh" type="MeshInstance3D" parent="GridCharacter"] -mesh = SubResource("SphereMesh_character") material_override = SubResource("StandardMaterial3D_character") +mesh = SubResource("SphereMesh_character") + +[node name="HUD" type="CanvasLayer" parent="."] + +[node name="TimeLabel" type="Label" parent="HUD"] +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -220.0 +offset_top = 20.0 +offset_right = -20.0 +offset_bottom = 60.0 +grow_horizontal = 0 +theme_override_font_sizes/font_size = 28 +text = "06:00" +horizontal_alignment = 2 +vertical_alignment = 1 +script = ExtResource("6_8n3rl") +day_night_controller_path = NodePath("../../DirectionalLight3D") diff --git a/scenes/Grid/grid_home_marker.tscn b/scenes/Grid/grid_home_marker.tscn new file mode 100644 index 0000000..d1d7ae1 --- /dev/null +++ b/scenes/Grid/grid_home_marker.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=4 format=4 uid="uid://r703rwsvxsx2"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_home"] +albedo_color = Color(0.196078, 0.643137, 0.909804, 1) +metallic = 0.0 +roughness = 1.0 + +[sub_resource type="CylinderMesh" id="CylinderMesh_home"] +radius = 0.45 +height = 0.05 + +[node name="GridHome" type="MeshInstance3D"] +mesh = SubResource("CylinderMesh_home") +material_override = SubResource("StandardMaterial3D_home") +cast_shadow = 0 diff --git a/scenes/Grid/time_display.gd b/scenes/Grid/time_display.gd new file mode 100644 index 0000000..7456ad4 --- /dev/null +++ b/scenes/Grid/time_display.gd @@ -0,0 +1,56 @@ +@tool +extends Label +class_name TimeDisplay + +@export var day_night_controller_path: NodePath +@export var display_enabled: bool = true + +var _day_night_controller: DayNightController = null + +func _ready() -> void: + set_process(true) + _resolve_references() + _connect_controller() + _update_visibility() + _update_text() + +func _process(_delta: float) -> void: + if Engine.is_editor_hint(): + _update_text() + +func set_display_enabled(value: bool) -> void: + display_enabled = value + _update_visibility() + _update_text() + +func _resolve_references() -> void: + if day_night_controller_path != NodePath(): + _day_night_controller = get_node_or_null(day_night_controller_path) as DayNightController + else: + _day_night_controller = get_parent() as DayNightController + +func _connect_controller() -> void: + if _day_night_controller and not _day_night_controller.is_connected("time_changed", Callable(self, "_on_time_changed")): + _day_night_controller.time_changed.connect(_on_time_changed) + +func _on_time_changed(_hours: float) -> void: + _update_text() + +func _update_visibility() -> void: + visible = display_enabled and _day_night_controller != null + +func _update_text() -> void: + if not display_enabled or not _day_night_controller: + text = "" + return + var hours: float = _day_night_controller.get_time_of_day_hours() + var total_hours: float = max(_day_night_controller.get_day_length_hours(), 0.001) + var clamped_hours: float = clamp(hours, 0.0, total_hours) + var whole_hours: int = int(clamped_hours) + var minutes: int = int(round((clamped_hours - float(whole_hours)) * 60.0)) + if minutes == 60: + whole_hours += 1 + minutes = 0 + if whole_hours >= int(total_hours): + whole_hours = 0 + text = "%02d:%02d" % [whole_hours, minutes] diff --git a/scenes/Grid/time_display.gd.uid b/scenes/Grid/time_display.gd.uid new file mode 100644 index 0000000..587ec2e --- /dev/null +++ b/scenes/Grid/time_display.gd.uid @@ -0,0 +1 @@ +uid://24uoe7g9nwp2