diff --git a/.gitignore b/.gitignore index 3d6cd30..e6dcc6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Godot 4+ specific ignores .godot/ android/build/ +builds/ # Godot-specific ignores .import/ diff --git a/addons/godot-cdt/libcdt.android.template_debug.arm64.so b/addons/godot-cdt/libcdt.android.template_debug.arm64.so new file mode 100644 index 0000000..c235450 --- /dev/null +++ b/addons/godot-cdt/libcdt.android.template_debug.arm64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b6a62d5ec5e2c9414b983a90041f1d674e092f71a9b5563277d2b6ad552a8d2 +size 6274408 diff --git a/addons/godot-cdt/libcdt.android.template_debug.x86_64.so b/addons/godot-cdt/libcdt.android.template_debug.x86_64.so new file mode 100644 index 0000000..7492fcb --- /dev/null +++ b/addons/godot-cdt/libcdt.android.template_debug.x86_64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70a9f2c799d3d6703bd95abaacdd82c0d1b7a66fc39098aac64c330b0be0db06 +size 5855024 diff --git a/addons/godot-cdt/libcdt.android.template_release.arm64.so b/addons/godot-cdt/libcdt.android.template_release.arm64.so new file mode 100644 index 0000000..936fedd --- /dev/null +++ b/addons/godot-cdt/libcdt.android.template_release.arm64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e679688861d608c244393a7e3366539fa067ca75f71c3efb916d8745423cc7f +size 6003048 diff --git a/addons/godot-cdt/libcdt.android.template_release.x86_64.so b/addons/godot-cdt/libcdt.android.template_release.x86_64.so new file mode 100644 index 0000000..b654783 --- /dev/null +++ b/addons/godot-cdt/libcdt.android.template_release.x86_64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27f82d0c296c1ae8d71754353ee3f9c32955fe7a56ffbd54ca4f171a40827387 +size 5612432 diff --git a/addons/godot-cdt/libcdt.gdextension b/addons/godot-cdt/libcdt.gdextension new file mode 100644 index 0000000..c7ec10c --- /dev/null +++ b/addons/godot-cdt/libcdt.gdextension @@ -0,0 +1,21 @@ +[configuration] + +entry_symbol = "example_library_init" +compatibility_minimum = 4.1 + +[libraries] + +macos.debug = "res://addons/godot-cdt/libcdt.macos.template_debug.framework" +macos.release = "res://addons/godot-cdt/libcdt.macos.template_release.framework" +windows.debug.x86_32 = "res://addons/godot-cdt/libcdt.windows.template_debug.x86_32.dll" +windows.release.x86_32 = "res://addons/godot-cdt/libcdt.windows.template_release.x86_32.dll" +windows.debug.x86_64 = "res://addons/godot-cdt/libcdt.windows.template_debug.x86_64.dll" +windows.release.x86_64 = "res://addons/godot-cdt/libcdt.windows.template_release.x86_64.dll" +linux.debug.x86_64 = "res://addons/godot-cdt/libcdt.linux.template_debug.x86_64.so" +linux.release.x86_64 = "res://addons/godot-cdt/libcdt.linux.template_release.x86_64.so" +linux.debug.arm64 = "res://addons/godot-cdt/libcdt.linux.template_debug.arm64.so" +linux.release.arm64 = "res://addons/godot-cdt/libcdt.linux.template_release.arm64.so" +linux.debug.rv64 = "res://addons/godot-cdt/libcdt.linux.template_debug.rv64.so" +linux.release.rv64 = "res://addons/godot-cdt/libcdt.linux.template_release.rv64.so" +android.debug.arm64 = "res://addons/godot-cdt/libcdt.android.template_debug.arm64.so" +android.release.arm64 = "res://addons/godot-cdt/libcdt.android.template_release.arm64.so" \ No newline at end of file diff --git a/addons/godot-cdt/libcdt.linux.template_debug.x86_64.so b/addons/godot-cdt/libcdt.linux.template_debug.x86_64.so new file mode 100644 index 0000000..a9bfc8a --- /dev/null +++ b/addons/godot-cdt/libcdt.linux.template_debug.x86_64.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95bda34ae6ebb2010c5a5e1bd0ccd994df43e5e5f956e214da3c6adae4521add +size 974176 diff --git a/addons/godot-cdt/libcdt.windows.template_debug.x86_64.dll b/addons/godot-cdt/libcdt.windows.template_debug.x86_64.dll new file mode 100644 index 0000000..aaf3431 --- /dev/null +++ b/addons/godot-cdt/libcdt.windows.template_debug.x86_64.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:418c2ca8e73932710184b3bc4de4b40a32fc7ef0369354f8a08fbacd01155f50 +size 871936 diff --git a/addons/godot-cdt/libcdt.windows.template_debug.x86_64.exp b/addons/godot-cdt/libcdt.windows.template_debug.x86_64.exp new file mode 100644 index 0000000..80a6e58 Binary files /dev/null and b/addons/godot-cdt/libcdt.windows.template_debug.x86_64.exp differ diff --git a/addons/godot-cdt/libcdt.windows.template_debug.x86_64.lib b/addons/godot-cdt/libcdt.windows.template_debug.x86_64.lib new file mode 100644 index 0000000..88cbaee Binary files /dev/null and b/addons/godot-cdt/libcdt.windows.template_debug.x86_64.lib differ diff --git a/addons/godot-cdt/~libcdt.windows.template_debug.x86_64.dll b/addons/godot-cdt/~libcdt.windows.template_debug.x86_64.dll new file mode 100644 index 0000000..aaf3431 --- /dev/null +++ b/addons/godot-cdt/~libcdt.windows.template_debug.x86_64.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:418c2ca8e73932710184b3bc4de4b40a32fc7ef0369354f8a08fbacd01155f50 +size 871936 diff --git a/assets/design.afdesign b/assets/design.afdesign index 768cfee..c636778 100644 --- a/assets/design.afdesign +++ b/assets/design.afdesign @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e54002ccb9b04b9b4fb4642cc3b5fd6512f910e65ecb52e41c117a2345d1d22b -size 17810864 +oid sha256:b117dc5a7537a60ff341010636802131c9aa3b80982130e63d5d94902c002d07 +size 13505995 diff --git a/assets/materials/pointer.png b/assets/materials/pointer.png index 0ba72b0..5a92f4d 100644 --- a/assets/materials/pointer.png +++ b/assets/materials/pointer.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68e2b9d5e723a2009f341e45e2968893dd2a1dd5077fe1d9ba970f01d0d75e02 -size 56989 +oid sha256:9738010a57d2157a53e4f537afbcfb50dd28e9de40bae510621d0ea8c94c5844 +size 51682 diff --git a/content/functions/movable.gd b/content/functions/movable.gd index 8bcf12f..46ad7ad 100644 --- a/content/functions/movable.gd +++ b/content/functions/movable.gd @@ -2,14 +2,34 @@ extends Function class_name Movable +signal on_move(position: Vector3, rotation: Vector3) + +@export var restricted: bool = false +@export var restrict_movement: Callable +@export var lock_rotation: bool = false var hit_node := Node3D.new() func _on_grab_down(event: EventPointer): + if restricted && event.target != get_parent(): + return + event.initiator.node.add_child(hit_node) hit_node.global_transform = get_parent().global_transform func _on_grab_move(_event: EventPointer): - get_parent().global_transform = hit_node.global_transform + if hit_node.get_parent() == null: + return + + if restrict_movement: + get_parent().global_position = restrict_movement.call(hit_node.global_position) + else: + get_parent().global_position = hit_node.global_position + + if !lock_rotation: + get_parent().global_basis = hit_node.global_basis + on_move.emit(get_parent().global_position, get_parent().global_rotation) + else: + on_move.emit(get_parent().global_position, Vector3(0, 0, 0)) func _on_grab_up(event: EventPointer): event.initiator.node.remove_child(hit_node) diff --git a/content/main.gd b/content/main.gd index 8108556..bc873e1 100644 --- a/content/main.gd +++ b/content/main.gd @@ -16,9 +16,8 @@ func _ready(): if OS.get_name() == "Android": # OS.request_permissions() environment.environment.sky.set_material(sky_passthrough) - house.visible = false else: - house.visible = true + RenderingServer.set_debug_generate_wireframes(true) controller_left.button_pressed.connect(func(name): _emit_action(name, true, false) @@ -41,7 +40,9 @@ func _ready(): EventSystem.on_action_down.connect(func(action): if action.name == "menu_button": - _toggle_menu() + toggle_menu() + elif action.name == "by_button": + House.body.mini_view = !House.body.mini_view ) EventSystem.on_focus_in.connect(func(event): @@ -49,8 +50,7 @@ func _ready(): return add_child(keyboard) - if event.previous_target == null: - keyboard.global_transform = menu.get_node("AnimationContainer/KeyboardPlace").global_transform + keyboard.global_transform = menu.get_node("AnimationContainer/KeyboardPlace").global_transform ) EventSystem.on_focus_out.connect(func(event): @@ -60,7 +60,7 @@ func _ready(): remove_child(keyboard) ) -func _toggle_menu(): +func toggle_menu(): if menu.show_menu == false: add_child(menu) menu.global_transform = _get_menu_transform() @@ -98,9 +98,13 @@ func _process(delta): controller_left.position += movement controller_right.position += movement -func _input(evnet): - if Input.is_key_pressed(KEY_M): - _toggle_menu() +func _input(event): + if event is InputEventKey and Input.is_key_pressed(KEY_F10): + var vp = get_viewport() + vp.debug_draw = (vp.debug_draw + 1) % 5 + + if event is InputEventKey and Input.is_key_pressed(KEY_M): + toggle_menu() func _get_menu_transform(): var transform = camera.get_global_transform() diff --git a/content/main.tscn b/content/main.tscn index 2549dfd..302c622 100644 --- a/content/main.tscn +++ b/content/main.tscn @@ -8,8 +8,8 @@ [ext_resource type="PackedScene" uid="uid://ctltchlf2j2r4" path="res://addons/xr-simulator/XRSimulator.tscn" id="5_3qc8g"] [ext_resource type="Material" uid="uid://bf5ina366dwm6" path="res://assets/materials/sky.material" id="5_wgwf8"] [ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="8_du83w"] -[ext_resource type="PackedScene" uid="uid://83lb5p4e0qk0" path="res://content/scenes/house.tscn" id="8_qkrg7"] [ext_resource type="PackedScene" uid="uid://lrehk38exd5n" path="res://content/system/keyboard/keyboard.tscn" id="9_e5n3p"] +[ext_resource type="PackedScene" uid="uid://cbemihbxkd4ll" path="res://content/system/house/house.tscn" id="9_np6mw"] [sub_resource type="Sky" id="Sky_vhymk"] sky_material = ExtResource("5_wgwf8") @@ -78,10 +78,8 @@ transform = Transform3D(0.999998, -0.000514899, -6.55874e-05, 1.96975e-05, 0.163 [node name="Keyboard" parent="." instance=ExtResource("9_e5n3p")] transform = Transform3D(0.499999, -0.000139169, -6.50204e-05, 5.24307e-05, 0.353553, -0.353553, 0.000144383, 0.353553, 0.353553, -0.0199266, 0.550784, -0.47368) -[node name="House" parent="." instance=ExtResource("8_qkrg7")] -transform = Transform3D(0.404247, 0.000180645, 0.914648, 0.00017221, 0.999999, -0.000273614, -0.914648, 0.00026812, 0.404247, -0.343479, 0.000110551, 1.91547) -visible = false - [node name="Rooms" type="Node3D" parent="."] +[node name="House" parent="." instance=ExtResource("9_np6mw")] + [editable path="XROrigin3D/XRControllerLeft"] diff --git a/content/system/armband/armband.gd b/content/system/armband/armband.gd new file mode 100644 index 0000000..c9db1a0 --- /dev/null +++ b/content/system/armband/armband.gd @@ -0,0 +1,15 @@ +extends Node3D + +@onready var menu_button = $Menu +@onready var mini_button = $Mini +@onready var clock = $Clock +@onready var main = $"/root/Main" + +func _ready(): + menu_button.on_button_down.connect(func(): + main.toggle_menu() + ) + + mini_button.on_button_down.connect(func(): + House.body.mini_view = !House.body.mini_view + ) diff --git a/content/system/armband/armband.tscn b/content/system/armband/armband.tscn new file mode 100644 index 0000000..fa24fd9 --- /dev/null +++ b/content/system/armband/armband.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=3 format=3 uid="uid://bexxngoxcegul"] + +[ext_resource type="Script" path="res://content/system/armband/armband.gd" id="1_4tskg"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="1_egcvm"] + +[node name="Armband" type="Node3D"] +transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0) +script = ExtResource("1_4tskg") + +[node name="Menu" parent="." instance=ExtResource("1_egcvm")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.04, 0, 0.04) +label = "menu" +icon = true + +[node name="Mini" parent="." instance=ExtResource("1_egcvm")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.02, 0, 0.04) +label = "view_comfy" +icon = true + +[node name="Clock" type="Label3D" parent="."] +transform = Transform3D(1, 4.37114e-08, 4.37114e-08, -4.37114e-08, -4.37114e-08, 1, 4.37114e-08, -1, -4.37114e-08, 0, 0.02, -0.02) +pixel_size = 0.001 +text = "10:00" diff --git a/content/system/house/align_reference.gd b/content/system/house/align_reference.gd new file mode 100644 index 0000000..92ae08b --- /dev/null +++ b/content/system/house/align_reference.gd @@ -0,0 +1,46 @@ +extends Node3D + +@onready var corner1 = $Corner1 +@onready var corner2 = $Corner1/Corner2 +@onready var edge = $Edge +@onready var marker = $Edge/Marker3D + +@export var disabled: bool: + set(value): + disabled = value + + if !is_node_ready(): await ready + + corner1.get_node("CollisionShape3D").disabled = value + corner2.get_node("CollisionShape3D").disabled = value + edge.get_node("CollisionShape3D").disabled = value + corner1.visible = !value + corner2.visible = !value + edge.visible = !value + +func _ready(): + update_initial_positions() + + corner1.get_node("Movable").on_move.connect(func(position, rotation): + edge.align_to_corners(corner1.global_position, corner2.global_position) + ) + + corner2.get_node("Movable").on_move.connect(func(position, rotation): + edge.align_to_corners(corner1.global_position, corner2.global_position) + ) + + corner2.get_node("Movable").restrict_movement = func(new_position): + new_position.y = corner1.global_position.y + + var delta_new_pos_corner1 = (new_position - corner1.position).normalized() + + return corner1.position + delta_new_pos_corner1 + +func update_initial_positions(): + edge.align_to_corners(corner1.global_position, corner2.global_position) + marker.global_transform = House.body.transform + +func get_new_transform(old_transform: Transform3D): + marker.scale = Vector3(1, 1, 1) + return marker.global_transform + diff --git a/content/system/house/align_reference.tscn b/content/system/house/align_reference.tscn new file mode 100644 index 0000000..4521894 --- /dev/null +++ b/content/system/house/align_reference.tscn @@ -0,0 +1,41 @@ +[gd_scene load_steps=7 format=3 uid="uid://jls16btb8nko"] + +[ext_resource type="Script" path="res://content/system/house/align_reference.gd" id="1_8fatp"] +[ext_resource type="PackedScene" uid="uid://brf6mm2gxj7y2" path="res://content/system/house/room/wall_corner.tscn" id="2_ppkie"] +[ext_resource type="PackedScene" uid="uid://dlj5chj7ndgua" path="res://content/system/house/room/wall_edge.tscn" id="3_6o3xn"] +[ext_resource type="Script" path="res://content/functions/movable.gd" id="3_7ktdq"] +[ext_resource type="Material" uid="uid://dxyuncqxagt28" path="res://content/system/house/room/walls_mini.tres" id="4_jkpj4"] + +[sub_resource type="CylinderMesh" id="CylinderMesh_k2m3v"] +top_radius = 0.001 +bottom_radius = 0.05 +height = 0.1 + +[node name="AlignReference" type="Node3D"] +script = ExtResource("1_8fatp") + +[node name="Corner1" parent="." instance=ExtResource("2_ppkie")] + +[node name="Movable" type="Node" parent="Corner1"] +script = ExtResource("3_7ktdq") +restricted = true +lock_rotation = true + +[node name="Corner2" parent="Corner1" instance=ExtResource("2_ppkie")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0) + +[node name="MeshInstance3D" parent="Corner1/Corner2" index="1"] +transform = Transform3D(-4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0, 1, 0, 0, 0) +material_override = ExtResource("4_jkpj4") +mesh = SubResource("CylinderMesh_k2m3v") + +[node name="Movable" type="Node" parent="Corner1/Corner2"] +script = ExtResource("3_7ktdq") +lock_rotation = true + +[node name="Edge" parent="." instance=ExtResource("3_6o3xn")] +transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0.5, 0, 0) + +[node name="Marker3D" type="Marker3D" parent="Edge"] + +[editable path="Corner1/Corner2"] diff --git a/content/system/house/house.gd b/content/system/house/house.gd new file mode 100644 index 0000000..e5fb4e9 --- /dev/null +++ b/content/system/house/house.gd @@ -0,0 +1,168 @@ +extends Node3D + +const Room = preload("./room/room.tscn") +const RoomType = preload("./room/room.gd") + +@onready var levels = $Levels +@onready var collision_shape = $Levels/CollisionShape3D +@onready var align_reference = $AlignReference + +var fixing_reference: bool = false +var editing_room: RoomType = null +var mini_view: bool = false: + set(value): + mini_view = value + update_mini_view() + +var target_size: float = 1.0 + +func _physics_process(delta): + levels.scale.x = lerp(levels.scale.x, target_size, 10.0 * delta) + levels.scale.y = lerp(levels.scale.y, target_size, 10.0 * delta) + levels.scale.z = lerp(levels.scale.z, target_size, 10.0 * delta) + + +func create_room(room_name: String, level: int) -> RoomType: + if editing_room != null: + editing_room.editable = false + editing_room = null + + var room = Room.instantiate() + room.name = room_name + room.editable = true + editing_room = room + + get_level(level).add_child(room) + + return room + +func edit_room(room_name): + var room = find_room(room_name) + + if room == editing_room: + return + + if editing_room != null: + editing_room.editable = false + editing_room = null + + if room != null: + room.editable = true + editing_room = room + +func is_valid_room(room_name): + var room = find_room(room_name) + + if room == null: + return + + return room.wall_corners.get_child_count() >= 3 + + +func delete_room(room_name): + var room = find_room(room_name) + + if room == null: + return + + if editing_room == room: + editing_room = null + + room.get_parent().remove_child(room) + room.queue_free() + +func is_editiong(room_name): + return editing_room != null && editing_room.name == room_name + +func find_room(room_name): + for level in levels.get_children(): + for room in level.get_children(): + if room.name == room_name: + return room + return null + +func find_room_at(entity_position: Vector3): + for level in levels.get_children(): + for room in level.get_children(): + if room.has_point(entity_position): + return room + return null + +func get_level(level: int): + return levels.get_child(level) + +func get_level_aabb(level: int): + var rooms = get_level(level).get_children() + if rooms.size() == 0: + return AABB() + + var min_pos = rooms[0].get_aabb().position + var max_pos = min_pos + rooms[0].get_aabb().size + + for room in rooms: + var room_min = room.get_aabb().position + var room_max = room_min + room.get_aabb().size + + min_pos.x = min(min_pos.x, room_min.x) + min_pos.y = min(min_pos.y, room_min.y) + min_pos.z = min(min_pos.z, room_min.z) + + max_pos.x = max(max_pos.x, room_max.x) + max_pos.y = max(max_pos.y, room_max.y) + max_pos.z = max(max_pos.z, room_max.z) + + return AABB(min_pos, max_pos - min_pos) + +func get_rooms(level: int): + return get_level(level).get_children() + +func create_entity(entity_id: String, entity_position: Vector3): + var room = find_room_at(entity_position) + + if room == null: + return + + var entity = EntityFactory.create_entity(entity_id) + + if entity == null: + return + + room.add_child(entity) + entity.global_position = entity_position + +func update_mini_view(): + collision_shape.disabled = !mini_view + + if mini_view: + var aabb = get_level_aabb(0) + aabb.position.y = -0.03 + aabb.size.y = 0.06 + var center = aabb.position + aabb.size / 2.0 + + collision_shape.global_position = center + collision_shape.shape.size = aabb.size + else: + levels.position = Vector3(0, 0, 0) + + target_size = 0.1 if mini_view else 1.0 + + for room in get_rooms(0): + room.state_machine.change_to("Mini" if mini_view else "View") + +func edit_reference(): + fixing_reference = false + align_reference.disabled = false + +func fix_reference(): + fixing_reference = true + align_reference.disabled = false + align_reference.update_initial_positions() + +func save_reference(): + if fixing_reference: + var align_transform = align_reference.global_transform + transform = align_reference.get_new_transform(transform) + align_reference.global_transform = align_transform + + align_reference.disabled = true + align_reference.update_initial_positions() \ No newline at end of file diff --git a/content/system/house/house.tscn b/content/system/house/house.tscn new file mode 100644 index 0000000..b17ab66 --- /dev/null +++ b/content/system/house/house.tscn @@ -0,0 +1,27 @@ +[gd_scene load_steps=5 format=3 uid="uid://cbemihbxkd4ll"] + +[ext_resource type="Script" path="res://content/system/house/house.gd" id="1_p8amj"] +[ext_resource type="Script" path="res://content/functions/movable.gd" id="2_w1auk"] +[ext_resource type="PackedScene" uid="uid://jls16btb8nko" path="res://content/system/house/align_reference.tscn" id="3_e1tcn"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_x81up"] + +[node name="House" type="Node3D"] +script = ExtResource("1_p8amj") + +[node name="Levels" type="StaticBody3D" parent="."] + +[node name="Level0" type="Node3D" parent="Levels"] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Levels"] +shape = SubResource("BoxShape3D_x81up") +disabled = true + +[node name="Movable" type="Node" parent="Levels"] +script = ExtResource("2_w1auk") +restricted = true +lock_rotation = true + +[node name="AlignReference" parent="." instance=ExtResource("3_e1tcn")] +visible = false +disabled = true diff --git a/content/ui/menu/room/edge.tres b/content/system/house/room/edge.tres similarity index 100% rename from content/ui/menu/room/edge.tres rename to content/system/house/room/edge.tres diff --git a/content/system/house/room/room.gd b/content/system/house/room/room.gd new file mode 100644 index 0000000..ea0b908 --- /dev/null +++ b/content/system/house/room/room.gd @@ -0,0 +1,53 @@ +extends Node3D + +@onready var wall_corners = $Ceiling/WallCorners +@onready var wall_edges = $Ceiling/WallEdges +@onready var wall_mesh: MeshInstance3D = $WallMesh +@onready var ceiling_mesh: MeshInstance3D = $CeilingMesh +@onready var wall_collisions = $WallCollisions + +@onready var room_floor = $Floor +@onready var room_ceiling = $Ceiling + +@onready var state_machine = $StateMachine + +var editable: bool = false: + set(value): + if !is_node_ready(): await ready + + if value: + state_machine.change_to("Edit") + else: + state_machine.change_to("View") + +func get_corner(index: int) -> MeshInstance3D: + return wall_corners.get_child(index % wall_corners.get_child_count()) + +func get_edge(index: int) -> MeshInstance3D: + return wall_edges.get_child(index % wall_edges.get_child_count()) + +func has_point(point: Vector3) -> bool: + return get_aabb().has_point(point) + +func remove_corner(index: int): + get_corner(index).queue_free() + get_edge(index).queue_free() + +func get_aabb(): + if wall_corners.get_child_count() == 0: + return AABB() + + var min_pos = wall_corners.get_child(0).position + var max_pos = wall_corners.get_child(0).position + + for corner in wall_corners.get_children(): + min_pos.x = min(min_pos.x, corner.position.x) + min_pos.z = min(min_pos.z, corner.position.z) + + max_pos.x = max(max_pos.x, corner.position.x) + max_pos.z = max(max_pos.z, corner.position.z) + + min_pos.y = room_floor.position.y + max_pos.y = room_ceiling.position.y + + return AABB(to_global(min_pos), to_global(max_pos) - to_global(min_pos)) \ No newline at end of file diff --git a/content/system/house/room/room.tscn b/content/system/house/room/room.tscn new file mode 100644 index 0000000..bd0cedd --- /dev/null +++ b/content/system/house/room/room.tscn @@ -0,0 +1,67 @@ +[gd_scene load_steps=11 format=3 uid="uid://bswgmclohuqui"] + +[ext_resource type="Script" path="res://content/system/house/room/room.gd" id="1_fccq0"] +[ext_resource type="Script" path="res://content/functions/clickable.gd" id="1_ugebq"] +[ext_resource type="Material" uid="uid://bbx6fv7jq50tr" path="res://content/system/house/room/walls.tres" id="3_al1ev"] +[ext_resource type="Script" path="res://lib/utils/state_machine/state_machine.gd" id="4_nbbo6"] +[ext_resource type="Script" path="res://content/system/house/room/states/mini.gd" id="6_g4qca"] +[ext_resource type="Script" path="res://content/system/house/room/states/view.gd" id="6_g066t"] +[ext_resource type="Script" path="res://content/system/house/room/states/edit.gd" id="7_ap14h"] + +[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_08sv0"] + +[sub_resource type="ArrayMesh" id="ArrayMesh_7dibq"] + +[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_ap613"] +plane = Plane(0, -1, 0, 0) + +[node name="Room" type="Node3D"] +script = ExtResource("1_fccq0") + +[node name="Floor" type="StaticBody3D" parent="."] +collision_layer = 24 +collision_mask = 0 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor"] +shape = SubResource("WorldBoundaryShape3D_08sv0") + +[node name="Clickable" type="Node" parent="Floor"] +script = ExtResource("1_ugebq") + +[node name="WallMesh" type="MeshInstance3D" parent="."] +material_override = ExtResource("3_al1ev") +mesh = SubResource("ArrayMesh_7dibq") + +[node name="CeilingMesh" type="MeshInstance3D" parent="."] +material_override = ExtResource("3_al1ev") + +[node name="WallCollisions" type="Node3D" parent="."] + +[node name="Ceiling" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0) +collision_layer = 24 +collision_mask = 0 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ceiling"] +shape = SubResource("WorldBoundaryShape3D_ap613") +disabled = true + +[node name="Clickable" type="Node" parent="Ceiling"] +script = ExtResource("1_ugebq") + +[node name="WallCorners" type="Node3D" parent="Ceiling"] + +[node name="WallEdges" type="Node3D" parent="Ceiling"] + +[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("current_state")] +script = ExtResource("4_nbbo6") +current_state = NodePath("View") + +[node name="View" type="Node" parent="StateMachine"] +script = ExtResource("6_g066t") + +[node name="Edit" type="Node" parent="StateMachine"] +script = ExtResource("7_ap14h") + +[node name="Mini" type="Node" parent="StateMachine"] +script = ExtResource("6_g4qca") diff --git a/content/system/house/room/states/edit.gd b/content/system/house/room/states/edit.gd new file mode 100644 index 0000000..05dd188 --- /dev/null +++ b/content/system/house/room/states/edit.gd @@ -0,0 +1,238 @@ +extends RoomState + +const wall_corner_scene = preload("../wall_corner.tscn") +const wall_edge_scene = preload("../wall_edge.tscn") +const RoomState = preload("./room_state.gd") + +var moving = null +var deleting: bool = false +var floor_corner: StaticBody3D = null +var height_corner: StaticBody3D = null +var height_edge: StaticBody3D = null + +func _on_enter(): + room.wall_corners.visible = true + room.wall_edges.visible = true + + if floor_corner != null: + floor_corner.visible = true + height_corner.visible = true + height_edge.visible = true + + room.room_ceiling.get_node("CollisionShape3D").disabled = (floor_corner == null && height_corner == null) + room.room_floor.get_node("CollisionShape3D").disabled = false + + var ceiling_shape = WorldBoundaryShape3D.new() + ceiling_shape.plane = Plane(Vector3.DOWN, 0) + + room.room_ceiling.get_node("CollisionShape3D").shape = ceiling_shape + room.room_floor.get_node("CollisionShape3D").shape = WorldBoundaryShape3D.new() + + room.room_ceiling.get_node("Clickable").on_click.connect(_on_click_ceiling) + room.room_floor.get_node("Clickable").on_click.connect(_on_click_floor) + +func _on_leave(): + room.wall_corners.visible = false + room.wall_edges.visible = false + + if floor_corner != null: + floor_corner.visible = false + height_corner.visible = false + height_edge.visible = false + + room.room_ceiling.get_node("CollisionShape3D").disabled = true + room.room_floor.get_node("CollisionShape3D").disabled = true + + room.room_ceiling.get_node("Clickable").on_click.disconnect(_on_click_ceiling) + room.room_floor.get_node("Clickable").on_click.disconnect(_on_click_floor) + +func _on_click_floor(event): + if floor_corner != null && height_corner != null: + return + + add_floor_corner(event.ray.get_collision_point()) + add_height_corner(event.ray.get_collision_point()) + room.room_ceiling.get_node("CollisionShape3D").disabled = false + +func _on_click_ceiling(event): + if floor_corner == null || height_corner == null || event.target != room.room_ceiling: + return + + var pos = event.ray.get_collision_point() + pos.y = 0 + + add_corner(pos) + +func add_floor_corner(position: Vector3): + floor_corner = wall_corner_scene.instantiate() + floor_corner.position = position + + height_edge = wall_edge_scene.instantiate() + height_edge.align_to_corners(position, position + Vector3.UP * room.room_ceiling.global_position.y) + + floor_corner.get_node("Clickable").on_grab_down.connect(func(event): + if !is_active() || moving != null: + return + + moving = event.target + ) + + floor_corner.get_node("Clickable").on_grab_move.connect(func(event): + if moving == null: + return + + var moving_index = height_corner.get_index() + var direction = -event.ray.global_transform.basis.z + var new_position = room.room_floor.get_node("CollisionShape3D").shape.plane.intersects_ray(event.ray.global_position, direction) + + if new_position == null: + return + + moving.position = new_position + + height_edge.align_to_corners(new_position, new_position + Vector3.UP * room.room_ceiling.global_position.y) + + room.get_corner(moving_index).position.x = new_position.x + room.get_corner(moving_index).position.z = new_position.z + + if room.wall_edges.get_child_count() == 0: + return + + room.get_edge(moving_index).align_to_corners(new_position, room.get_corner(moving_index + 1).position) + room.get_edge(moving_index - 1).align_to_corners(room.get_corner(moving_index - 1).position, new_position) + ) + + floor_corner.get_node("Clickable").on_grab_up.connect(func(_event): + moving = null + ) + + room.add_child(floor_corner) + room.add_child(height_edge) + +func add_height_corner(position: Vector3): + height_corner = wall_corner_scene.instantiate() + height_corner.position.x = position.x + height_corner.position.z = position.z + + height_corner.get_node("Clickable").on_grab_down.connect(func(event): + if !is_active() || moving != null: + return + + moving = event.target + ) + + height_corner.get_node("Clickable").on_grab_move.connect(func(event): + if moving == null: + return + + var direction = -event.ray.global_transform.basis.z + var plane_direction = direction + plane_direction.y = 0 + plane_direction = plane_direction.normalized() * -1 + + var plane = Plane(plane_direction, moving.position) + + var new_position = plane.intersects_ray(event.ray.global_position, direction) + + if new_position == null: + return + + room.room_ceiling.position.y = new_position.y + height_edge.align_to_corners(floor_corner.global_position, height_corner.global_position) + + ) + + height_corner.get_node("Clickable").on_grab_up.connect(func(_event): + moving = null + ) + + room.wall_corners.add_child(height_corner) + +func add_corner(position: Vector3, index: int = -1): + var corner = wall_corner_scene.instantiate() + corner.position.x = position.x + corner.position.z = position.z + + corner.get_node("Clickable").on_grab_down.connect(func(event): + if !is_active() || moving != null: + return + + moving = event.target + ) + + corner.get_node("Clickable").on_grab_move.connect(func(event): + if moving == null: + return + + var moving_index = moving.get_index() + var direction = -event.ray.global_transform.basis.z + var ceiling_plane = Plane(Vector3.DOWN, room.room_ceiling.global_position) + var new_position = ceiling_plane.intersects_ray(event.ray.global_position, direction) + + if new_position == null: + deleting = true + + new_position = event.ray.global_position + direction + + room.get_corner(moving_index).global_position = new_position + + if room.wall_edges.get_child_count() == 0: + return + + room.get_edge(moving_index).align_to_corners(room.get_corner(moving_index - 1).position, room.get_corner(moving_index + 1).position) + room.get_edge(moving_index - 1).transform = room.get_edge(moving_index).transform + + return + + deleting = false + + new_position.y = 0 + + moving.position = new_position + + + if room.wall_edges.get_child_count() == 0: + return + + room.get_edge(moving_index).align_to_corners(new_position, room.get_corner(moving_index + 1).position) + room.get_edge(moving_index - 1).align_to_corners(room.get_corner(moving_index - 1).position, new_position) + ) + + corner.get_node("Clickable").on_grab_up.connect(func(_event): + if deleting: + var moving_index = moving.get_index() + room.remove_corner(moving_index) + + moving = null + deleting = false + ) + + room.wall_corners.add_child(corner) + room.wall_corners.move_child(corner, index) + + var num_corners = room.wall_corners.get_child_count() + + if num_corners > 1: + add_edge(position, room.get_corner(index + 1).position, index) + + if num_corners > 2: + if num_corners != room.wall_edges.get_child_count(): + add_edge(room.get_corner(-2).position, room.get_corner(-1).position, -2) + else: + room.get_edge(index - 1).align_to_corners(room.get_corner(index - 1).position, position) + + +func add_edge(from_pos: Vector3, to_pos: Vector3, index: int = -1): + var edge: StaticBody3D = wall_edge_scene.instantiate() + edge.align_to_corners(from_pos, to_pos) + + edge.get_node("Clickable").on_press_down.connect(func(event): + var point = event.ray.get_collision_point() + point.y = 0 + add_corner(point, edge.get_index() + 1) + ) + + + room.wall_edges.add_child(edge) + room.wall_edges.move_child(edge, index) + return edge \ No newline at end of file diff --git a/content/system/house/room/states/mini.gd b/content/system/house/room/states/mini.gd new file mode 100644 index 0000000..99f17d6 --- /dev/null +++ b/content/system/house/room/states/mini.gd @@ -0,0 +1,41 @@ +extends RoomState + +const RoomState = preload("./room_state.gd") +const walls_mini_material = preload("../walls_mini.tres") +const walls_material = preload("../walls.tres") + +func _on_enter(): + room.wall_mesh.visible = true + room.ceiling_mesh.visible = true + room.wall_mesh.material_override = walls_mini_material + room.room_ceiling.get_node("CollisionShape3D").disabled = true + room.room_floor.get_node("CollisionShape3D").disabled = true + + for collision in room.wall_collisions.get_children(): + collision.get_child(0).disabled = true + + for corner in room.wall_corners.get_children(): + corner.get_node("CollisionShape3D").disabled = true + + for edge in room.wall_edges.get_children(): + edge.get_node("CollisionShape3D").disabled = true + + + +func _on_leave(): + room.wall_mesh.visible = false + room.ceiling_mesh.visible = false + room.wall_mesh.material_override = walls_material + room.room_ceiling.get_node("CollisionShape3D").disabled = false + room.room_floor.get_node("CollisionShape3D").disabled = false + + for collision in room.wall_collisions.get_children(): + collision.get_child(0).disabled = false + + for corner in room.wall_corners.get_children(): + corner.get_node("CollisionShape3D").disabled = false + + for edge in room.wall_edges.get_children(): + edge.get_node("CollisionShape3D").disabled = false + + diff --git a/content/system/house/room/states/room_state.gd b/content/system/house/room/states/room_state.gd new file mode 100644 index 0000000..31e6877 --- /dev/null +++ b/content/system/house/room/states/room_state.gd @@ -0,0 +1,7 @@ +extends State +const Room = preload("res://content/system/house/room/room.gd") + +var room: Room + +func _ready(): + room = get_parent().get_parent() diff --git a/content/system/house/room/states/view.gd b/content/system/house/room/states/view.gd new file mode 100644 index 0000000..06e4715 --- /dev/null +++ b/content/system/house/room/states/view.gd @@ -0,0 +1,144 @@ +extends RoomState + +const RoomState = preload("./room_state.gd") + +var room_height = 3 +var corner_count = 0 + +func _on_enter(): + corner_count = room.wall_corners.get_child_count() + + if corner_count < 3: + return + + room_height = room.room_ceiling.position.y + + room.wall_mesh.visible = true + room.ceiling_mesh.visible = true + room.wall_mesh.mesh = generate_mesh() + + if room.wall_mesh.mesh == null: + return + + var ceiling_shape = room.room_ceiling.get_node("CollisionShape3D") + var floor_shape = room.room_floor.get_node("CollisionShape3D") + + ceiling_shape.disabled = false + floor_shape.disabled = false + + room.ceiling_mesh.mesh = generate_ceiling_mesh() + ceiling_shape.shape = room.ceiling_mesh.mesh.create_trimesh_shape() + floor_shape.shape = room.ceiling_mesh.mesh.create_trimesh_shape() + ceiling_shape.shape.backface_collision = true + + var collisions = generate_collision() + + for collision in collisions: + var static_body = StaticBody3D.new() + static_body.set_collision_layer_value(4, true) + static_body.set_collision_layer_value(5, true) + static_body.collision_mask = 0 + static_body.add_child(collision) + room.wall_collisions.add_child(static_body) + + room.wall_mesh.visible = true + +func _on_leave(): + room.wall_mesh.visible = false + room.ceiling_mesh.visible = false + + room.room_ceiling.get_node("CollisionShape3D").disabled = true + room.room_floor.get_node("CollisionShape3D").disabled = true + + for collision in room.wall_collisions.get_children(): + collision.queue_free() + +func generate_mesh(): + var st = SurfaceTool.new() + var wall_up = Vector3.UP * room_height + + st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP) + + for i in range(corner_count): + var corner = room.get_corner(i) + + st.add_vertex(corner.position) + st.add_vertex(corner.position + wall_up) + + var first_corner = room.get_corner(0) + + st.add_vertex(first_corner.position) + st.add_vertex(first_corner.position + wall_up) + + st.index() + st.generate_normals() + st.generate_tangents() + var mesh = st.commit() + + return mesh + +func generate_ceiling_mesh(): + var points: PackedVector2Array = PackedVector2Array() + var edges: PackedInt32Array = PackedInt32Array() + var triangles: PackedInt32Array + + for i in range(corner_count): + var corner = room.get_corner(i) + points.append(Vector2(corner.position.x, corner.position.z)) + edges.append(i) + edges.append((i + 1) % corner_count) + + var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new() + + cdt.init(true, true, 0.1) + + cdt.insert_vertices(points) + cdt.insert_edges(edges) + + cdt.erase_outer_triangles() + + points = cdt.get_all_vertices() + triangles = cdt.get_all_triangles() + + var st = SurfaceTool.new() + + st.begin(Mesh.PRIMITIVE_TRIANGLES) + + for i in range(points.size()): + st.add_vertex(Vector3(points[i].x, 0, points[i].y)) + + for i in range(triangles.size()): + st.add_index(triangles[i]) + + st.index() + st.generate_normals() + st.generate_tangents() + + var mesh = st.commit() + + return mesh + +func generate_collision(): + var collision_shapes: Array[CollisionShape3D] = [] + + for i in range(corner_count): + var corner = room.get_corner(i) + var next_corner = room.get_corner(i + 1) + + var shape = BoxShape3D.new() + shape.size = Vector3((next_corner.position - corner.position).length(), room_height, 0.04) + + var transform = Transform3D() + var back_vector = (corner.position - next_corner.position).cross(Vector3.UP).normalized() * shape.size.z / 2 + + transform.basis = Basis((next_corner.position - corner.position).normalized(), Vector3.UP, back_vector.normalized()) + transform.origin = corner.position + (next_corner.position - corner.position) / 2 + back_vector + Vector3.UP * shape.size.y / 2 + + var collision_shape = CollisionShape3D.new() + + collision_shape.shape = shape + collision_shape.transform = transform + + collision_shapes.append(collision_shape) + + return collision_shapes diff --git a/content/system/room/wall_corner.tscn b/content/system/house/room/wall_corner.tscn similarity index 98% rename from content/system/room/wall_corner.tscn rename to content/system/house/room/wall_corner.tscn index c12b7ed..f713d4c 100644 --- a/content/system/room/wall_corner.tscn +++ b/content/system/house/room/wall_corner.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://content/functions/clickable.gd" id="1_e5awq"] [sub_resource type="SphereShape3D" id="SphereShape3D_86rci"] -radius = 0.05 +radius = 0.1 [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_i1w3w"] transparency = 1 diff --git a/content/system/house/room/wall_edge.gd b/content/system/house/room/wall_edge.gd new file mode 100644 index 0000000..22745fd --- /dev/null +++ b/content/system/house/room/wall_edge.gd @@ -0,0 +1,16 @@ +extends StaticBody3D + + +func align_to_corners(from_pos: Vector3, to_pos: Vector3): + var diff = to_pos - from_pos + var direction = diff.normalized() + var tangent = Vector3(direction.z, 0, -direction.x).normalized() + + if tangent == Vector3.ZERO: + tangent = Vector3(1, 0, 0) + + var edge_position = from_pos + diff / 2 + + var edge_basis = Basis(tangent, diff, tangent.cross(direction)) + + transform = Transform3D(edge_basis, edge_position) diff --git a/content/system/house/room/wall_edge.tscn b/content/system/house/room/wall_edge.tscn new file mode 100644 index 0000000..2eeb489 --- /dev/null +++ b/content/system/house/room/wall_edge.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=6 format=3 uid="uid://dlj5chj7ndgua"] + +[ext_resource type="Script" path="res://content/system/house/room/wall_edge.gd" id="1_0c5rj"] +[ext_resource type="Material" uid="uid://j12e5wwthtaa" path="res://content/system/house/room/edge.tres" id="1_hs3tw"] +[ext_resource type="Script" path="res://content/functions/clickable.gd" id="2_cfvx2"] + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_a2dct"] +material = ExtResource("1_hs3tw") +radius = 0.01 +height = 1.0 + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_6m53l"] +radius = 0.04 +height = 1.0 + +[node name="StaticBody3D" type="StaticBody3D"] +script = ExtResource("1_0c5rj") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +mesh = SubResource("CapsuleMesh_a2dct") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("CapsuleShape3D_6m53l") + +[node name="Clickable" type="Node" parent="."] +script = ExtResource("2_cfvx2") diff --git a/content/system/room/walls.tres b/content/system/house/room/walls.tres similarity index 100% rename from content/system/room/walls.tres rename to content/system/house/room/walls.tres diff --git a/content/system/house/room/walls_mini.tres b/content/system/house/room/walls_mini.tres new file mode 100644 index 0000000..1432646 --- /dev/null +++ b/content/system/house/room/walls_mini.tres @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6b87dd767a03b39f93f17a71b75b3a6ce82623a7703c24722dd112e31718376 +size 157 diff --git a/content/system/keyboard/keyboard.gd b/content/system/keyboard/keyboard.gd index 947e5f1..fd70e60 100644 --- a/content/system/keyboard/keyboard.gd +++ b/content/system/keyboard/keyboard.gd @@ -90,5 +90,4 @@ func _emit_event(type: String, key: Key): event.shift_pressed = caps EventSystem.emit(type, event) - print("Emitting event: " + type + " " + EventKey.key_to_string(key, caps)) diff --git a/content/system/room/room.gd b/content/system/room/room.gd deleted file mode 100644 index aa1e171..0000000 --- a/content/system/room/room.gd +++ /dev/null @@ -1,205 +0,0 @@ -extends Node3D - -const wall_corner_scene = preload("./wall_corner.tscn") -const wall_edge_scene = preload("./wall_edge.tscn") - -@onready var wall_corners = $WallCorners -@onready var wall_edges = $WallEdges -@onready var wall_mesh = $WallMesh -@onready var wall_collisions = $WallCollisions - -@onready var ground = $Ground/Clickable - -var moving = null -var editable := false: - set(value): - if value == editable: - return - - editable = value - if value: - _start_edit_mode() - else: - _end_edit_mode() -var ground_plane = Plane(Vector3.UP, Vector3.ZERO) - - -func _ready(): - ground.on_click.connect(func(event): - if !editable: - return - - add_corner(event.ray.get_collision_point()) - ) - -func _start_edit_mode(): - wall_corners.visible = true - wall_edges.visible = true - wall_mesh.visible = false - wall_mesh.mesh = null - - for old_coll in wall_collisions.get_children(): - old_coll.queue_free() - -func _end_edit_mode(): - wall_corners.visible = false - wall_edges.visible = false - wall_mesh.mesh = generate_mesh() - - if wall_mesh.mesh == null: - return - - var collisions = generate_collision(wall_mesh.mesh) - - for collision in collisions: - var static_body = StaticBody3D.new() - static_body.set_collision_layer_value(4, true) - static_body.set_collision_layer_value(5, true) - static_body.collision_mask = 0 - static_body.add_child(collision) - wall_collisions.add_child(static_body) - - wall_mesh.visible = true - -func generate_mesh(): - var corner_count = wall_corners.get_child_count() - - if corner_count < 3: - return - - var st = SurfaceTool.new() - var wall_up = Vector3.UP * 3 - - st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP) - - for i in range(corner_count): - var corner = get_corner(i) - - st.add_vertex(corner.position) - st.add_vertex(corner.position + wall_up) - - var first_corner = get_corner(0) - - st.add_vertex(first_corner.position) - st.add_vertex(first_corner.position + wall_up) - - st.index() - st.generate_normals() - st.generate_tangents() - var mesh = st.commit() - - return mesh - -func generate_collision(mesh: ArrayMesh): - var corner_count = wall_corners.get_child_count() - - if corner_count < 3: - return - - var collision_shapes: Array[CollisionShape3D] = [] - - for i in range(corner_count): - var corner = get_corner(i) - var next_corner = get_corner(i + 1) - - var shape = BoxShape3D.new() - shape.size = Vector3((next_corner.position - corner.position).length(), 3, 0.04) - - var transform = Transform3D() - var back_vector = (corner.position - next_corner.position).cross(Vector3.UP).normalized() * shape.size.z / 2 - - transform.basis = Basis((next_corner.position - corner.position).normalized(), Vector3.UP, back_vector.normalized()) - transform.origin = corner.position + (next_corner.position - corner.position) / 2 + back_vector + Vector3.UP * shape.size.y / 2 - - var collision_shape = CollisionShape3D.new() - - collision_shape.shape = shape - collision_shape.transform = transform - - collision_shapes.append(collision_shape) - - return collision_shapes - -func add_corner(position: Vector3): - var corner = wall_corner_scene.instantiate() - corner.position = position - - corner.get_node("Clickable").on_grab_down.connect(func(event): - if !editable: - return - - moving = event.target - ) - - corner.get_node("Clickable").on_grab_move.connect(func(event): - if moving == null: - return - - var direction = -event.ray.global_transform.basis.z - var new_position = ground_plane.intersects_ray(event.ray.global_position, direction) - - if new_position == null: - return - - moving.position = new_position - var moving_index = moving.get_index() - - get_edge(moving_index).transform = corners_to_edge_transform(new_position, get_corner(moving_index + 1).position) - get_edge(moving_index - 1).transform = corners_to_edge_transform(get_corner(moving_index - 1).position, new_position) - ) - - corner.get_node("Clickable").on_grab_up.connect(func(_event): - moving = null - ) - - wall_corners.add_child(corner) - - - var num_corners = wall_corners.get_child_count() - var edge - - if num_corners > 1: - edge = add_edge(wall_corners.get_child(num_corners - 2).position, position) - - if num_corners > 2: - if num_corners != wall_edges.get_child_count(): - add_edge(position, wall_corners.get_child(0).position) - else: - wall_edges.move_child(edge, num_corners - 2) - get_edge(-1).transform = corners_to_edge_transform(position, get_corner(0).position) - -func get_corner(index: int) -> MeshInstance3D: - return wall_corners.get_child(index % wall_corners.get_child_count()) - -func get_edge(index: int) -> MeshInstance3D: - return wall_edges.get_child(index % wall_edges.get_child_count()) - - -func add_edge(from_pos: Vector3, to_pos: Vector3): - var edge: MeshInstance3D = wall_edge_scene.instantiate() - edge.transform = corners_to_edge_transform(from_pos, to_pos) - wall_edges.add_child(edge) - return edge - -func corners_to_edge_transform(from_pos: Vector3, to_pos: Vector3) -> Transform3D: - var diff = to_pos - from_pos - var direction = diff.normalized() - - var edge_position = from_pos + diff / 2 - var edge_basis = Basis(Vector3.UP, diff, direction.cross(Vector3.UP)) - - var edge_transform = Transform3D(edge_basis, edge_position) - return edge_transform - -func _save(): - return { - "corners": wall_corners.get_children().map(func(corner): return corner.position), - } - -func _load(data): - await ready - - for corner in data["corners"]: - add_corner(corner) - - _end_edit_mode() diff --git a/content/system/room/room.tscn b/content/system/room/room.tscn deleted file mode 100644 index 6270f6a..0000000 --- a/content/system/room/room.tscn +++ /dev/null @@ -1,42 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://bswgmclohuqui"] - -[ext_resource type="Script" path="res://content/system/room/room.gd" id="1_fccq0"] -[ext_resource type="Script" path="res://content/functions/clickable.gd" id="1_ugebq"] -[ext_resource type="Material" uid="uid://bbx6fv7jq50tr" path="res://content/system/room/walls.tres" id="3_al1ev"] - -[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_08sv0"] - -[sub_resource type="ArrayMesh" id="ArrayMesh_7dibq"] - -[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_ap613"] - -[node name="Room" type="Node3D"] -script = ExtResource("1_fccq0") - -[node name="Ground" type="StaticBody3D" parent="."] -collision_layer = 24 -collision_mask = 0 - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"] -shape = SubResource("WorldBoundaryShape3D_08sv0") - -[node name="Clickable" type="Node" parent="Ground"] -script = ExtResource("1_ugebq") - -[node name="WallCorners" type="Node3D" parent="."] - -[node name="WallEdges" type="Node3D" parent="."] - -[node name="WallMesh" type="MeshInstance3D" parent="."] -material_override = ExtResource("3_al1ev") -mesh = SubResource("ArrayMesh_7dibq") - -[node name="WallCollisions" type="Node3D" parent="."] - -[node name="Celing" type="StaticBody3D" parent="."] -transform = Transform3D(-1, 8.74228e-08, 0, -8.74228e-08, -1, 0, 0, 0, 1, 0, 3.07, 0) -collision_layer = 0 -collision_mask = 0 - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Celing"] -shape = SubResource("WorldBoundaryShape3D_ap613") diff --git a/content/system/room/wall_edge.tscn b/content/system/room/wall_edge.tscn deleted file mode 100644 index 21f2718..0000000 --- a/content/system/room/wall_edge.tscn +++ /dev/null @@ -1,11 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://dlj5chj7ndgua"] - -[ext_resource type="Material" uid="uid://j12e5wwthtaa" path="res://content/ui/menu/room/edge.tres" id="1_b21dw"] - -[sub_resource type="CapsuleMesh" id="CapsuleMesh_a2dct"] -material = ExtResource("1_b21dw") -radius = 0.01 -height = 1.0 - -[node name="MeshInstance3D" type="MeshInstance3D"] -mesh = SubResource("CapsuleMesh_a2dct") diff --git a/content/ui/components/button/button.gd b/content/ui/components/button/button.gd index 5dbfad1..26ce74e 100644 --- a/content/ui/components/button/button.gd +++ b/content/ui/components/button/button.gd @@ -3,8 +3,6 @@ extends Node3D class_name Button3D -const Proxy = preload("res://lib/utils/proxy.gd") - signal on_button_down() signal on_button_up() @@ -38,7 +36,7 @@ const IconFont = preload("res://assets/icons/icons.tres") if value: label_node.font = IconFont - label_node.font_size = 48 + label_node.font_size = 36 label_node.width = 1000 label_node.autowrap_mode = TextServer.AUTOWRAP_OFF else: @@ -50,13 +48,24 @@ const IconFont = preload("res://assets/icons/icons.tres") @export var toggleable: bool = false @export var disabled: bool = false @export var initial_active: bool = false -var external_value: Proxy = null +var external_value: Proxy = null: + set(value): + if !is_node_ready(): await ready + + external_value = value + if value != null: + value.on_set.connect(func(_value): + update_animation() + ) + var active: bool = false: get: if external_value != null: return external_value.value return active set(value): + if !is_node_ready(): await ready + if external_value != null: external_value.value = value else: diff --git a/content/ui/components/input/input.gd b/content/ui/components/input/input.gd index a543f8d..6dd76e6 100644 --- a/content/ui/components/input/input.gd +++ b/content/ui/components/input/input.gd @@ -116,7 +116,6 @@ func update_caret_position(event): func _on_focus_out(_event): - print("focus out") animation.stop() caret.hide() diff --git a/content/ui/components/notification/notification.gd b/content/ui/components/notification/notification.gd index 5b8e6b6..38ddd61 100644 --- a/content/ui/components/notification/notification.gd +++ b/content/ui/components/notification/notification.gd @@ -13,7 +13,6 @@ extends Node3D set(value): type = value if !is_node_ready(): await ready - print(value, " ", _type_to_string(value)) icon_label.text = _type_to_string(value) @export var text: String = "": set(value): diff --git a/content/ui/components/tabs/tabs.gd b/content/ui/components/tabs/tabs.gd new file mode 100644 index 0000000..f8e88e6 --- /dev/null +++ b/content/ui/components/tabs/tabs.gd @@ -0,0 +1,28 @@ +extends Node3D +class_name Tabs3D + +signal on_select(selected: int) + +var selected: Node3D +@export var initial_selected: Node3D +var proxy_group = ProxyGroup.new() + +func _ready(): + if initial_selected != null: + selected = initial_selected + on_select.emit(selected.get_index()) + + for option in get_children(): + if option is Button3D == false: + continue + + var proxy = proxy_group.proxy(func(): + return selected == option + , func(value: bool): + if value == true: + selected = option + on_select.emit(selected.get_index()) + ) + + option.external_value = proxy + option.toggleable = true diff --git a/content/ui/components/tabs/tabs.tscn b/content/ui/components/tabs/tabs.tscn new file mode 100644 index 0000000..7adbee7 --- /dev/null +++ b/content/ui/components/tabs/tabs.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://doavdm6fskmrt"] + +[ext_resource type="Script" path="res://content/ui/components/tabs/tabs.gd" id="1_xt6wm"] + +[node name="Tabs" type="Node3D"] +script = ExtResource("1_xt6wm") diff --git a/content/ui/components/tabs/tabs_content.gd b/content/ui/components/tabs/tabs_content.gd new file mode 100644 index 0000000..73d3052 --- /dev/null +++ b/content/ui/components/tabs/tabs_content.gd @@ -0,0 +1,22 @@ +extends Node3D +class_name TabsContent3D + +@export var tabs: Tabs3D + +var children: Array = [] + +func _ready(): + children = get_children() + + for child in children: + child.visible = true + if tabs.selected != null && tabs.selected.get_index() == child.get_index(): + continue + remove_child(child) + + tabs.on_select.connect(func(index): + for child in get_children(): + remove_child(child) + + add_child(children[index]) + ) diff --git a/content/ui/components/tabs/tabs_content.tscn b/content/ui/components/tabs/tabs_content.tscn new file mode 100644 index 0000000..48c8307 --- /dev/null +++ b/content/ui/components/tabs/tabs_content.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://wewhef3qmulp"] + +[ext_resource type="Script" path="res://content/ui/components/tabs/tabs_content.gd" id="1_ljgkj"] + +[node name="TabsContent" type="Node3D"] +script = ExtResource("1_ljgkj") diff --git a/content/ui/menu/edit/edit_menu.gd b/content/ui/menu/edit/edit_menu.gd index afcb926..247e717 100644 --- a/content/ui/menu/edit/edit_menu.gd +++ b/content/ui/menu/edit/edit_menu.gd @@ -1,7 +1,6 @@ extends Node3D const ButtonScene = preload("res://content/ui/components/button/button.tscn") -const EntityCreator = preload("./entity_creator.gd") @onready var devices_node: GridContainer3D = $Devices @onready var next_page_button = $Buttons/NextPageButton @@ -145,22 +144,11 @@ func _on_entity_click(entity_name): render() return - var type = entity_name.split(".")[0] AudioPlayer.play_effect("spawn") - var entity = EntityCreator.create_entity(type, entity_name) - - if entity == null: - return - - entity.set_position(global_position) - get_node("/root/Main").add_child(entity) + House.body.create_entity(entity_name, global_position) func clear_menu(): for child in devices_node.get_children(): devices_node.remove_child(child) - child.queue_free() - -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta): - pass + child.queue_free() \ No newline at end of file diff --git a/content/ui/menu/menu.gd b/content/ui/menu/menu.gd index 7186689..6af6f86 100644 --- a/content/ui/menu/menu.gd +++ b/content/ui/menu/menu.gd @@ -3,15 +3,6 @@ extends Node3D const Proxy = preload("res://lib/utils/proxy.gd") const Notification = preload("res://content/ui/components/notification/notification.tscn") -@onready var nav_view = $AnimationContainer/Navigation/View -@onready var nav_edit: Button3D = $AnimationContainer/Navigation/Edit -@onready var menu_edit: Node3D = $AnimationContainer/Content/EditMenu -@onready var nav_room = $AnimationContainer/Navigation/Room -@onready var menu_room: Node3D = $AnimationContainer/Content/RoomMenu -@onready var nav_automate = $AnimationContainer/Navigation/Automate -@onready var nav_settings = $AnimationContainer/Navigation/Settings -@onready var menu_settings: Node3D = $AnimationContainer/Content/SettingsMenu - @onready var menu_root = $AnimationContainer @onready var content = $AnimationContainer/Content @onready var nav = $AnimationContainer/Navigation @@ -41,61 +32,3 @@ func _ready(): notify_place.add_child(notification_node) ) - - var nav_buttons = [ - nav_view, - nav_edit, - nav_room, - nav_automate, - nav_settings - ] - - for nav_button in nav_buttons: - var getter = func(): - return nav_button == selected_nav - - var setter = func(value): - if value: - select_menu(nav_button) - - nav_button.external_value = Proxy.new(getter, setter) - - select_menu(nav_edit) - -func select_menu(nav): - if _is_valid_nav(nav) == false || selected_nav == nav: - return - - for child in content.get_children(): - content.remove_child(child) - - var old_nav = selected_nav - - selected_nav = nav - - if old_nav != null: - old_nav.update_animation() - - if selected_nav != null: - selected_nav.update_animation() - var menu = _nav_to_menu(selected_nav) - if menu != null: - content.add_child(menu) - menu.visible = true - -func _is_valid_nav(nav): - return nav == nav_view || nav == nav_edit || nav == nav_room || nav == nav_automate || nav == nav_settings - -func _nav_to_menu(nav): - match nav: - nav_view: - return null - nav_edit: - return menu_edit - nav_room: - return menu_room - nav_automate: - return null - nav_settings: - return menu_settings - return null diff --git a/content/ui/menu/menu.tscn b/content/ui/menu/menu.tscn index 2b6de75..a8acc5a 100644 --- a/content/ui/menu/menu.tscn +++ b/content/ui/menu/menu.tscn @@ -1,11 +1,14 @@ -[gd_scene load_steps=16 format=3 uid="uid://c3kdssrmv84kv"] +[gd_scene load_steps=19 format=3 uid="uid://c3kdssrmv84kv"] [ext_resource type="Script" path="res://content/ui/menu/menu.gd" id="1_ng4u3"] [ext_resource type="Material" uid="uid://bnwimm214q67g" path="res://assets/materials/sec-500.material" id="2_0x5at"] [ext_resource type="Script" path="res://content/functions/movable.gd" id="2_8coxu"] +[ext_resource type="Script" path="res://content/ui/components/tabs/tabs.gd" id="4_eavfx"] [ext_resource type="PackedScene" uid="uid://crrb0l3ekuotj" path="res://content/ui/menu/edit/edit_menu.tscn" id="4_r2raj"] [ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="5_w4i01"] +[ext_resource type="Script" path="res://content/ui/components/tabs/tabs_content.gd" id="6_7rntr"] [ext_resource type="ArrayMesh" uid="uid://cbqhhnknyium2" path="res://assets/immersive_home_panels/immersive_home_panels.obj" id="7_f4u4o"] +[ext_resource type="PackedScene" uid="uid://ddpxthb414unp" path="res://content/ui/menu/view/view_menu.tscn" id="8_71pkg"] [ext_resource type="PackedScene" uid="uid://c01gkeldvjwtr" path="res://content/ui/menu/room/room_menu.tscn" id="10_u4i1x"] [ext_resource type="PackedScene" uid="uid://c6r4higceibif" path="res://content/ui/menu/settings/settings_menu.tscn" id="11_7wm6b"] @@ -181,48 +184,58 @@ skeleton = NodePath("../..") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.21, 0, 0.15) shape = SubResource("ConvexPolygonShape3D_mgnm0") -[node name="Navigation" type="Node3D" parent="AnimationContainer"] +[node name="Tabs" type="Node3D" parent="AnimationContainer" node_paths=PackedStringArray("initial_selected")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, 0, 0) +script = ExtResource("4_eavfx") +initial_selected = NodePath("View") -[node name="View" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")] +[node name="View" parent="AnimationContainer/Tabs" instance=ExtResource("5_w4i01")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.03) label = "visibility" icon = true toggleable = true -[node name="Edit" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")] +[node name="Edit" parent="AnimationContainer/Tabs" instance=ExtResource("5_w4i01")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.09) label = "widgets" icon = true toggleable = true -[node name="Room" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")] +[node name="Room" parent="AnimationContainer/Tabs" instance=ExtResource("5_w4i01")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.15) label = "view_in_ar" icon = true toggleable = true -[node name="Automate" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")] +[node name="Automate" parent="AnimationContainer/Tabs" instance=ExtResource("5_w4i01")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.21) label = "schema" icon = true toggleable = true -[node name="Settings" parent="AnimationContainer/Navigation" instance=ExtResource("5_w4i01")] +[node name="Settings" parent="AnimationContainer/Tabs" instance=ExtResource("5_w4i01")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.03, 0, 0.27) label = "settings" icon = true toggleable = true -[node name="Content" type="Node3D" parent="AnimationContainer"] +[node name="TabsContent" type="Node3D" parent="AnimationContainer" node_paths=PackedStringArray("tabs")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, 0, 0) +script = ExtResource("6_7rntr") +tabs = NodePath("../Tabs") -[node name="EditMenu" parent="AnimationContainer/Content" instance=ExtResource("4_r2raj")] - -[node name="RoomMenu" parent="AnimationContainer/Content" instance=ExtResource("10_u4i1x")] +[node name="ViewMenu" parent="AnimationContainer/TabsContent" instance=ExtResource("8_71pkg")] visible = false -[node name="SettingsMenu" parent="AnimationContainer/Content" instance=ExtResource("11_7wm6b")] +[node name="EditMenu" parent="AnimationContainer/TabsContent" instance=ExtResource("4_r2raj")] + +[node name="RoomMenu" parent="AnimationContainer/TabsContent" instance=ExtResource("10_u4i1x")] +visible = false + +[node name="AutomateMenu" type="Node3D" parent="AnimationContainer/TabsContent"] +visible = false + +[node name="SettingsMenu" parent="AnimationContainer/TabsContent" instance=ExtResource("11_7wm6b")] visible = false [node name="NotifyPlace" type="Marker3D" parent="AnimationContainer"] diff --git a/content/ui/menu/room/room_menu.gd b/content/ui/menu/room/room_menu.gd index 147c68b..3293953 100644 --- a/content/ui/menu/room/room_menu.gd +++ b/content/ui/menu/room/room_menu.gd @@ -1,40 +1,16 @@ extends Node3D -const Room = preload("res://content/system/room/room.tscn") - const window_scene = preload("./window.tscn") @onready var background = $Background -@onready var toggle_edit_button = $Interface/ToggleEdit -@onready var spawn_windows = $SpawnWindows -@onready var rooms = get_tree().root.get_node("Main/Rooms") -var room: Node3D func _ready(): background.visible = false HomeApi.on_connect.connect(func(): - if rooms.get_child_count() == 0: - room = Room.instantiate() - rooms.add_child(room) - else: - room = rooms.get_child(0) - if rooms.get_child_count() > 1: - for child in rooms.get_children(): - if child != room: - child.queue_free() - ) + # var rooms = House.body.get_rooms(0) - spawn_windows.on_button_down.connect(func(): - get_tree().root.get_node("Main").add_child.call_deferred(window_scene.instantiate()) - ) - - toggle_edit_button.on_button_down.connect(func(): - if room != null: - room.editable = true - ) - - toggle_edit_button.on_button_up.connect(func(): - if room != null: - room.editable = false + # for room in rooms: + # var mesh = room.wall_mesh + pass ) diff --git a/content/ui/menu/room/room_menu.tscn b/content/ui/menu/room/room_menu.tscn index e1df0ee..4dd5d60 100644 --- a/content/ui/menu/room/room_menu.tscn +++ b/content/ui/menu/room/room_menu.tscn @@ -1,8 +1,12 @@ -[gd_scene load_steps=5 format=3 uid="uid://c01gkeldvjwtr"] +[gd_scene load_steps=9 format=3 uid="uid://c01gkeldvjwtr"] [ext_resource type="Script" path="res://content/ui/menu/room/room_menu.gd" id="1_ch4jb"] -[ext_resource type="Script" path="res://content/functions/clickable.gd" id="2_elugy"] -[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_whl7a"] +[ext_resource type="Material" uid="uid://bujy3egn1oqac" path="res://assets/materials/pri-500.material" id="2_7m4yn"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="4_cghmp"] +[ext_resource type="Script" path="res://content/ui/components/tabs/tabs.gd" id="5_ddrep"] +[ext_resource type="PackedScene" uid="uid://dd71loi64gnmp" path="res://content/ui/menu/room/views/overview.tscn" id="6_206ad"] +[ext_resource type="Script" path="res://content/ui/components/tabs/tabs_content.gd" id="6_ba00g"] +[ext_resource type="PackedScene" uid="uid://bpta22fahai46" path="res://content/ui/menu/room/views/rooms.tscn" id="7_2f8e0"] [sub_resource type="BoxMesh" id="BoxMesh_e37nn"] size = Vector3(0.3, 0.01, 0.3) @@ -12,35 +16,27 @@ script = ExtResource("1_ch4jb") [node name="Background" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, 0, 0.15) +material_override = ExtResource("2_7m4yn") mesh = SubResource("BoxMesh_e37nn") [node name="Interface" type="Node3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.01, 0) -[node name="ToggleEdit" parent="Interface" instance=ExtResource("3_whl7a")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0, 0.05) -label = "room_preferences" -icon = true -toggleable = true +[node name="Tabs3D" type="Node3D" parent="Interface" node_paths=PackedStringArray("initial_selected")] +script = ExtResource("5_ddrep") +initial_selected = NodePath("Overview") -[node name="Clickable" type="Node" parent="Interface/ToggleEdit"] -script = ExtResource("2_elugy") +[node name="Overview" parent="Interface/Tabs3D" instance=ExtResource("4_cghmp")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, -0.02) +label = "Overview" -[node name="Label3D" type="Label3D" parent="Interface"] -transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.13, -1.86265e-09, 0.05) -pixel_size = 0.001 -text = "Edit Room" -font_size = 18 -outline_size = 0 +[node name="Rooms" parent="Interface/Tabs3D" instance=ExtResource("4_cghmp")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.09, 0, -0.02) +label = "Rooms" -[node name="CreateBlur" type="Label3D" parent="."] -transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.15, 0.01, 0.261858) -pixel_size = 0.001 -text = "Fake Windows" -font_size = 18 -outline_size = 0 +[node name="TabsContent3D" type="Node3D" parent="Interface" node_paths=PackedStringArray("tabs")] +script = ExtResource("6_ba00g") +tabs = NodePath("../Tabs3D") -[node name="SpawnWindows" parent="." instance=ExtResource("3_whl7a")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0, 0.26) -label = "lens_blur" -icon = true +[node name="Overview" parent="Interface/TabsContent3D" instance=ExtResource("6_206ad")] + +[node name="Rooms" parent="Interface/TabsContent3D" instance=ExtResource("7_2f8e0")] diff --git a/content/ui/menu/room/room_selected.tres b/content/ui/menu/room/room_selected.tres new file mode 100644 index 0000000..a0ad81c --- /dev/null +++ b/content/ui/menu/room/room_selected.tres @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5245272378c86fb17cf012dee95460df366d7781d3119604e447ae2330de7199 +size 134 diff --git a/content/ui/menu/room/room_unselected.tres b/content/ui/menu/room/room_unselected.tres new file mode 100644 index 0000000..6f9b538 --- /dev/null +++ b/content/ui/menu/room/room_unselected.tres @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b77e182a6941bd1837cdbae2586f5a7561e033fc26a1a2c50c0eb1a600d40322 +size 101 diff --git a/content/ui/menu/room/views/overview.gd b/content/ui/menu/room/views/overview.gd new file mode 100644 index 0000000..2cb31f1 --- /dev/null +++ b/content/ui/menu/room/views/overview.gd @@ -0,0 +1,31 @@ +extends Node3D + +@onready var edit_button = $EditButton +@onready var fix_button = $FixButton + +var active = false: + set(value): + if value: + edit_button.label = "save" + fix_button.disabled = true + fix_button.visible = false + else: + edit_button.label = "edit" + fix_button.disabled = false + fix_button.visible = true + active = value + +func _ready(): + + edit_button.on_button_down.connect(func(): + if active: + House.body.save_reference() + else: + House.body.edit_reference() + active = !active + ) + + fix_button.on_button_down.connect(func(): + House.body.fix_reference() + active = true + ) diff --git a/content/ui/menu/room/views/overview.tscn b/content/ui/menu/room/views/overview.tscn new file mode 100644 index 0000000..d158f91 --- /dev/null +++ b/content/ui/menu/room/views/overview.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=3 format=3 uid="uid://dd71loi64gnmp"] + +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="1_fteh8"] +[ext_resource type="Script" path="res://content/ui/menu/room/views/overview.gd" id="1_jesad"] + +[node name="Overview" type="Node3D"] +script = ExtResource("1_jesad") + +[node name="EditButton" parent="." instance=ExtResource("1_fteh8")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.04, 0, 0.07) +label = "edit" +icon = true + +[node name="FixButton" parent="." instance=ExtResource("1_fteh8")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.1, 0, 0.07) +label = "healing" +icon = true + +[node name="Label3D" type="Label3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.06, 0.01, 0.02) +pixel_size = 0.001 +text = "Reference" +font_size = 18 +outline_size = 0 diff --git a/content/ui/menu/room/views/rooms.gd b/content/ui/menu/room/views/rooms.gd new file mode 100644 index 0000000..5efc268 --- /dev/null +++ b/content/ui/menu/room/views/rooms.gd @@ -0,0 +1,130 @@ +extends Node3D + +const Room = preload("res://content/system/house/room/room.tscn") +const RoomType = preload("res://content/system/house/room/room.gd") + +const material_selected = preload("../room_selected.tres") +const material_unselected = preload("../room_unselected.tres") + + +@onready var room_button = $Button +@onready var input = $Input +@onready var rooms_map = $Rooms + +var selected_room = null: + set(value): + if selected_room != null && value == null: + room_button.label = "add" + input.text = "Room %s" % (rooms_map.get_child_count() + 1) + + if selected_room != null: + var old_room = get_room(selected_room) + if old_room != null: + old_room.get_node("MeshInstance3D").material_override = material_unselected + + if value != null: + input.text = value + edit_room = false + var new_room = get_room(value) + if new_room != null: + new_room.get_node("MeshInstance3D").material_override = material_selected + + + selected_room = value + +var edit_room = false: + set(value): + edit_room = value + if value: + room_button.label = "save" + else: + room_button.label = "edit" + +func _ready(): + + room_button.on_button_down.connect(func(): + if selected_room == null: + var room_name = input.text + if get_room(room_name) != null: + EventSystem.notify("Name already taken", EventNotify.Type.WARNING) + return + + House.body.create_room(room_name, 0) + selected_room = room_name + edit_room = true + else: + if edit_room: + edit_room = false + + if !House.body.is_valid_room(selected_room): + House.body.delete_room(selected_room) + selected_room = null + else: + House.body.edit_room(null) + _generate_room_map() + else: + edit_room = true + House.body.edit_room(selected_room) + ) + +func get_room(room_name): + if rooms_map.has_node("%s" % room_name): + return rooms_map.get_node("%s" % room_name) + return null + +func _on_click(event: EventPointer): + if event.target.get_parent() == rooms_map: + var room_name = event.target.name + + if selected_room == room_name: + selected_room = null + House.body.edit_room(null) + return + + selected_room = room_name + +func _generate_room_map(): + var rooms = House.body.get_rooms(0) + + var target_size = Vector3(0.3, 1, 0.24) + + for old_room in rooms_map.get_children(): + old_room.queue_free() + await old_room.tree_exited + + var aabb = House.body.get_level_aabb(0) + var current_min = aabb.position + var current_max = aabb.position + aabb.size + + for room in rooms: + var mesh = room.ceiling_mesh.mesh + if mesh == null: + continue + + var body = StaticBody3D.new() + body.name = room.name + + + var mesh_instance = MeshInstance3D.new() + mesh_instance.name = "MeshInstance3D" + mesh_instance.mesh = mesh + mesh_instance.material_override = material_unselected if selected_room != room.name else material_selected + body.add_child(mesh_instance) + + var collision_shape = CollisionShape3D.new() + collision_shape.shape = mesh.create_trimesh_shape() + body.add_child(collision_shape) + + rooms_map.add_child(body) + + if current_min == null: + return + + var current_size = current_max - current_min + var target_scale = target_size / current_size + var scale_value = min(target_scale.x, target_scale.z) + + rooms_map.position.x = -current_min.x * scale_value + rooms_map.position.z = -current_min.z * scale_value + + rooms_map.scale = Vector3(scale_value, scale_value, scale_value) diff --git a/content/ui/menu/room/views/rooms.tscn b/content/ui/menu/room/views/rooms.tscn new file mode 100644 index 0000000..d666af7 --- /dev/null +++ b/content/ui/menu/room/views/rooms.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=4 format=3 uid="uid://bpta22fahai46"] + +[ext_resource type="Script" path="res://content/ui/menu/room/views/rooms.gd" id="1_3a1oa"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="1_y3lty"] +[ext_resource type="PackedScene" uid="uid://blrhy2uccrdn4" path="res://content/ui/components/input/input.tscn" id="2_hstw7"] + +[node name="Rooms" type="Node3D"] +script = ExtResource("1_3a1oa") + +[node name="Rooms" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, 0.01, 0.12) + +[node name="Button" parent="." instance=ExtResource("1_y3lty")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.27, 0, 0.27) +label = "add" +icon = true + +[node name="Input" parent="." instance=ExtResource("2_hstw7")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.12, 0.005, 0.27) +text = "Room 1" diff --git a/content/ui/menu/settings/settings_menu.tscn b/content/ui/menu/settings/settings_menu.tscn index 195e69c..dcfa1ee 100644 --- a/content/ui/menu/settings/settings_menu.tscn +++ b/content/ui/menu/settings/settings_menu.tscn @@ -23,14 +23,14 @@ mesh = SubResource("BoxMesh_e51x8") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.007, 0) [node name="Label3D" type="Label3D" parent="Content"] -transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.134377, 0, 0.253575) +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.124377, 0, 0.263575) pixel_size = 0.001 text = "Spawn Ball" font_size = 18 outline_size = 0 [node name="Button" parent="Content" instance=ExtResource("1_faxng")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0458097, 0, 0.253575) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0358097, 0, 0.263575) label = "sports_basketball" icon = true @@ -109,11 +109,11 @@ outline_size = 0 script = ExtResource("3_qmg6q") [node name="Save" parent="Content" instance=ExtResource("1_faxng")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.04, 0, 0.17) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, 0.12) label = "save" icon = true [node name="ClearSave" parent="Content" instance=ExtResource("1_faxng")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.1, 0, 0.17) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.09, 0, 0.12) label = "close" icon = true diff --git a/content/ui/menu/view/view_menu.gd b/content/ui/menu/view/view_menu.gd new file mode 100644 index 0000000..11fa1b9 --- /dev/null +++ b/content/ui/menu/view/view_menu.gd @@ -0,0 +1,12 @@ +extends Node3D + +@onready var mini_view = $Content/MiniView +@onready var background = $Background + +func _ready(): + background.visible = false + + mini_view.on_button_down.connect(func(): + House.body.mini_view = !House.body.mini_view + ) + diff --git a/content/ui/menu/view/view_menu.tscn b/content/ui/menu/view/view_menu.tscn new file mode 100644 index 0000000..986c50b --- /dev/null +++ b/content/ui/menu/view/view_menu.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=4 format=3 uid="uid://ddpxthb414unp"] + +[ext_resource type="Script" path="res://content/ui/menu/view/view_menu.gd" id="1_hxajx"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="2_qan1b"] + +[sub_resource type="BoxMesh" id="BoxMesh_qr3bi"] +size = Vector3(0.3, 0.01, 0.3) + +[node name="ViewMenu" type="Node3D"] +script = ExtResource("1_hxajx") + +[node name="Background" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, 0, 0.15) +mesh = SubResource("BoxMesh_qr3bi") + +[node name="Content" type="Node3D" parent="."] + +[node name="MiniView" parent="Content" instance=ExtResource("2_qan1b")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, 0.03) +label = "view_comfy" +icon = true diff --git a/lib/globals/home_api.gd b/lib/globals/home_api.gd index 85fa799..81801da 100644 --- a/lib/globals/home_api.gd +++ b/lib/globals/home_api.gd @@ -96,4 +96,5 @@ func watch_state(entity: String, callback: Callable): func _notification(what): if what == NOTIFICATION_WM_CLOSE_REQUEST || what == NOTIFICATION_WM_GO_BACK_REQUEST: - SaveSystem.save() \ No newline at end of file + # SaveSystem.save() + pass \ No newline at end of file diff --git a/lib/globals/house_body.gd b/lib/globals/house_body.gd new file mode 100644 index 0000000..c10f30a --- /dev/null +++ b/lib/globals/house_body.gd @@ -0,0 +1,3 @@ +extends Node + +@onready var body = get_node("/root/Main/House") \ No newline at end of file diff --git a/lib/globals/save_system.gd b/lib/globals/save_system.gd index 000a9df..c4d7e10 100644 --- a/lib/globals/save_system.gd +++ b/lib/globals/save_system.gd @@ -2,8 +2,17 @@ extends Node const VariantSerializer = preload("res://lib/utils/variant_serializer.gd") +signal loaded() +signal unloaded() + +var is_loaded := false +var export_config = ConfigFile.new() +var export_config_path = "res://export_presets.cfg" + func clear(): await _clear_save_tree(get_tree().root.get_node("Main")) + unloaded.emit() + is_loaded = false func save(): if HomeApi.has_connected() == false: @@ -18,7 +27,10 @@ func save(): var save_tree = _generate_save_tree(get_tree().root.get_node("Main")) - var json_text = JSON.stringify(save_tree) + var json_text = JSON.stringify({ + "version": get_version(), + "tree": save_tree + }) save_file.store_line(json_text) func load(): @@ -35,7 +47,19 @@ func load(): return var json_text = save_file.get_line() - var save_tree = JSON.parse_string(json_text) + var save_data = JSON.parse_string(json_text) + + if save_data == null: + return + + if save_data.has("version") == false: + save() + return + + var save_tree = save_data["tree"] + + if save_tree == null: + return if save_tree is Array: for tree in save_tree: @@ -43,6 +67,22 @@ func load(): else: _build_save_tree(save_tree) + loaded.emit() + is_loaded = true + +func get_version(): + var config_error = export_config.load(export_config_path) + + if config_error != OK: + return null + + var version = export_config.get_value("preset.1.options", "version/name") + + if version == null: + return null + + return version + func _clear_save_tree(node: Node): for child in node.get_children(): await _clear_save_tree(child) diff --git a/content/ui/menu/edit/entity_creator.gd b/lib/utils/entity_factory.gd similarity index 89% rename from content/ui/menu/edit/entity_creator.gd rename to lib/utils/entity_factory.gd index 25eb24b..8850d2d 100644 --- a/content/ui/menu/edit/entity_creator.gd +++ b/lib/utils/entity_factory.gd @@ -1,4 +1,5 @@ extends RefCounted +class_name EntityFactory const Switch = preload("res://content/entities/switch/switch.tscn") const Light = preload("res://content/entities/light/light.tscn") @@ -7,8 +8,9 @@ const MediaPlayer = preload("res://content/entities/media_player/media_player.ts const Camera = preload("res://content/entities/camera/camera.tscn") const ButtonEntity = preload("res://content/entities/button/button.tscn") -static func create_entity(type: String, id: String): +static func create_entity(id: String): var entity = null + var type = id.split(".")[0] match type: "switch": diff --git a/lib/utils/proxy.gd b/lib/utils/proxy.gd index 376db93..e42aefe 100644 --- a/lib/utils/proxy.gd +++ b/lib/utils/proxy.gd @@ -1,4 +1,7 @@ extends RefCounted +class_name Proxy + +signal on_set(new_value: Variant) var gettable: Callable var settable: Callable @@ -7,8 +10,12 @@ func _init(gettable: Callable, settable: Callable): self.gettable = gettable self.settable = settable + + var value: Variant: get: return gettable.call() set(new_value): - settable.call(new_value) \ No newline at end of file + settable.call(new_value) + on_set.emit(new_value) + diff --git a/lib/utils/proxy_group.gd b/lib/utils/proxy_group.gd new file mode 100644 index 0000000..0cd956e --- /dev/null +++ b/lib/utils/proxy_group.gd @@ -0,0 +1,19 @@ +extends RefCounted +class_name ProxyGroup + +var proxies = [] + +func proxy(_get: Callable, _set: Callable): + var _proxy + _proxy = Proxy.new(_get, func(value): + _set.call(value) + + for p in proxies: + if p != _proxy: + p.on_set.emit(value) + ) + + proxies.append(_proxy) + + return _proxy + \ No newline at end of file diff --git a/lib/utils/state_machine/state.gd b/lib/utils/state_machine/state.gd new file mode 100644 index 0000000..521d0ea --- /dev/null +++ b/lib/utils/state_machine/state.gd @@ -0,0 +1,13 @@ +extends Node +class_name State + +var state_machine: StateMachine + +func is_active(): + return state_machine.current_state == self + +func _on_enter(): + pass + +func _on_leave(): + pass \ No newline at end of file diff --git a/lib/utils/state_machine/state_machine.gd b/lib/utils/state_machine/state_machine.gd new file mode 100644 index 0000000..a5dbc81 --- /dev/null +++ b/lib/utils/state_machine/state_machine.gd @@ -0,0 +1,32 @@ +class_name StateMachine +extends Node + +signal changed(state_name: String, old_state: String) + +@export var current_state: Node +var states: Dictionary = {} + +func _ready() -> void: + for state in get_children(): + states[state.get_name()] = state + state.state_machine = self + + if state != current_state: + remove_child(state) + + await get_parent().ready + + current_state._on_enter() + +func change_to(new_state: String) -> void: + if states.has(new_state) == false: + return + + var old_state = current_state.get_name() + + current_state._on_leave() + remove_child(current_state) + current_state = states[new_state] + add_child(current_state) + current_state._on_enter() + changed.emit(new_state, old_state) diff --git a/project.godot b/project.godot index 60f8748..fcaa8d9 100644 --- a/project.godot +++ b/project.godot @@ -24,6 +24,7 @@ HomeApi="*res://lib/globals/home_api.gd" AudioPlayer="*res://lib/globals/audio_player.gd" EventSystem="*res://lib/globals/event_system.gd" SaveSystem="*res://lib/globals/save_system.gd" +House="*res://lib/globals/house_body.gd" [editor_plugins]