133 lines
5.1 KiB
GDScript
133 lines
5.1 KiB
GDScript
extends Node
|
|
|
|
const ROOM_HEIGHT: float = 4.0
|
|
const WALL_THICKNESS: float = 0.4
|
|
const CORRIDOR_WIDTH: float = 4.0
|
|
const DOOR_WIDTH: float = 4.5
|
|
|
|
var rng: RandomNumberGenerator
|
|
var rooms: Array = []
|
|
|
|
func generate(parent: Node3D, seed: int, scale_difficulty: float = 1.0) -> Dictionary:
|
|
rng = RandomNumberGenerator.new()
|
|
rng.seed = seed
|
|
rooms.clear()
|
|
var room_count: int = rng.randi_range(5, 8)
|
|
var pos := Vector3(0, 0, 0)
|
|
var dir := Vector3(0, 0, -1)
|
|
for i in range(room_count):
|
|
var w: float = rng.randf_range(8.0, 14.0)
|
|
var d: float = rng.randf_range(8.0, 14.0)
|
|
rooms.append({"pos": pos, "size": Vector3(w, ROOM_HEIGHT, d), "openings": []})
|
|
if i == room_count - 1:
|
|
break
|
|
var corridor_len: float = rng.randf_range(4.0, 8.0)
|
|
var step: Vector3 = dir * (max(w, d) * 0.5 + corridor_len + 4.0)
|
|
pos += step
|
|
if rng.randf() < 0.5:
|
|
var rotate_left: bool = rng.randf() < 0.5
|
|
dir = dir.rotated(Vector3.UP, PI * 0.5 * (1 if rotate_left else -1))
|
|
_compute_openings()
|
|
_build_geometry(parent)
|
|
return {"rooms": rooms, "spawn": rooms[0].pos + Vector3(0, 1, 0), "boss": rooms[-1].pos}
|
|
|
|
func _compute_openings() -> void:
|
|
for i in range(rooms.size() - 1):
|
|
var rel: Vector3 = rooms[i + 1].pos - rooms[i].pos
|
|
if abs(rel.x) > abs(rel.z):
|
|
if rel.x > 0:
|
|
rooms[i].openings.append("east")
|
|
rooms[i + 1].openings.append("west")
|
|
else:
|
|
rooms[i].openings.append("west")
|
|
rooms[i + 1].openings.append("east")
|
|
else:
|
|
if rel.z > 0:
|
|
rooms[i].openings.append("south")
|
|
rooms[i + 1].openings.append("north")
|
|
else:
|
|
rooms[i].openings.append("north")
|
|
rooms[i + 1].openings.append("south")
|
|
|
|
func _build_geometry(parent: Node3D) -> void:
|
|
for r in rooms:
|
|
_build_room(parent, r.pos, r.size, r.openings)
|
|
for i in range(rooms.size() - 1):
|
|
_build_corridor(parent, rooms[i].pos, rooms[i + 1].pos)
|
|
|
|
func _build_room(parent: Node3D, center: Vector3, size: Vector3, openings: Array) -> void:
|
|
_add_floor(parent, center, Vector2(size.x, size.z))
|
|
var hw: float = size.x * 0.5
|
|
var hd: float = size.z * 0.5
|
|
_add_wall_with_opening(parent, center + Vector3(0, ROOM_HEIGHT * 0.5, -hd), Vector3(size.x, ROOM_HEIGHT, WALL_THICKNESS), "north", openings, true)
|
|
_add_wall_with_opening(parent, center + Vector3(0, ROOM_HEIGHT * 0.5, hd), Vector3(size.x, ROOM_HEIGHT, WALL_THICKNESS), "south", openings, true)
|
|
_add_wall_with_opening(parent, center + Vector3(-hw, ROOM_HEIGHT * 0.5, 0), Vector3(WALL_THICKNESS, ROOM_HEIGHT, size.z), "west", openings, false)
|
|
_add_wall_with_opening(parent, center + Vector3(hw, ROOM_HEIGHT * 0.5, 0), Vector3(WALL_THICKNESS, ROOM_HEIGHT, size.z), "east", openings, false)
|
|
|
|
func _add_wall_with_opening(parent: Node3D, center: Vector3, size: Vector3, side: String, openings: Array, axis_x: bool) -> void:
|
|
if not openings.has(side):
|
|
_add_wall(parent, center, size)
|
|
return
|
|
if axis_x:
|
|
var seg_len: float = (size.x - DOOR_WIDTH) * 0.5
|
|
if seg_len <= 0.1:
|
|
return
|
|
var seg_offset: float = DOOR_WIDTH * 0.5 + seg_len * 0.5
|
|
_add_wall(parent, center + Vector3(-seg_offset, 0, 0), Vector3(seg_len, size.y, size.z))
|
|
_add_wall(parent, center + Vector3(seg_offset, 0, 0), Vector3(seg_len, size.y, size.z))
|
|
else:
|
|
var seg_len: float = (size.z - DOOR_WIDTH) * 0.5
|
|
if seg_len <= 0.1:
|
|
return
|
|
var seg_offset: float = DOOR_WIDTH * 0.5 + seg_len * 0.5
|
|
_add_wall(parent, center + Vector3(0, 0, -seg_offset), Vector3(size.x, size.y, seg_len))
|
|
_add_wall(parent, center + Vector3(0, 0, seg_offset), Vector3(size.x, size.y, seg_len))
|
|
|
|
func _build_corridor(parent: Node3D, from: Vector3, to: Vector3) -> void:
|
|
var mid: Vector3 = (from + to) * 0.5
|
|
var d: float = from.distance_to(to)
|
|
var dir: Vector3 = (to - from).normalized()
|
|
_add_floor(parent, Vector3(mid.x, 0, mid.z), Vector2(d, CORRIDOR_WIDTH) if abs(dir.x) > abs(dir.z) else Vector2(CORRIDOR_WIDTH, d))
|
|
|
|
func _add_floor(parent: Node3D, center: Vector3, size: Vector2) -> void:
|
|
var body := StaticBody3D.new()
|
|
body.collision_layer = 1
|
|
body.collision_mask = 0
|
|
var mesh := MeshInstance3D.new()
|
|
var box := BoxMesh.new()
|
|
box.size = Vector3(size.x, 0.4, size.y)
|
|
mesh.mesh = box
|
|
var mat := StandardMaterial3D.new()
|
|
mat.albedo_color = Color(0.25, 0.22, 0.2)
|
|
mesh.material_override = mat
|
|
mesh.position = Vector3(0, -0.2, 0)
|
|
var col := CollisionShape3D.new()
|
|
var shape := BoxShape3D.new()
|
|
shape.size = Vector3(size.x, 0.4, size.y)
|
|
col.shape = shape
|
|
col.position = Vector3(0, -0.2, 0)
|
|
body.add_child(mesh)
|
|
body.add_child(col)
|
|
body.position = center
|
|
parent.add_child(body)
|
|
|
|
func _add_wall(parent: Node3D, center: Vector3, size: Vector3) -> void:
|
|
var body := StaticBody3D.new()
|
|
body.collision_layer = 1
|
|
body.collision_mask = 0
|
|
var mesh := MeshInstance3D.new()
|
|
var box := BoxMesh.new()
|
|
box.size = size
|
|
mesh.mesh = box
|
|
var mat := StandardMaterial3D.new()
|
|
mat.albedo_color = Color(0.35, 0.32, 0.28)
|
|
mesh.material_override = mat
|
|
var col := CollisionShape3D.new()
|
|
var shape := BoxShape3D.new()
|
|
shape.size = size
|
|
col.shape = shape
|
|
body.add_child(mesh)
|
|
body.add_child(col)
|
|
body.position = center
|
|
parent.add_child(body)
|