commit
c355e0be05
15
app/assets/environment.tres
Normal file
15
app/assets/environment.tres
Normal file
|
@ -0,0 +1,15 @@
|
|||
[gd_resource type="Environment" load_steps=3 format=3 uid="uid://cfm0g4r0h2n1p"]
|
||||
|
||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_i4xao"]
|
||||
|
||||
[sub_resource type="Sky" id="Sky_vhymk"]
|
||||
sky_material = SubResource("ProceduralSkyMaterial_i4xao")
|
||||
|
||||
[resource]
|
||||
background_mode = 1
|
||||
background_color = Color(1, 1, 1, 1)
|
||||
sky = SubResource("Sky_vhymk")
|
||||
ambient_light_source = 2
|
||||
ambient_light_color = Color(1, 1, 1, 1)
|
||||
ssao_radius = 6.52
|
||||
ssao_intensity = 5.68
|
15
app/assets/environment_passthrough.tres
Normal file
15
app/assets/environment_passthrough.tres
Normal file
|
@ -0,0 +1,15 @@
|
|||
[gd_resource type="Environment" load_steps=3 format=3 uid="uid://gljmitbkl86b"]
|
||||
|
||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_i4xao"]
|
||||
|
||||
[sub_resource type="Sky" id="Sky_vhymk"]
|
||||
sky_material = SubResource("ProceduralSkyMaterial_i4xao")
|
||||
|
||||
[resource]
|
||||
background_color = Color(0, 0, 0, 0)
|
||||
background_energy_multiplier = 0.0
|
||||
sky = SubResource("Sky_vhymk")
|
||||
ambient_light_source = 2
|
||||
ambient_light_color = Color(1, 1, 1, 1)
|
||||
ssao_radius = 6.52
|
||||
ssao_intensity = 5.68
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ae8276428c45d39d78153880ad4133705f61063edbc26bea163fec23119bbfc1
|
||||
size 302
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9bac0d498144e58cd467f8db75da57f71b519523ac08799d2e3d75b22ba2401f
|
||||
size 361
|
|
@ -1,8 +1,7 @@
|
|||
extends Node3D
|
||||
|
||||
var sky = preload ("res://assets/materials/sky.material")
|
||||
var sky_passthrough = preload ("res://assets/materials/sky_passthrough.material")
|
||||
const VoiceAssistant = preload ("res://content/system/assist/assist.tscn")
|
||||
const environment_passthrough_material = preload ("res://assets/environment_passthrough.tres")
|
||||
|
||||
@onready var environment: WorldEnvironment = $WorldEnvironment
|
||||
@onready var camera: XRCamera3D = $XROrigin3D/XRCamera3D
|
||||
|
@ -15,9 +14,10 @@ var voice_assistant = null
|
|||
|
||||
func _ready():
|
||||
# In case we're running on the headset, use the passthrough sky
|
||||
|
||||
if OS.get_name() == "Android":
|
||||
# OS.request_permissions()
|
||||
environment.environment.sky.set_material(sky_passthrough)
|
||||
environment.environment = environment_passthrough_material
|
||||
get_viewport().transparent_bg = true
|
||||
else:
|
||||
RenderingServer.set_debug_generate_wireframes(true)
|
||||
|
|
|
@ -1,31 +1,18 @@
|
|||
[gd_scene load_steps=17 format=3 uid="uid://eecv28y6jxk4"]
|
||||
[gd_scene load_steps=15 format=3 uid="uid://eecv28y6jxk4"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"]
|
||||
[ext_resource type="Script" path="res://content/main.gd" id="1_uvrd4"]
|
||||
[ext_resource type="PackedScene" uid="uid://b30w6tywfj4fp" path="res://content/system/controller_left/controller_left.tscn" id="2_2lraw"]
|
||||
[ext_resource type="Environment" uid="uid://cfm0g4r0h2n1p" path="res://assets/environment.tres" id="2_lsndp"]
|
||||
[ext_resource type="PackedScene" uid="uid://dscp8x0ari57n" path="res://content/system/raycast/raycast.tscn" id="3_67lii"]
|
||||
[ext_resource type="PackedScene" uid="uid://b2kjh1fpjptdr" path="res://content/system/camera/camera.tscn" id="3_rj4ac"]
|
||||
[ext_resource type="PackedScene" uid="uid://bsx12q23v8apy" path="res://content/system/hands/hands.tscn" id="4_v8xu6"]
|
||||
[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://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"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhyddd1f0ry1x" path="res://content/ui/onboarding/onboarding.tscn" id="12_uq2nj"]
|
||||
|
||||
[sub_resource type="Sky" id="Sky_vhymk"]
|
||||
sky_material = ExtResource("5_wgwf8")
|
||||
|
||||
[sub_resource type="Environment" id="Environment_7ghp0"]
|
||||
background_mode = 1
|
||||
background_color = Color(0, 0, 0, 0)
|
||||
background_energy_multiplier = 0.0
|
||||
sky = SubResource("Sky_vhymk")
|
||||
ambient_light_source = 2
|
||||
ambient_light_color = Color(1, 1, 1, 1)
|
||||
ssao_radius = 6.52
|
||||
ssao_intensity = 5.68
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"]
|
||||
ao_enabled = true
|
||||
|
||||
|
@ -38,7 +25,7 @@ transform = Transform3D(1, -0.000296142, 0.000270963, 0.000296143, 1, -4.5899e-0
|
|||
script = ExtResource("1_uvrd4")
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_7ghp0")
|
||||
environment = ExtResource("2_lsndp")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(1, -2.51787e-05, 0.000567105, -0.000567105, 4.3985e-08, 1, -2.51784e-05, -1, 2.97105e-08, -4.65661e-10, 7.21041, 2.06458)
|
||||
|
|
242
app/content/system/house/doors/doors.gd
Normal file
242
app/content/system/house/doors/doors.gd
Normal file
|
@ -0,0 +1,242 @@
|
|||
extends Node3D
|
||||
|
||||
const WallCornerScene = preload ("../room/wall_corner.tscn")
|
||||
const WallEdgeScene = preload ("../room/wall_edge.tscn")
|
||||
|
||||
## int | null
|
||||
var editing_door = null
|
||||
|
||||
var room1 = null
|
||||
var room2 = null
|
||||
var room1_corner1 = null
|
||||
var room1_corner2 = null
|
||||
var room2_corner1 = null
|
||||
var room2_corner2 = null
|
||||
|
||||
@onready var ray_cast = $RayCast3D
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func is_editing():
|
||||
return editing_door != null
|
||||
|
||||
func is_valid():
|
||||
return room1 != null&&room2 != null&&room1_corner1 != null&&room1_corner2 != null&&room2_corner1 != null&&room2_corner2 != null
|
||||
|
||||
func add():
|
||||
var doors = Store.house.state.doors
|
||||
|
||||
var next_index = 0
|
||||
for i in range(doors.size()):
|
||||
next_index = max(next_index, doors[i].id)
|
||||
edit(next_index + 1)
|
||||
|
||||
return next_index + 1
|
||||
|
||||
func delete(door):
|
||||
Store.house.state.doors = Store.house.state.doors.filter(func(d): return d.id != door)
|
||||
Store.house.save_local()
|
||||
|
||||
func edit(door):
|
||||
var doors = Store.house.state.doors
|
||||
editing_door = door
|
||||
|
||||
var existing_door = null
|
||||
|
||||
for i in range(doors.size()):
|
||||
if doors[i].id == door:
|
||||
existing_door = doors[i]
|
||||
break
|
||||
|
||||
if existing_door != null:
|
||||
room1 = House.body.find_room(existing_door.room1)
|
||||
room2 = House.body.find_room(existing_door.room2)
|
||||
|
||||
room1_corner1 = WallCornerScene.instantiate()
|
||||
room1_corner1.global_position = existing_door.room1_position1
|
||||
room1_corner1.get_node("Clickable").on_grab_move.connect(_move_corner.bind(room1, room1_corner1))
|
||||
add_child(room1_corner1)
|
||||
|
||||
room1_corner2 = WallCornerScene.instantiate()
|
||||
room1_corner2.global_position = existing_door.room1_position2
|
||||
room1_corner2.get_node("Clickable").on_grab_move.connect(_move_corner.bind(room1, room1_corner2))
|
||||
add_child(room1_corner2)
|
||||
|
||||
room2_corner1 = WallCornerScene.instantiate()
|
||||
room2_corner1.global_position = existing_door.room2_position1
|
||||
room2_corner1.get_node("Clickable").on_grab_move.connect(_move_corner.bind(room2, room2_corner1))
|
||||
add_child(room2_corner1)
|
||||
|
||||
room2_corner2 = WallCornerScene.instantiate()
|
||||
room2_corner2.global_position = existing_door.room2_position2
|
||||
room2_corner2.get_node("Clickable").on_grab_move.connect(_move_corner.bind(room2, room2_corner2))
|
||||
add_child(room2_corner2)
|
||||
|
||||
for room in House.body.get_rooms(0):
|
||||
if room != room1&&room != room2:
|
||||
room.get_node("WallCollision/Clickable").on_click.connect(_add_corner.bind(room))
|
||||
else:
|
||||
room.get_node("WallCollision/Clickable").on_click.disconnect(_add_corner.bind(room))
|
||||
|
||||
for room in House.body.get_rooms(0):
|
||||
if door != null:
|
||||
room.get_node("WallCollision/Clickable").on_click.connect(_add_corner.bind(room))
|
||||
else:
|
||||
room.get_node("WallCollision/Clickable").on_click.disconnect(_add_corner.bind(room))
|
||||
|
||||
func discard():
|
||||
_clear()
|
||||
|
||||
func save():
|
||||
var doors = Store.house.state.doors
|
||||
|
||||
if is_valid() == false:
|
||||
EventSystem.notify("Door is not valid", EventNotify.Type.WARNING)
|
||||
return
|
||||
|
||||
var existing_door_index = -1
|
||||
for i in range(doors.size()):
|
||||
|
||||
if doors[i].id == editing_door:
|
||||
existing_door_index = i
|
||||
break
|
||||
|
||||
var door = {
|
||||
"id": editing_door,
|
||||
"room1": room1.name,
|
||||
"room2": room2.name,
|
||||
"room1_position1": room1_corner1.global_position,
|
||||
"room1_position2": room1_corner2.global_position,
|
||||
"room2_position1": room2_corner1.global_position,
|
||||
"room2_position2": room2_corner2.global_position
|
||||
}
|
||||
|
||||
if existing_door_index == - 1:
|
||||
doors.append(door)
|
||||
else:
|
||||
doors[existing_door_index] = door
|
||||
|
||||
Store.house.state.doors = Store.house.state.doors
|
||||
|
||||
room1.update()
|
||||
room2.update()
|
||||
|
||||
Store.house.save_local()
|
||||
|
||||
_clear()
|
||||
|
||||
func _clear():
|
||||
editing_door = null
|
||||
room1 = null
|
||||
room2 = null
|
||||
|
||||
if room1_corner1 != null:
|
||||
remove_child(room1_corner1)
|
||||
room1_corner1.queue_free()
|
||||
room1_corner1 = null
|
||||
|
||||
if room1_corner2 != null:
|
||||
remove_child(room1_corner2)
|
||||
room1_corner2.queue_free()
|
||||
room1_corner2 = null
|
||||
|
||||
if room2_corner1 != null:
|
||||
remove_child(room2_corner1)
|
||||
room2_corner1.queue_free()
|
||||
room2_corner1 = null
|
||||
|
||||
if room2_corner2 != null:
|
||||
remove_child(room2_corner2)
|
||||
room2_corner2.queue_free()
|
||||
room2_corner2 = null
|
||||
|
||||
func _add_corner(event: EventPointer, room):
|
||||
_match_connected_room(event.ray.get_collision_point(), event.ray.get_collision_normal() * - 1)
|
||||
|
||||
if room1_corner1 == null:
|
||||
if ray_cast.get_collider() == null:
|
||||
EventSystem.notify("Could not find connected room", EventNotify.Type.WARNING)
|
||||
return
|
||||
|
||||
var connected_room = ray_cast.get_collider().get_parent()
|
||||
|
||||
room1 = room
|
||||
room2 = connected_room
|
||||
|
||||
room1_corner1 = WallCornerScene.instantiate()
|
||||
room1_corner1.global_position = event.ray.get_collision_point()
|
||||
room1_corner1.get_node("Clickable").on_grab_move.connect(_move_corner.bind(room, room1_corner1))
|
||||
add_child(room1_corner1)
|
||||
|
||||
room2_corner1 = WallCornerScene.instantiate()
|
||||
room2_corner1.global_position = ray_cast.get_collision_point()
|
||||
room2_corner1.get_node("Clickable").on_grab_move.connect(_move_corner.bind(connected_room, room2_corner1))
|
||||
add_child(room2_corner1)
|
||||
|
||||
elif room1_corner2 == null:
|
||||
if ray_cast.get_collider() == null:
|
||||
EventSystem.notify("Could not find connected room", EventNotify.Type.WARNING)
|
||||
return
|
||||
|
||||
if room1 != room:
|
||||
EventSystem.notify("2nd corner must be in the same room", EventNotify.Type.WARNING)
|
||||
return
|
||||
|
||||
var connected_room = ray_cast.get_collider().get_parent()
|
||||
|
||||
if room2 != connected_room:
|
||||
EventSystem.notify("Connected rooms do not match", EventNotify.Type.WARNING)
|
||||
return
|
||||
|
||||
room1_corner2 = WallCornerScene.instantiate()
|
||||
room1_corner2.global_position = event.ray.get_collision_point()
|
||||
room1_corner2.get_node("Clickable").on_grab_move.connect(_move_corner.bind(room, room1_corner2))
|
||||
add_child(room1_corner2)
|
||||
|
||||
room2_corner2 = WallCornerScene.instantiate()
|
||||
room2_corner2.global_position = ray_cast.get_collision_point()
|
||||
room2_corner2.get_node("Clickable").on_grab_move.connect(_move_corner.bind(connected_room, room2_corner2))
|
||||
add_child(room2_corner2)
|
||||
|
||||
func _move_corner(event: EventPointer, room, corner):
|
||||
_match_room(event.ray.global_position, event.ray.to_global(event.ray.target_position) - event.ray.global_position)
|
||||
|
||||
if ray_cast.get_collider() == null||ray_cast.get_collider().get_parent() != room:
|
||||
return
|
||||
|
||||
var collision_point = ray_cast.get_collision_point()
|
||||
|
||||
_match_connected_room(collision_point, ray_cast.get_collision_normal() * - 1)
|
||||
|
||||
var connected_collision_point = ray_cast.get_collision_point()
|
||||
|
||||
if ray_cast.get_collider() == null||ray_cast.get_collider().get_parent() != _get_connected_room(room):
|
||||
return
|
||||
|
||||
corner.global_position = collision_point
|
||||
_get_connected_corner(corner).global_position = connected_collision_point
|
||||
|
||||
func _get_connected_room(room):
|
||||
return room1 if room == room2 else room2
|
||||
|
||||
func _get_connected_corner(corner):
|
||||
match corner:
|
||||
room1_corner1:
|
||||
return room2_corner1
|
||||
room1_corner2:
|
||||
return room2_corner2
|
||||
room2_corner1:
|
||||
return room1_corner1
|
||||
room2_corner2:
|
||||
return room1_corner2
|
||||
|
||||
func _match_room(pos: Vector3, dir: Vector3):
|
||||
ray_cast.global_position = pos
|
||||
ray_cast.target_position = dir.normalized() * 1000
|
||||
ray_cast.force_raycast_update()
|
||||
|
||||
func _match_connected_room(pos: Vector3, dir: Vector3):
|
||||
ray_cast.global_position = pos
|
||||
ray_cast.target_position = dir.normalized() * 1000
|
||||
ray_cast.force_raycast_update()
|
12
app/content/system/house/doors/doors.tscn
Normal file
12
app/content/system/house/doors/doors.tscn
Normal file
|
@ -0,0 +1,12 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://c8nh8582vwc8u"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/system/house/doors/doors.gd" id="1_rsgao"]
|
||||
|
||||
[node name="Doors" type="Node3D"]
|
||||
script = ExtResource("1_rsgao")
|
||||
|
||||
[node name="RayCast3D" type="RayCast3D" parent="."]
|
||||
top_level = true
|
||||
enabled = false
|
||||
collision_mask = 16
|
||||
hit_from_inside = true
|
|
@ -3,12 +3,14 @@ extends Node3D
|
|||
const Room = preload ("./room/room.tscn")
|
||||
const RoomType = preload ("./room/room.gd")
|
||||
const Miniature = preload ("./mini/miniature.gd")
|
||||
const Doors = preload ("./doors/doors.gd")
|
||||
const AlignReference = preload ("./align_reference.gd")
|
||||
|
||||
@onready var levels = $Levels
|
||||
@onready var collision_shape = $Levels/CollisionShape3D
|
||||
@onready var align_reference: AlignReference = $AlignReference
|
||||
@onready var mini_view: Miniature = $Levels/Miniature
|
||||
@onready var doors: Doors = $Levels/Doors
|
||||
|
||||
var fixing_reference: bool = false
|
||||
var editing_room: RoomType = null
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://cbemihbxkd4ll"]
|
||||
[gd_scene load_steps=7 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"]
|
||||
[ext_resource type="PackedScene" uid="uid://c8nh8582vwc8u" path="res://content/system/house/doors/doors.tscn" id="4_bb3c2"]
|
||||
[ext_resource type="PackedScene" uid="uid://ds60i5n211hi3" path="res://content/system/house/mini/miniature.tscn" id="4_qjbly"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_x81up"]
|
||||
|
@ -25,6 +26,8 @@ lock_rotation = true
|
|||
|
||||
[node name="Miniature" parent="Levels" instance=ExtResource("4_qjbly")]
|
||||
|
||||
[node name="Doors" parent="Levels" instance=ExtResource("4_bb3c2")]
|
||||
|
||||
[node name="AlignReference" parent="." instance=ExtResource("3_e1tcn")]
|
||||
visible = false
|
||||
disabled = true
|
||||
|
|
|
@ -63,7 +63,15 @@ func _ready():
|
|||
model.add_child(walls_mesh)
|
||||
model.add_child(floor_mesh)
|
||||
|
||||
walls_mesh.mesh=ConstructRoomMesh.generate_wall_mesh_grid(room.corners, room.height)
|
||||
var doors=[]
|
||||
|
||||
for door in Store.house.state.doors:
|
||||
if door.room1 == room.name:
|
||||
doors.append([door.room1_position1, door.room1_position2])
|
||||
elif door.room2 == room.name:
|
||||
doors.append([door.room2_position1, door.room2_position2])
|
||||
|
||||
walls_mesh.mesh=ConstructRoomMesh.generate_wall_mesh_with_doors_grid(room.corners, room.height, doors)
|
||||
floor_mesh.mesh=ConstructRoomMesh.generate_ceiling_mesh_grid(room.corners)
|
||||
|
||||
walls_mesh.material_override=wall_material
|
||||
|
|
|
@ -19,10 +19,7 @@ var editable: bool = false:
|
|||
|
||||
if !is_inside_tree(): return
|
||||
|
||||
if editable:
|
||||
state_machine.change_to("Edit")
|
||||
else:
|
||||
state_machine.change_to("View")
|
||||
update()
|
||||
|
||||
func _ready():
|
||||
Update.props(self, ["editable"])
|
||||
|
@ -30,6 +27,12 @@ func _ready():
|
|||
func has_point(point: Vector3) -> bool:
|
||||
return get_aabb().has_point(point)
|
||||
|
||||
func update():
|
||||
if editable:
|
||||
state_machine.change_to("Edit")
|
||||
else:
|
||||
state_machine.change_to("View")
|
||||
|
||||
func get_aabb():
|
||||
var room_store = Store.house.get_room(name)
|
||||
|
||||
|
@ -56,13 +59,26 @@ func get_aabb():
|
|||
|
||||
return AABB(to_global(min_pos), to_global(max_pos) - to_global(min_pos))
|
||||
|
||||
static func generate_wall_mesh(room_store: Dictionary):
|
||||
var corners = room_store.corners
|
||||
var height = room_store.height
|
||||
func generate_wall_mesh():
|
||||
var room = Store.house.get_room(name)
|
||||
|
||||
return ConstructRoomMesh.generate_wall_mesh(corners, height)
|
||||
if room == null||room.corners.size() < 3:
|
||||
return null
|
||||
|
||||
static func generate_ceiling_mesh(room_store: Dictionary):
|
||||
var corners = room_store.corners
|
||||
var corners = room.corners
|
||||
var height = room.height
|
||||
var doors = []
|
||||
|
||||
for door in Store.house.state.doors:
|
||||
if door.room1 == name:
|
||||
doors.append([door.room1_position1, door.room1_position2])
|
||||
elif door.room2 == name:
|
||||
doors.append([door.room2_position1, door.room2_position2])
|
||||
|
||||
# return ConstructRoomMesh.generate_wall_mesh(corners, height)
|
||||
return ConstructRoomMesh.generate_wall_mesh_with_doors(corners, height, doors)
|
||||
|
||||
static func generate_ceiling_mesh(room: Dictionary):
|
||||
var corners = room.corners
|
||||
|
||||
return ConstructRoomMesh.generate_ceiling_mesh(corners)
|
||||
|
|
|
@ -37,6 +37,9 @@ collision_mask = 0
|
|||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="WallCollision"]
|
||||
|
||||
[node name="Clickable" type="Node" parent="WallCollision"]
|
||||
script = ExtResource("1_ugebq")
|
||||
|
||||
[node name="Ceiling" type="StaticBody3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
|
||||
collision_layer = 24
|
||||
|
|
|
@ -5,10 +5,10 @@ const RoomState = preload ("./room_state.gd")
|
|||
func _on_enter():
|
||||
var room_store = Store.house.get_room(room.name)
|
||||
|
||||
if room_store == null||room_store.corners.size() < 3:
|
||||
if room_store == null:
|
||||
return
|
||||
|
||||
room.wall_mesh.mesh = Room.generate_wall_mesh(room_store)
|
||||
room.wall_mesh.mesh = room.generate_wall_mesh()
|
||||
|
||||
if room.wall_mesh.mesh == null:
|
||||
return
|
||||
|
|
|
@ -127,6 +127,7 @@ size = Vector3(0.14, 0.03, 0.01)
|
|||
|
||||
[node name="Background" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 1.06581e-14, 0, -1.06581e-14, 1, 0.21, -0.16, 0)
|
||||
visible = false
|
||||
material_override = SubResource("ShaderMaterial_hstwo")
|
||||
mesh = SubResource("QuadMesh_4pj6f")
|
||||
skeleton = NodePath("../..")
|
||||
|
|
|
@ -269,7 +269,6 @@ visible = false
|
|||
[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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=10 format=3 uid="uid://c01gkeldvjwtr"]
|
||||
[gd_scene load_steps=11 format=3 uid="uid://c01gkeldvjwtr"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/ui/menu/room/room_menu.gd" id="1_ch4jb"]
|
||||
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="4_cghmp"]
|
||||
|
@ -7,6 +7,7 @@
|
|||
[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"]
|
||||
[ext_resource type="Shader" path="res://content/ui/components/panel/glass.gdshader" id="7_bxp1w"]
|
||||
[ext_resource type="PackedScene" uid="uid://biwinf4360f10" path="res://content/ui/menu/room/views/doors.tscn" id="7_fl4l8"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_2asng"]
|
||||
render_priority = -3
|
||||
|
@ -46,13 +47,22 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.1, 0, 0)
|
|||
label = "Rooms"
|
||||
size = Vector3(0.06, 0.04, 0.01)
|
||||
|
||||
[node name="Doors" parent="Interface/Tabs3D" instance=ExtResource("4_cghmp")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.17, 0, 0)
|
||||
label = "Doors"
|
||||
size = Vector3(0.06, 0.04, 0.01)
|
||||
|
||||
[node name="TabsContent3D" type="Node3D" parent="Interface" node_paths=PackedStringArray("tabs")]
|
||||
script = ExtResource("6_ba00g")
|
||||
tabs = NodePath("../Tabs3D")
|
||||
|
||||
[node name="Overview" parent="Interface/TabsContent3D" instance=ExtResource("6_206ad")]
|
||||
visible = false
|
||||
|
||||
[node name="Rooms" parent="Interface/TabsContent3D" instance=ExtResource("7_2f8e0")]
|
||||
visible = false
|
||||
|
||||
[node name="Doors" parent="Interface/TabsContent3D" instance=ExtResource("7_fl4l8")]
|
||||
|
||||
[node name="Background" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 1.06581e-14, 0, -1.06581e-14, 1, 0.21, -0.16, 0)
|
||||
|
|
64
app/content/ui/menu/room/views/doors.gd
Normal file
64
app/content/ui/menu/room/views/doors.gd
Normal file
|
@ -0,0 +1,64 @@
|
|||
extends Node3D
|
||||
|
||||
const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd")
|
||||
|
||||
const material_selected = preload ("../room_selected.tres")
|
||||
const material_unselected = preload ("../room_unselected.tres")
|
||||
|
||||
@onready var door_button = $Button
|
||||
@onready var delete_button = $DeleteButton
|
||||
@onready var door_label = $Label3D
|
||||
@onready var rooms_map = $Rooms
|
||||
@onready var doors_map = $Doors
|
||||
|
||||
var editing_door = R.state(false)
|
||||
|
||||
func _ready():
|
||||
rooms_map.selectable.value = false
|
||||
|
||||
var button_icon = R.computed(func(_arg):
|
||||
if doors_map.selected_door.value == null:
|
||||
return "add"
|
||||
elif editing_door.value == false:
|
||||
return "edit"
|
||||
else:
|
||||
return "save"
|
||||
)
|
||||
|
||||
R.bind(door_button, "label", button_icon)
|
||||
|
||||
var button_label = R.computed(func(_arg):
|
||||
if doors_map.selected_door.value == null:
|
||||
return "Add Door"
|
||||
elif editing_door.value == false:
|
||||
return "Edit Door"
|
||||
else:
|
||||
return "Save Door"
|
||||
)
|
||||
|
||||
R.bind(door_label, "text", button_label)
|
||||
|
||||
R.effect(func(_arg):
|
||||
delete_button.disabled=doors_map.selected_door.value == null
|
||||
delete_button.visible=doors_map.selected_door.value != null
|
||||
)
|
||||
|
||||
door_button.on_button_up.connect(func():
|
||||
if doors_map.selected_door.value == null:
|
||||
var id=House.body.doors.add()
|
||||
editing_door.value=true
|
||||
doors_map.selected_door.value=id
|
||||
elif editing_door.value == false:
|
||||
editing_door.value=true
|
||||
House.body.doors.edit(doors_map.selected_door.value)
|
||||
else:
|
||||
House.body.doors.save()
|
||||
editing_door.value=false
|
||||
)
|
||||
|
||||
delete_button.on_button_up.connect(func():
|
||||
if doors_map.selected_door.value != null:
|
||||
House.body.doors.delete(doors_map.selected_door.value)
|
||||
doors_map.selected_door.value=null
|
||||
)
|
||||
|
66
app/content/ui/menu/room/views/doors.tscn
Normal file
66
app/content/ui/menu/room/views/doors.tscn
Normal file
|
@ -0,0 +1,66 @@
|
|||
[gd_scene load_steps=9 format=3 uid="uid://biwinf4360f10"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/ui/menu/room/views/doors.gd" id="1_22w4h"]
|
||||
[ext_resource type="Script" path="res://content/ui/menu/room/views/rooms_map.gd" id="2_to21g"]
|
||||
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="2_v01ty"]
|
||||
[ext_resource type="Script" path="res://content/ui/menu/room/views/doors_map.gd" id="3_0k2cc"]
|
||||
[ext_resource type="Shader" path="res://content/ui/components/panel/glass.gdshader" id="4_eorpn"]
|
||||
|
||||
[sub_resource type="QuadMesh" id="QuadMesh_lkxbm"]
|
||||
size = Vector2(0.2, 0.2)
|
||||
orientation = 1
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_dah0r"]
|
||||
render_priority = -3
|
||||
shader = ExtResource("4_eorpn")
|
||||
shader_parameter/color = Color(1, 1, 1, 0.3)
|
||||
shader_parameter/border_color = Color(1, 1, 1, 1)
|
||||
shader_parameter/edge_color = Color(0, 0, 0, 1)
|
||||
shader_parameter/size = Vector2(0.42, 0.32)
|
||||
shader_parameter/border_size = 0.001
|
||||
shader_parameter/border_fade_in = 0.005
|
||||
shader_parameter/border_fade_out = 0.0
|
||||
shader_parameter/corner_radius = 0.02
|
||||
shader_parameter/roughness = 0.3
|
||||
shader_parameter/grain_amount = 0.02
|
||||
|
||||
[sub_resource type="QuadMesh" id="QuadMesh_fq44b"]
|
||||
size = Vector2(0.42, 0.32)
|
||||
|
||||
[node name="Doors" type="Node3D"]
|
||||
script = ExtResource("1_22w4h")
|
||||
|
||||
[node name="Rooms" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0.12, -0.16, 0.005)
|
||||
script = ExtResource("2_to21g")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Rooms"]
|
||||
mesh = SubResource("QuadMesh_lkxbm")
|
||||
|
||||
[node name="Doors" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0.12, -0.16, 0.006)
|
||||
script = ExtResource("3_0k2cc")
|
||||
|
||||
[node name="Button" parent="." instance=ExtResource("2_v01ty")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.04, -0.28, 0)
|
||||
label = "add"
|
||||
icon = true
|
||||
|
||||
[node name="DeleteButton" parent="." instance=ExtResource("2_v01ty")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.2, -0.28, 0)
|
||||
label = "delete"
|
||||
icon = true
|
||||
|
||||
[node name="Background" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 1.06581e-14, 0, -1.06581e-14, 1, 0.21, -0.16, 0)
|
||||
material_override = SubResource("ShaderMaterial_dah0r")
|
||||
mesh = SubResource("QuadMesh_fq44b")
|
||||
skeleton = NodePath("../..")
|
||||
|
||||
[node name="Label3D" type="Label3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.07, -0.28, 0)
|
||||
pixel_size = 0.001
|
||||
text = "Add Door"
|
||||
font_size = 18
|
||||
outline_size = 0
|
||||
horizontal_alignment = 0
|
87
app/content/ui/menu/room/views/doors_map.gd
Normal file
87
app/content/ui/menu/room/views/doors_map.gd
Normal file
|
@ -0,0 +1,87 @@
|
|||
extends Node3D
|
||||
|
||||
const BoundingBoxTools = preload ("res://lib/utils/mesh/bounding_box_tools.gd")
|
||||
const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd")
|
||||
|
||||
const material_selected = preload ("../room_selected.tres")
|
||||
const material_unselected = preload ("../room_unselected.tres")
|
||||
|
||||
var selectable = R.state(true)
|
||||
var selected_door = R.state(null)
|
||||
|
||||
func _ready():
|
||||
R.effect(func(_arg):
|
||||
var rooms=Store.house.state.rooms
|
||||
var doors=Store.house.state.doors
|
||||
|
||||
for old_room in get_children():
|
||||
remove_child(old_room)
|
||||
old_room.queue_free()
|
||||
|
||||
if rooms.size() == 0:
|
||||
return
|
||||
|
||||
var target_rect=Rect2(0.0, 0.0, 0.2, 0.2)
|
||||
var rooms_rect=Rect2()
|
||||
|
||||
for room in rooms:
|
||||
rooms_rect=rooms_rect.merge(BoundingBoxTools.get_bounding_box_2d(room.corners))
|
||||
|
||||
var box_transform=BoundingBoxTools.resize_bounding_box_2d(rooms_rect, target_rect)
|
||||
|
||||
for door in doors:
|
||||
var door_points=[
|
||||
Vector2(door.room1_position1.x, door.room1_position1.z),
|
||||
Vector2(door.room1_position2.x, door.room1_position2.z),
|
||||
Vector2(door.room2_position2.x, door.room2_position2.z),
|
||||
Vector2(door.room2_position1.x, door.room2_position1.z)
|
||||
]
|
||||
var mesh=ConstructRoomMesh.generate_ceiling_mesh(door_points)
|
||||
|
||||
if mesh == null:
|
||||
continue
|
||||
|
||||
var body=StaticBody3D.new()
|
||||
body.name=str(door.id)
|
||||
body.position.x=box_transform.origin.x
|
||||
body.position.z=box_transform.origin.y
|
||||
body.set_collision_layer_value(1, false)
|
||||
body.set_collision_layer_value(2, true)
|
||||
|
||||
var mesh_instance=MeshInstance3D.new()
|
||||
mesh_instance.name="Mesh"
|
||||
mesh_instance.mesh=mesh
|
||||
mesh_instance.material_override=material_unselected if selected_door.value != door.id 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)
|
||||
|
||||
add_child(body)
|
||||
|
||||
var box_scale=box_transform.get_scale()
|
||||
var min_scale=min(box_scale.x, box_scale.y)
|
||||
scale=Vector3(min_scale, min_scale, min_scale)
|
||||
)
|
||||
|
||||
func _on_click(event: EventPointer):
|
||||
if selectable.value == false:
|
||||
return
|
||||
|
||||
var door_id = int(str(event.target.name))
|
||||
|
||||
if selected_door.value == door_id:
|
||||
selected_door.value = null
|
||||
return
|
||||
|
||||
selected_door.value = door_id
|
||||
|
||||
func get_room(door_id):
|
||||
if door_id == null:
|
||||
return null
|
||||
|
||||
if has_node(str(door_id)):
|
||||
return get_node(str(door_id))
|
||||
return null
|
|
@ -1,162 +1,72 @@
|
|||
extends Node3D
|
||||
|
||||
const Room = preload ("res://content/system/house/room/room.tscn")
|
||||
const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd")
|
||||
|
||||
const material_selected = preload ("../room_selected.tres")
|
||||
const material_unselected = preload ("../room_unselected.tres")
|
||||
const RoomsMap = preload ("rooms_map.gd")
|
||||
|
||||
@onready var room_button = $Button
|
||||
@onready var input = $Input
|
||||
@onready var rooms_map = $Rooms
|
||||
@onready var rooms_map: RoomsMap = $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)
|
||||
|
||||
var old_room = get_room(selected_room)
|
||||
|
||||
if old_room != null:
|
||||
old_room.get_node("MeshInstance3D").material_override = material_unselected
|
||||
|
||||
if value != null:
|
||||
room_button.label = "edit"
|
||||
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):
|
||||
if value == edit_room:
|
||||
return
|
||||
|
||||
edit_room = value
|
||||
if value:
|
||||
room_button.label = "save"
|
||||
input.disabled = false
|
||||
else:
|
||||
room_button.label = "edit"
|
||||
input.disabled = true
|
||||
|
||||
if selected_room != null&&selected_room != input.text:
|
||||
House.body.rename_room(selected_room, input.text)
|
||||
selected_room = input.text
|
||||
var editing_room = R.state(false)
|
||||
|
||||
func _ready():
|
||||
|
||||
R.effect(func(_arg):
|
||||
if rooms_map.selected_room.value == null:
|
||||
room_button.label="add"
|
||||
elif editing_room.value:
|
||||
room_button.label="save"
|
||||
else:
|
||||
room_button.label="edit"
|
||||
)
|
||||
|
||||
R.effect(func(_arg):
|
||||
input.disabled=editing_room.value == false
|
||||
)
|
||||
|
||||
R.effect(func(_arg):
|
||||
if rooms_map.selected_room.value == null:
|
||||
var i=1
|
||||
while rooms_map.get_room("Room %s" % i) != null:
|
||||
i += 1
|
||||
|
||||
input.text="Room %s" % i
|
||||
else:
|
||||
input.text=rooms_map.selected_room.value
|
||||
)
|
||||
|
||||
if !Store.house.is_loaded(): await Store.house.on_loaded
|
||||
|
||||
_generate_room_map()
|
||||
|
||||
input.text = "Room %s" % (rooms_map.get_child_count() + 1)
|
||||
|
||||
room_button.on_button_down.connect(func():
|
||||
if selected_room == null:
|
||||
var selected_room=rooms_map.selected_room
|
||||
|
||||
if selected_room.value == null:
|
||||
var room_name=input.text
|
||||
if get_room(room_name) != null:
|
||||
if rooms_map.get_room(room_name) != null:
|
||||
EventSystem.notify("Name already taken", EventNotify.Type.WARNING)
|
||||
return
|
||||
|
||||
House.body.create_room(room_name, 0)
|
||||
House.body.edit_room(room_name)
|
||||
selected_room=room_name
|
||||
edit_room=true
|
||||
selected_room.value=room_name
|
||||
editing_room.value=true
|
||||
rooms_map.selectable.value=false
|
||||
else:
|
||||
if edit_room:
|
||||
edit_room=false
|
||||
editing_room.value=!editing_room.value
|
||||
rooms_map.selectable.value=!editing_room.value
|
||||
|
||||
if !House.body.is_valid_room(selected_room):
|
||||
if editing_room.value == false:
|
||||
if !House.body.is_valid_room(selected_room.value):
|
||||
EventSystem.notify("Room was deleted as it had less than 3 corners.", EventNotify.Type.WARNING)
|
||||
House.body.delete_room(selected_room)
|
||||
selected_room=null
|
||||
else:
|
||||
House.body.edit_room(null)
|
||||
_generate_room_map()
|
||||
House.body.delete_room(selected_room.value)
|
||||
selected_room.value=null
|
||||
return
|
||||
|
||||
if selected_room.value != null&&selected_room.value != input.text:
|
||||
House.body.rename_room(selected_room.value, input.text)
|
||||
selected_room.value=input.text
|
||||
|
||||
House.body.edit_room(null)
|
||||
else:
|
||||
edit_room=true
|
||||
House.body.edit_room(selected_room)
|
||||
House.body.edit_room(selected_room.value)
|
||||
)
|
||||
|
||||
func get_room(room_name):
|
||||
if room_name == null:
|
||||
return null
|
||||
|
||||
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 = Store.house.state.rooms
|
||||
|
||||
var target_size = Vector2(0.2, 0.2)
|
||||
var target_offset = Vector2(0, 0.05)
|
||||
|
||||
for old_room in rooms_map.get_children():
|
||||
old_room.queue_free()
|
||||
await old_room.tree_exited
|
||||
|
||||
if rooms.size() == 0:
|
||||
return
|
||||
|
||||
if rooms[0].corners.size() == 0:
|
||||
return
|
||||
|
||||
var current_min = Vector2(rooms[0].corners[0].x, rooms[0].corners[0].y)
|
||||
var current_max = current_min
|
||||
|
||||
for room in rooms:
|
||||
for corner in room.corners:
|
||||
current_min.x = min(current_min.x, corner.x)
|
||||
current_min.y = min(current_min.y, corner.y)
|
||||
current_max.x = max(current_max.x, corner.x)
|
||||
current_max.y = max(current_max.y, corner.y)
|
||||
|
||||
for room in rooms:
|
||||
var mesh = ConstructRoomMesh.generate_ceiling_mesh(room.corners)
|
||||
|
||||
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.y)
|
||||
|
||||
rooms_map.position.x = -current_min.x * scale_value + target_offset.x
|
||||
rooms_map.position.y = current_min.y * scale_value - target_offset.y
|
||||
rooms_map.position.z = 0.002
|
||||
|
||||
rooms_map.scale = Vector3(scale_value, scale_value, scale_value)
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
[gd_scene load_steps=7 format=3 uid="uid://bpta22fahai46"]
|
||||
[gd_scene load_steps=9 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="Script" path="res://content/ui/menu/room/views/rooms_map.gd" id="2_2t24u"]
|
||||
[ext_resource type="PackedScene" uid="uid://blrhy2uccrdn4" path="res://content/ui/components/input/input.tscn" id="2_hstw7"]
|
||||
[ext_resource type="Shader" path="res://content/ui/components/panel/glass.gdshader" id="4_jx6i3"]
|
||||
|
||||
[sub_resource type="QuadMesh" id="QuadMesh_ehu5x"]
|
||||
size = Vector2(0.2, 0.2)
|
||||
orientation = 1
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_dah0r"]
|
||||
render_priority = -3
|
||||
shader = ExtResource("4_jx6i3")
|
||||
|
@ -26,7 +31,11 @@ size = Vector2(0.42, 0.32)
|
|||
script = ExtResource("1_3a1oa")
|
||||
|
||||
[node name="Rooms" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0.14, -0.15, 0)
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0.12, -0.16, 0.005)
|
||||
script = ExtResource("2_2t24u")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Rooms"]
|
||||
mesh = SubResource("QuadMesh_ehu5x")
|
||||
|
||||
[node name="Button" parent="." instance=ExtResource("1_y3lty")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.2, -0.28, 0)
|
||||
|
|
86
app/content/ui/menu/room/views/rooms_map.gd
Normal file
86
app/content/ui/menu/room/views/rooms_map.gd
Normal file
|
@ -0,0 +1,86 @@
|
|||
extends Node3D
|
||||
|
||||
const BoundingBoxTools = preload ("res://lib/utils/mesh/bounding_box_tools.gd")
|
||||
const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd")
|
||||
|
||||
const material_selected = preload ("../room_selected.tres")
|
||||
const material_unselected = preload ("../room_unselected.tres")
|
||||
|
||||
var selectable = R.state(true)
|
||||
var selected_room = R.state(null)
|
||||
|
||||
func _ready():
|
||||
R.effect(func(_arg):
|
||||
var rooms=Store.house.state.rooms
|
||||
|
||||
for old_room in get_children():
|
||||
remove_child(old_room)
|
||||
old_room.queue_free()
|
||||
|
||||
if rooms.size() == 0:
|
||||
return
|
||||
|
||||
var target_rect=Rect2(0.0, 0.0, 0.2, 0.2)
|
||||
var rooms_rect=Rect2()
|
||||
|
||||
for room in rooms:
|
||||
rooms_rect=rooms_rect.merge(BoundingBoxTools.get_bounding_box_2d(room.corners))
|
||||
|
||||
var box_transform=BoundingBoxTools.resize_bounding_box_2d(rooms_rect, target_rect)
|
||||
|
||||
for room in rooms:
|
||||
var mesh=ConstructRoomMesh.generate_ceiling_mesh(room.corners)
|
||||
|
||||
if mesh == null:
|
||||
continue
|
||||
|
||||
var body=StaticBody3D.new()
|
||||
body.name=room.name
|
||||
body.position.x=box_transform.origin.x
|
||||
body.position.z=box_transform.origin.y
|
||||
body.set_collision_layer_value(1, false)
|
||||
body.set_collision_layer_value(2, true)
|
||||
|
||||
var mesh_instance=MeshInstance3D.new()
|
||||
mesh_instance.name="Mesh"
|
||||
mesh_instance.mesh=mesh
|
||||
mesh_instance.material_override=material_unselected if selected_room.value != 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)
|
||||
|
||||
add_child(body)
|
||||
|
||||
var box_scale=box_transform.get_scale()
|
||||
var min_scale=min(box_scale.x, box_scale.y)
|
||||
scale=Vector3(min_scale, min_scale, min_scale)
|
||||
)
|
||||
|
||||
func _on_click(event: EventPointer):
|
||||
if selectable.value == false:
|
||||
return
|
||||
|
||||
var previous_room = get_room(selected_room.value)
|
||||
|
||||
if previous_room != null:
|
||||
previous_room.get_node("Mesh").material_override = material_unselected
|
||||
|
||||
var room_name = event.target.name
|
||||
|
||||
if selected_room.value == room_name:
|
||||
selected_room.value = null
|
||||
return
|
||||
|
||||
selected_room.value = room_name
|
||||
get_room(selected_room.value).get_node("Mesh").material_override = material_selected
|
||||
|
||||
func get_room(room_name):
|
||||
if room_name == null:
|
||||
return null
|
||||
|
||||
if has_node(str(room_name)):
|
||||
return get_node(str(room_name))
|
||||
return null
|
|
@ -36,7 +36,6 @@ func _ready():
|
|||
var success = Store.settings.load_local()
|
||||
|
||||
if success:
|
||||
print(Store.settings)
|
||||
start_adapter(Store.settings.state.type.to_lower(), Store.settings.state.url, Store.settings.state.token)
|
||||
|
||||
## Starts the adapter for the given type and url
|
||||
|
|
|
@ -19,6 +19,15 @@ func _init():
|
|||
## room: String
|
||||
## interface: String
|
||||
"entities": [],
|
||||
## Type Door
|
||||
## id: int
|
||||
## room1: String
|
||||
## room2: String
|
||||
## room1_position1: Vec3
|
||||
## room1_position2: Vec3
|
||||
## room2_position1: Vec3
|
||||
## room2_position2: Vec3
|
||||
"doors": [],
|
||||
"align_position1": Vector3(),
|
||||
"align_position2": Vector3()
|
||||
})
|
||||
|
|
22
app/lib/utils/mesh/bounding_box_tools.gd
Normal file
22
app/lib/utils/mesh/bounding_box_tools.gd
Normal file
|
@ -0,0 +1,22 @@
|
|||
static func get_bounding_box_2d(points) -> Rect2:
|
||||
if points.size() == 0:
|
||||
return Rect2()
|
||||
|
||||
var min_x = points[0].x
|
||||
var min_y = points[0].y
|
||||
var max_x = points[0].x
|
||||
var max_y = points[0].y
|
||||
|
||||
for i in range(1, points.size()):
|
||||
min_x = min(min_x, points[i].x)
|
||||
min_y = min(min_y, points[i].y)
|
||||
max_x = max(max_x, points[i].x)
|
||||
max_y = max(max_y, points[i].y)
|
||||
|
||||
return Rect2(Vector2(min_x, min_y), Vector2(max_x - min_x, max_y - min_y))
|
||||
|
||||
static func resize_bounding_box_2d(bbox: Rect2, target_box: Rect2) -> Transform2D:
|
||||
var scale = Vector2(target_box.size.x / bbox.size.x, target_box.size.y / bbox.size.y)
|
||||
var offset = target_box.get_center() - bbox.get_center()
|
||||
|
||||
return Transform2D(0, scale, 0, offset)
|
|
@ -25,6 +25,84 @@ static func generate_wall_mesh(corners, height):
|
|||
|
||||
return mesh
|
||||
|
||||
## Generate a wall mesh with doors
|
||||
## corners: Array of Vector2
|
||||
## height: float
|
||||
## doors: Array[Array[Vector3, Vector3]]
|
||||
static func generate_wall_mesh_with_doors(corners, height, doors):
|
||||
if corners.size() < 3:
|
||||
return null
|
||||
|
||||
var mesh = ArrayMesh.new()
|
||||
|
||||
for i in range(0, corners.size()):
|
||||
var corner = corners[i]
|
||||
var next_corner = corners[(i + 1) % corners.size()]
|
||||
|
||||
var forward = Vector3(next_corner.x - corner.x, 0, next_corner.y - corner.y).normalized()
|
||||
|
||||
var points := PackedVector2Array()
|
||||
|
||||
points.append(Vector2(0, 0))
|
||||
points.append(Vector2(0, height))
|
||||
points.append(Vector2(corner.distance_to(next_corner), height))
|
||||
points.append(Vector2(corner.distance_to(next_corner), 0))
|
||||
|
||||
for door in doors:
|
||||
var door_point1 = Vector2(door[0].x, door[0].z)
|
||||
var door_point2 = Vector2(door[1].x, door[1].z)
|
||||
var proj_point1 = Geometry2D.get_closest_point_to_segment_uncapped(door_point1, corner, next_corner)
|
||||
var proj_point2 = Geometry2D.get_closest_point_to_segment_uncapped(door_point2, corner, next_corner)
|
||||
|
||||
if proj_point1.distance_to(door_point1) > 0.02&&proj_point2.distance_to(door_point2) > 0.02:
|
||||
continue
|
||||
|
||||
if proj_point1.distance_to(proj_point2) < 0.02:
|
||||
continue
|
||||
|
||||
var point1_distance = corner.distance_to(proj_point1)
|
||||
var point2_distance = corner.distance_to(proj_point2)
|
||||
|
||||
var door_points := PackedVector2Array()
|
||||
|
||||
door_points.append(Vector2(point1_distance, -1))
|
||||
door_points.append(Vector2(point1_distance, door[0].y))
|
||||
door_points.append(Vector2(point2_distance, door[1].y))
|
||||
door_points.append(Vector2(point2_distance, -1))
|
||||
|
||||
var clip = Geometry2D.clip_polygons(points, door_points)
|
||||
if clip.size() == 0:
|
||||
continue
|
||||
|
||||
assert(clip.size() != 2, "Door clip should not create holes")
|
||||
|
||||
points = clip[0]
|
||||
|
||||
var edges = PackedInt32Array()
|
||||
for k in range(points.size()):
|
||||
edges.append(k)
|
||||
edges.append((k + 1) % points.size())
|
||||
|
||||
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()
|
||||
var triangles: PackedInt32Array = cdt.get_all_triangles()
|
||||
|
||||
var points_3d = PackedVector3Array()
|
||||
|
||||
for k in range(points.size()):
|
||||
points_3d.append(Vector3(corner.x, 0, corner.y) + points[k].x * forward + Vector3(0, points[k].y, 0))
|
||||
|
||||
mesh = _create_mesh_3d(points_3d, triangles, mesh)
|
||||
|
||||
return mesh
|
||||
|
||||
static func generate_ceiling_mesh(corners):
|
||||
var points: PackedVector2Array = PackedVector2Array()
|
||||
var edges: PackedInt32Array = PackedInt32Array()
|
||||
|
@ -51,7 +129,107 @@ static func generate_ceiling_mesh(corners):
|
|||
points = cdt.get_all_vertices()
|
||||
triangles = cdt.get_all_triangles()
|
||||
|
||||
return _create_mesh(points, triangles)
|
||||
return _create_mesh_2d(points, triangles)
|
||||
|
||||
static func generate_wall_mesh_with_doors_grid(corners, height, doors, grid:=0.1):
|
||||
if corners.size() < 3:
|
||||
return null
|
||||
|
||||
var mesh = ArrayMesh.new()
|
||||
|
||||
for i in range(0, corners.size()):
|
||||
var corner = corners[i]
|
||||
var next_corner = corners[(i + 1) % corners.size()]
|
||||
|
||||
var forward = Vector3(next_corner.x - corner.x, 0, next_corner.y - corner.y).normalized()
|
||||
|
||||
var points := PackedVector2Array()
|
||||
|
||||
points.append(Vector2(0, 0))
|
||||
points.append(Vector2(0, height))
|
||||
points.append(Vector2(corner.distance_to(next_corner), height))
|
||||
points.append(Vector2(corner.distance_to(next_corner), 0))
|
||||
|
||||
for door in doors:
|
||||
var door_point1 = Vector2(door[0].x, door[0].z)
|
||||
var door_point2 = Vector2(door[1].x, door[1].z)
|
||||
var proj_point1 = Geometry2D.get_closest_point_to_segment_uncapped(door_point1, corner, next_corner)
|
||||
var proj_point2 = Geometry2D.get_closest_point_to_segment_uncapped(door_point2, corner, next_corner)
|
||||
|
||||
if proj_point1.distance_to(door_point1) > 0.02&&proj_point2.distance_to(door_point2) > 0.02:
|
||||
continue
|
||||
|
||||
if proj_point1.distance_to(proj_point2) < 0.02:
|
||||
continue
|
||||
|
||||
var point1_distance = corner.distance_to(proj_point1)
|
||||
var point2_distance = corner.distance_to(proj_point2)
|
||||
|
||||
var door_points := PackedVector2Array()
|
||||
|
||||
door_points.append(Vector2(point1_distance, -1))
|
||||
door_points.append(Vector2(point1_distance, door[0].y))
|
||||
door_points.append(Vector2(point2_distance, door[1].y))
|
||||
door_points.append(Vector2(point2_distance, -1))
|
||||
|
||||
var clip = Geometry2D.clip_polygons(points, door_points)
|
||||
if clip.size() == 0:
|
||||
continue
|
||||
|
||||
assert(clip.size() != 2, "Door clip should not create holes")
|
||||
|
||||
points = clip[0]
|
||||
|
||||
# Subdivide edge to grid
|
||||
|
||||
var new_points = PackedVector2Array()
|
||||
|
||||
for k in range(points.size()):
|
||||
var point = points[k]
|
||||
var next_point = points[(k + 1) % points.size()]
|
||||
|
||||
new_points.append(point)
|
||||
|
||||
var steps = floor(point.distance_to(next_point) / grid)
|
||||
|
||||
for x in range(1, steps):
|
||||
new_points.append(point + (next_point - point).normalized() * grid * x)
|
||||
|
||||
points = new_points
|
||||
|
||||
var edges = PackedInt32Array()
|
||||
for k in range(points.size()):
|
||||
edges.append(k)
|
||||
edges.append((k + 1) % points.size())
|
||||
|
||||
# Subdivide inner polygon to grid
|
||||
var steps = ceil(Vector2(corner.distance_to(next_corner) / grid, height / grid))
|
||||
|
||||
for y in range(1, steps.y):
|
||||
for x in range(1, steps.x):
|
||||
var point = Vector2(x * grid, y * grid)
|
||||
|
||||
points.append(point)
|
||||
|
||||
var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new()
|
||||
cdt.init(true, true, 0.001)
|
||||
|
||||
cdt.insert_vertices(points)
|
||||
cdt.insert_edges(edges)
|
||||
|
||||
cdt.erase_outer_triangles()
|
||||
|
||||
points = cdt.get_all_vertices()
|
||||
var triangles: PackedInt32Array = cdt.get_all_triangles()
|
||||
|
||||
var points_3d = PackedVector3Array()
|
||||
|
||||
for k in range(points.size()):
|
||||
points_3d.append(Vector3(corner.x, 0, corner.y) + points[k].x * forward + Vector3(0, points[k].y, 0))
|
||||
|
||||
mesh = _create_mesh_3d(points_3d, triangles, mesh)
|
||||
|
||||
return mesh
|
||||
|
||||
static func generate_wall_mesh_grid(corners, height, grid: Vector2=Vector2(0.1, 0.1)):
|
||||
if corners.size() < 3:
|
||||
|
@ -186,9 +364,29 @@ static func generate_ceiling_mesh_grid(corners, grid: Vector2=Vector2(0.1, 0.1))
|
|||
points = cdt.get_all_vertices()
|
||||
triangles = cdt.get_all_triangles()
|
||||
|
||||
return _create_mesh(points, triangles)
|
||||
return _create_mesh_2d(points, triangles)
|
||||
|
||||
static func _create_mesh(points: PackedVector2Array, triangles: PackedInt32Array):
|
||||
static func _create_mesh_3d(points: PackedVector3Array, triangles: PackedInt32Array, existing=null):
|
||||
var st = SurfaceTool.new()
|
||||
|
||||
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
|
||||
for i in range(points.size()):
|
||||
st.add_vertex(Vector3(points[i].x, points[i].y, points[i].z))
|
||||
|
||||
for i in range(triangles.size()):
|
||||
st.add_index(triangles[i])
|
||||
|
||||
st.index()
|
||||
st.generate_normals()
|
||||
st.generate_tangents()
|
||||
|
||||
if existing != null:
|
||||
return st.commit(existing)
|
||||
|
||||
return st.commit()
|
||||
|
||||
static func _create_mesh_2d(points: PackedVector2Array, triangles: PackedInt32Array):
|
||||
var st = SurfaceTool.new()
|
||||
|
||||
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
|
|
|
@ -14,6 +14,8 @@ static func stringify_value(value):
|
|||
)
|
||||
TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_NIL:
|
||||
return value
|
||||
TYPE_STRING_NAME:
|
||||
return str(value)
|
||||
TYPE_VECTOR2:
|
||||
return {
|
||||
"x": value.x,
|
||||
|
|
Loading…
Reference in New Issue
Block a user