start working on implementing doors

This commit is contained in:
Nitwel 2024-04-28 20:13:09 +02:00
parent 0cddcc5ea1
commit 04ad9bb647
13 changed files with 441 additions and 144 deletions

View File

@ -0,0 +1,129 @@
extends Node3D
const WallCornerScene = preload ("../room/wall_corner.tscn")
const WallEdgeScene = preload ("../room/wall_edge.tscn")
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 edit(door):
editing_door = door
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():
pass
func save():
pass
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()

View File

@ -0,0 +1,33 @@
[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
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="."]
[node name="CSGPolygon3D2" type="CSGPolygon3D" parent="CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 2.98023e-08, -1, 0, 1, 2.98023e-08, -3.32523, 0, -0.681036)
snap = 1e-06
flip_faces = true
polygon = PackedVector2Array(1.44028, 2.37318, 1.98957, 0.544275, 0.705633, -0.829152, -0.559752, 0.530294, -0.933822, 2.4059)
depth = 2.5
[node name="CSGPolygon3D" type="CSGPolygon3D" parent="CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 2.98023e-08, -1, 0, 1, 2.98023e-08, 0, 0, 0)
snap = 1e-06
flip_faces = true
polygon = PackedVector2Array(1.44028, 2.37318, 1.98957, 0.544275, 0.705633, -0.829152, -0.559752, 0.530294, -0.933822, 2.4059)
depth = 2.5
[node name="CSGBox3D" type="CSGBox3D" parent="CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.767542, 0.804975, 0.629865)
flip_faces = true
size = Vector3(2.00439, 1, 1)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1,25 @@
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 door_label = $Label3D
@onready var rooms_map = $Rooms
@onready var doors_map = $Doors
var selected_door = R.state(null)
var editing_door = R.state(false)
func _ready():
# Generate Room Mesh
R.effect(func(_arg):
pass
)
door_button.on_button_up.connect(func():
House.body.doors.edit(1)
)

View File

@ -0,0 +1,59 @@
[gd_scene load_steps=8 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="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)
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)
[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="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

View File

@ -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)

View File

@ -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)
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)
@ -40,7 +49,6 @@ disabled = 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)
visible = false
material_override = SubResource("ShaderMaterial_dah0r")
mesh = SubResource("QuadMesh_fq44b")
skeleton = NodePath("../..")

View File

@ -0,0 +1,84 @@
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.y=- box_transform.origin.y
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("%s"% room_name):
return get_node("%s"% room_name)
return null

View File

@ -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()
})

View 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)