Level Setup
Integrated with Trenchbroom
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
@tool
|
||||
class_name DestructableWall extends Node3D
|
||||
|
||||
enum ExtrudeDirection {
|
||||
BACK = 0, # z
|
||||
RIGHT = 1, # x
|
||||
UP = 2 # y
|
||||
}
|
||||
|
||||
@export_category("TrechBroom Generated Values")
|
||||
@export var verts2d: PackedVector2Array
|
||||
@export var meshInstance3d: MeshInstance3D
|
||||
@export var extrusion_direction: ExtrudeDirection
|
||||
@export var depth: float = 0.1
|
||||
@export var depth_position_offset: Vector3 = Vector3.ZERO
|
||||
|
||||
@export var edge_non_fracture: float = 0.1
|
||||
@onready var parentNode = get_node("..")
|
||||
|
||||
var outer_polygon: PackedVector2Array
|
||||
var inner_polygons: Array[PackedVector2Array]
|
||||
|
||||
var static_body: StaticBody3D
|
||||
|
||||
func _func_godot_apply_properties(entity_properties: Dictionary) -> void:
|
||||
meshInstance3d = _find_mesh_body()
|
||||
var verticies = meshInstance3d.mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX]
|
||||
|
||||
extrusion_direction = entity_properties["extrude_direction"]
|
||||
|
||||
var depth_min: float
|
||||
var depth_max: float
|
||||
|
||||
var verts_2d: PackedVector2Array = []
|
||||
if extrusion_direction == ExtrudeDirection.BACK:
|
||||
for vert in verticies:
|
||||
verts_2d.append(Vector2(vert.x, vert.y))
|
||||
|
||||
var d = vert.z
|
||||
|
||||
if d > depth_max:
|
||||
depth_max = d
|
||||
elif d < depth_min:
|
||||
depth_min = d
|
||||
depth = -(abs(depth_min) + abs(depth_max))
|
||||
|
||||
depth_position_offset = -(Vector3.BACK * (depth/2))
|
||||
elif extrusion_direction == ExtrudeDirection.RIGHT:
|
||||
for vert in verticies:
|
||||
verts_2d.append(Vector2(vert.z, vert.y))
|
||||
|
||||
var d = vert.x
|
||||
|
||||
if d > depth_max:
|
||||
depth_max = d
|
||||
elif d < depth_min:
|
||||
depth_min = d
|
||||
depth = -(abs(depth_min) + abs(depth_max))
|
||||
|
||||
depth_position_offset = Vector3.RIGHT * (depth/2)
|
||||
elif extrusion_direction == ExtrudeDirection.UP:
|
||||
for vert in verticies:
|
||||
verts_2d.append(Vector2(vert.x, vert.z))
|
||||
|
||||
var d = vert.y
|
||||
|
||||
if d > depth_max:
|
||||
depth_max = d
|
||||
elif d < depth_min:
|
||||
depth_min = d
|
||||
depth = -(abs(depth_min) + abs(depth_max))
|
||||
|
||||
depth_position_offset = (Vector3.UP * (depth/2))
|
||||
|
||||
|
||||
var outer_boudary = Geometry2D.convex_hull(verts_2d)
|
||||
verts2d = outer_boudary
|
||||
|
||||
func _ready() -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
outer_polygon = verts2d
|
||||
_draw()
|
||||
|
||||
func _draw():
|
||||
var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons)
|
||||
var vectors = []
|
||||
|
||||
vectors.append_array(outer_polygon)
|
||||
for ip in inner_polygons:
|
||||
vectors.append_array(ip)
|
||||
|
||||
var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth)
|
||||
var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0))
|
||||
|
||||
meshInstance3d.mesh = commited_mesh
|
||||
meshInstance3d.position += depth_position_offset
|
||||
meshInstance3d.create_trimesh_collision()
|
||||
static_body = _find_static_body()
|
||||
|
||||
func _re_draw():
|
||||
meshInstance3d.remove_child(static_body)
|
||||
static_body.queue_free()
|
||||
|
||||
var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons)
|
||||
var vectors = []
|
||||
|
||||
vectors.append_array(outer_polygon)
|
||||
for ip in inner_polygons:
|
||||
vectors.append_array(ip)
|
||||
|
||||
var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth)
|
||||
var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0))
|
||||
|
||||
meshInstance3d.mesh = commited_mesh
|
||||
meshInstance3d.create_trimesh_collision()
|
||||
static_body = _find_static_body()
|
||||
|
||||
|
||||
func hit(position: Vector3):
|
||||
var cutter = Cutter.circleCutter()
|
||||
var hole_position_offset = meshInstance3d.to_local(position)
|
||||
|
||||
var hole_vector2_offset: Vector2
|
||||
if extrusion_direction == ExtrudeDirection.BACK:
|
||||
hole_vector2_offset = Vector2(hole_position_offset.x, hole_position_offset.y)
|
||||
elif extrusion_direction == ExtrudeDirection.RIGHT:
|
||||
hole_vector2_offset = Vector2(hole_position_offset.z, hole_position_offset.y)
|
||||
elif extrusion_direction == ExtrudeDirection.UP:
|
||||
hole_vector2_offset = Vector2(hole_position_offset.x, hole_position_offset.z)
|
||||
|
||||
# translate the cutter
|
||||
var hole_vectors = Transform2D(0, hole_vector2_offset) * cutter
|
||||
var draw = _add_hole(hole_vectors)
|
||||
|
||||
if draw:
|
||||
_re_draw()
|
||||
|
||||
func _add_hole(new_hole: PackedVector2Array) -> bool:
|
||||
var values_to_remove = []
|
||||
|
||||
# validate that the hole is valid
|
||||
var boundary_polygon = Geometry2D.offset_polygon(outer_polygon, -edge_non_fracture)
|
||||
|
||||
var boundary_hole = Geometry2D.intersect_polygons(new_hole, boundary_polygon[0])
|
||||
if !boundary_hole:
|
||||
return false
|
||||
|
||||
var merged: PackedVector2Array = boundary_hole[0]
|
||||
for index in range(len(self.inner_polygons)):
|
||||
var result = Geometry2D.merge_polygons(merged, self.inner_polygons[index])
|
||||
|
||||
if len(result) == 1:
|
||||
merged = result[0]
|
||||
values_to_remove.append(self.inner_polygons[index])
|
||||
elif len(result) > 1:
|
||||
# need to check that they have no overlapping area if they do clip
|
||||
var overlap = Geometry2D.intersect_polygons(result[0], result[1])
|
||||
|
||||
if len(overlap) != 0:
|
||||
merged = Geometry2D.clip_polygons(result[0], result[1])[0]
|
||||
values_to_remove.append(self.inner_polygons[index])
|
||||
|
||||
for i in values_to_remove:
|
||||
inner_polygons.erase(i)
|
||||
|
||||
inner_polygons.append(merged)
|
||||
|
||||
return true
|
||||
|
||||
func _find_static_body():
|
||||
for child in meshInstance3d.get_children():
|
||||
if child is StaticBody3D:
|
||||
return child
|
||||
|
||||
func _find_mesh_body():
|
||||
for child in self.get_children():
|
||||
if child is MeshInstance3D:
|
||||
return child
|
||||
Reference in New Issue
Block a user