Implemented R-Tree
Would like to switch the identifer of the hole to a random string.
This commit is contained in:
BIN
.sconsign.dblite
BIN
.sconsign.dblite
Binary file not shown.
@@ -13,15 +13,32 @@ enum ExtrudeDirection {
|
|||||||
@export var extrusion_direction: ExtrudeDirection
|
@export var extrusion_direction: ExtrudeDirection
|
||||||
@export var depth: float = 0.1
|
@export var depth: float = 0.1
|
||||||
@export var depth_position_offset: Vector3 = Vector3.ZERO
|
@export var depth_position_offset: Vector3 = Vector3.ZERO
|
||||||
|
@export_category("User Defined Values")
|
||||||
@export var edge_non_fracture: float = 0.1
|
@export var edge_non_fracture: float = 0.1
|
||||||
@onready var parentNode = get_node("..")
|
|
||||||
|
var parentNode
|
||||||
|
var inner_rtree: RectangleTree
|
||||||
|
|
||||||
var outer_polygon: PackedVector2Array
|
var outer_polygon: PackedVector2Array
|
||||||
var inner_polygons: Array[PackedVector2Array]
|
var inner_polygons: Holes
|
||||||
|
|
||||||
var static_body: StaticBody3D
|
var static_body: StaticBody3D
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
parentNode = get_node("..")
|
||||||
|
inner_polygons = Holes.new()
|
||||||
|
inner_rtree = RectangleTree.new()
|
||||||
|
outer_polygon = verts2d
|
||||||
|
_draw()
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
inner_rtree.free()
|
||||||
|
|
||||||
func _func_godot_apply_properties(entity_properties: Dictionary) -> void:
|
func _func_godot_apply_properties(entity_properties: Dictionary) -> void:
|
||||||
meshInstance3d = _find_mesh_body()
|
meshInstance3d = _find_mesh_body()
|
||||||
var verticies = meshInstance3d.mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX]
|
var verticies = meshInstance3d.mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX]
|
||||||
@@ -75,20 +92,12 @@ func _func_godot_apply_properties(entity_properties: Dictionary) -> void:
|
|||||||
var outer_boudary = Geometry2D.convex_hull(verts_2d)
|
var outer_boudary = Geometry2D.convex_hull(verts_2d)
|
||||||
verts2d = outer_boudary
|
verts2d = outer_boudary
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
if Engine.is_editor_hint():
|
|
||||||
return
|
|
||||||
|
|
||||||
outer_polygon = verts2d
|
|
||||||
_draw()
|
|
||||||
|
|
||||||
func _draw():
|
func _draw():
|
||||||
var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons)
|
var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons.get_holes())
|
||||||
var vectors = []
|
var vectors = []
|
||||||
|
|
||||||
vectors.append_array(outer_polygon)
|
vectors.append_array(outer_polygon)
|
||||||
for ip in inner_polygons:
|
vectors.append_array(inner_polygons.get_hole_verticies())
|
||||||
vectors.append_array(ip)
|
|
||||||
|
|
||||||
var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth)
|
var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth)
|
||||||
var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0))
|
var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0))
|
||||||
@@ -101,24 +110,29 @@ func _draw():
|
|||||||
static_body = _find_static_body()
|
static_body = _find_static_body()
|
||||||
|
|
||||||
func _re_draw():
|
func _re_draw():
|
||||||
meshInstance3d.remove_child(static_body)
|
var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons.get_holes())
|
||||||
static_body.queue_free()
|
|
||||||
|
|
||||||
var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons)
|
|
||||||
var vectors = []
|
var vectors = []
|
||||||
|
|
||||||
vectors.append_array(outer_polygon)
|
vectors.append_array(outer_polygon)
|
||||||
for ip in inner_polygons:
|
vectors.append_array(inner_polygons.get_hole_verticies())
|
||||||
vectors.append_array(ip)
|
WorkerThreadPool.add_task(_generate_mesh.bind(vector_indexes, vectors))
|
||||||
|
|
||||||
|
func _deffered_draw(mesh: Mesh, task_id: int):
|
||||||
|
if task_id:
|
||||||
|
WorkerThreadPool.wait_for_task_completion(task_id)
|
||||||
|
|
||||||
|
meshInstance3d.remove_child(static_body)
|
||||||
|
static_body.queue_free()
|
||||||
|
meshInstance3d.mesh = mesh
|
||||||
|
meshInstance3d.create_trimesh_collision()
|
||||||
|
static_body = _find_static_body()
|
||||||
|
|
||||||
|
func _generate_mesh(vector_indexes: PackedInt32Array, vectors: PackedVector2Array):
|
||||||
var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth)
|
var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth)
|
||||||
var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0))
|
var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0))
|
||||||
meshGenerator.free()
|
meshGenerator.free()
|
||||||
|
|
||||||
meshInstance3d.mesh = commited_mesh
|
self.call_deferred("_deffered_draw", commited_mesh, WorkerThreadPool.get_caller_task_id())
|
||||||
meshInstance3d.create_trimesh_collision()
|
|
||||||
static_body = _find_static_body()
|
|
||||||
|
|
||||||
|
|
||||||
func hit(position: Vector3):
|
func hit(position: Vector3):
|
||||||
var cutter = Cutter.circleCutter()
|
var cutter = Cutter.circleCutter()
|
||||||
@@ -134,13 +148,18 @@ func hit(position: Vector3):
|
|||||||
|
|
||||||
# translate the cutter
|
# translate the cutter
|
||||||
var hole_vectors = Transform2D(0, hole_vector2_offset) * cutter
|
var hole_vectors = Transform2D(0, hole_vector2_offset) * cutter
|
||||||
var draw = _add_hole(hole_vectors)
|
|
||||||
|
var rtree_search = []
|
||||||
|
for hv in hole_vectors:
|
||||||
|
rtree_search.append_array(inner_rtree.query(hv))
|
||||||
|
|
||||||
|
var draw = _add_hole(hole_vectors, rtree_search)
|
||||||
|
|
||||||
if draw:
|
if draw:
|
||||||
_re_draw()
|
_re_draw()
|
||||||
|
|
||||||
func _add_hole(new_hole: PackedVector2Array) -> bool:
|
func _add_hole(new_hole: PackedVector2Array, holes_id: PackedInt32Array) -> bool:
|
||||||
var values_to_remove = []
|
var ids_to_remove = []
|
||||||
|
|
||||||
# validate that the hole is valid
|
# validate that the hole is valid
|
||||||
var boundary_polygon = Geometry2D.offset_polygon(outer_polygon, -edge_non_fracture)
|
var boundary_polygon = Geometry2D.offset_polygon(outer_polygon, -edge_non_fracture)
|
||||||
@@ -150,24 +169,28 @@ func _add_hole(new_hole: PackedVector2Array) -> bool:
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
var merged: PackedVector2Array = boundary_hole[0]
|
var merged: PackedVector2Array = boundary_hole[0]
|
||||||
for index in range(len(self.inner_polygons)):
|
|
||||||
var result = Geometry2D.merge_polygons(merged, self.inner_polygons[index])
|
for id in holes_id:
|
||||||
|
var result = Geometry2D.merge_polygons(merged, inner_polygons.get_hole(id).vectors)
|
||||||
|
|
||||||
if len(result) == 1:
|
if len(result) == 1:
|
||||||
merged = result[0]
|
merged = result[0]
|
||||||
values_to_remove.append(self.inner_polygons[index])
|
ids_to_remove.append(id)
|
||||||
elif len(result) > 1:
|
elif len(result) > 1:
|
||||||
# need to check that they have no overlapping area if they do clip
|
# need to check that they have no overlapping area if they do clip
|
||||||
var overlap = Geometry2D.intersect_polygons(result[0], result[1])
|
var overlap = Geometry2D.intersect_polygons(result[0], result[1])
|
||||||
|
|
||||||
if len(overlap) != 0:
|
if len(overlap) != 0:
|
||||||
merged = Geometry2D.clip_polygons(result[0], result[1])[0]
|
merged = Geometry2D.clip_polygons(result[0], result[1])[0]
|
||||||
values_to_remove.append(self.inner_polygons[index])
|
ids_to_remove.append(id)
|
||||||
|
|
||||||
for i in values_to_remove:
|
for id in ids_to_remove:
|
||||||
inner_polygons.erase(i)
|
inner_rtree.remove(id)
|
||||||
|
inner_polygons.remove_hole(id)
|
||||||
|
|
||||||
inner_polygons.append(merged)
|
var hole = inner_polygons.add_hole(merged)
|
||||||
|
var bound_rect = UTIL.get_bounding_rect(merged)
|
||||||
|
inner_rtree.add(bound_rect.position, bound_rect.end, hole.hole_id)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|||||||
34
demo/assets/scripts/environment/destructable/holes.gd
Normal file
34
demo/assets/scripts/environment/destructable/holes.gd
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
class_name Holes
|
||||||
|
|
||||||
|
var holes: Dictionary[int, Hole]
|
||||||
|
var counter: int = 0
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
self.holes = {}
|
||||||
|
|
||||||
|
func add_hole(vectors: PackedVector2Array) -> Hole:
|
||||||
|
var hole = Hole.new(counter, vectors)
|
||||||
|
self.holes[counter] = hole
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
return hole
|
||||||
|
|
||||||
|
func remove_hole(hole_id: int):
|
||||||
|
self.holes.erase(hole_id)
|
||||||
|
|
||||||
|
func get_hole(hole_id: int) -> Hole:
|
||||||
|
return self.holes[hole_id]
|
||||||
|
|
||||||
|
func get_hole_verticies() -> PackedVector2Array:
|
||||||
|
var return_val: PackedVector2Array = []
|
||||||
|
for hole in holes.values():
|
||||||
|
return_val.append_array(hole.vectors)
|
||||||
|
return return_val
|
||||||
|
|
||||||
|
func get_holes() -> Array[PackedVector2Array]:
|
||||||
|
var return_val: Array[PackedVector2Array] = []
|
||||||
|
for hole in holes.values():
|
||||||
|
return_val.append(hole.vectors)
|
||||||
|
return return_val
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dt73l1q8fgdyo
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
extends Resource
|
||||||
|
|
||||||
|
class_name Hole
|
||||||
|
|
||||||
|
var hole_id: int
|
||||||
|
var vectors: PackedVector2Array
|
||||||
|
|
||||||
|
func _init(hole_id: int, vectors: PackedVector2Array):
|
||||||
|
self.hole_id = hole_id
|
||||||
|
self.vectors = vectors
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cqtnb878sls4b
|
||||||
@@ -14,3 +14,14 @@ static func chunk_array(arr: Array, chunk_size: int) -> Array:
|
|||||||
|
|
||||||
static func vector2_to_vector3(v: Vector2) -> Vector3:
|
static func vector2_to_vector3(v: Vector2) -> Vector3:
|
||||||
return Vector3(v.x, v.y, 0)
|
return Vector3(v.x, v.y, 0)
|
||||||
|
|
||||||
|
static func get_bounding_rect(vectors: PackedVector2Array) -> Rect2:
|
||||||
|
if vectors.is_empty():
|
||||||
|
return Rect2()
|
||||||
|
|
||||||
|
var rect := Rect2(vectors[0], Vector2.ZERO) # Initialize with the first point
|
||||||
|
for point in vectors:
|
||||||
|
rect = rect.expand(point)
|
||||||
|
|
||||||
|
# The 'position' of the Rect2 will be the minimum corner
|
||||||
|
return rect
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user