128 lines
3.8 KiB
GDScript
128 lines
3.8 KiB
GDScript
extends RefCounted
|
|
|
|
## Prototype QA: two short bumps on StaticBody3D siblings of Floor (same NavigationRegion3D parent).
|
|
## Avoids one body with floor + cylinder (compound internal edges caused idle jitter beside bumps).
|
|
## Bump mesh group and collision fudge: random_floor_bump_collision_constants.gd.
|
|
## Spawner called from main.gd before nav bake.
|
|
## Collision radius > mesh radius; spawn before `NavigationRegion3D.bake_navigation_mesh()`.
|
|
|
|
const BUMP_COLLISION_CONSTS_SCRIPT: Script = preload(
|
|
"res://scripts/random_floor_bump_collision_constants.gd"
|
|
)
|
|
|
|
const COUNT: int = 2
|
|
const HEIGHT_MIN: float = 0.08
|
|
const HEIGHT_MAX: float = 0.14
|
|
const RADIUS_MIN: float = 0.36
|
|
const RADIUS_MAX: float = 0.62
|
|
const FLOOR_SINK: float = 0.008
|
|
const XZ_RANGE: float = 8.15
|
|
const MIN_PAIR_SEPARATION: float = 2.85
|
|
const MAX_PLACE_ATTEMPTS: int = 64
|
|
const EXCLUSION_MARGIN: float = 0.72
|
|
|
|
|
|
static func spawn_short_random_bumps(floor_node: StaticBody3D) -> void:
|
|
var rng := RandomNumberGenerator.new()
|
|
rng.randomize()
|
|
var mat := StandardMaterial3D.new()
|
|
mat.albedo_color = Color(0.22, 0.52, 0.32, 1.0)
|
|
mat.roughness = 1.0
|
|
mat.metallic = 0.0
|
|
mat.specular_mode = 2
|
|
|
|
var placed_xz: Array[Vector2] = []
|
|
for idx: int in COUNT:
|
|
var xz: Vector2 = Vector2.ZERO
|
|
var ok := false
|
|
for _a: int in MAX_PLACE_ATTEMPTS:
|
|
xz = Vector2(rng.randf_range(-XZ_RANGE, XZ_RANGE), rng.randf_range(-XZ_RANGE, XZ_RANGE))
|
|
if _xz_in_exclusion(xz):
|
|
continue
|
|
var far_enough := true
|
|
for p: Vector2 in placed_xz:
|
|
if xz.distance_to(p) < MIN_PAIR_SEPARATION:
|
|
far_enough = false
|
|
break
|
|
if not far_enough:
|
|
continue
|
|
ok = true
|
|
break
|
|
if not ok:
|
|
push_warning(
|
|
(
|
|
"RandomFloorBumps: could not place bump %d after %d tries"
|
|
% [idx, MAX_PLACE_ATTEMPTS]
|
|
)
|
|
)
|
|
continue
|
|
placed_xz.append(xz)
|
|
var h: float = rng.randf_range(HEIGHT_MIN, HEIGHT_MAX)
|
|
var r: float = rng.randf_range(RADIUS_MIN, RADIUS_MAX)
|
|
_add_cylinder_bump(floor_node, xz.x, xz.y, h, r, mat, idx)
|
|
|
|
|
|
static func _xz_in_exclusion(xz: Vector2) -> bool:
|
|
var ex: Array[Vector2] = [
|
|
Vector2(-5.0, -5.0),
|
|
Vector2(0.0, 0.0),
|
|
Vector2(6.0, 5.0),
|
|
Vector2(7.5, -6.5),
|
|
Vector2(9.0, 9.0),
|
|
]
|
|
var rad: Array[float] = [2.65, 1.2, 2.25, 1.65, 1.85]
|
|
for i: int in ex.size():
|
|
if xz.distance_to(ex[i]) < rad[i] + EXCLUSION_MARGIN:
|
|
return true
|
|
return false
|
|
|
|
|
|
static func _add_cylinder_bump(
|
|
floor_node: StaticBody3D,
|
|
x: float,
|
|
z: float,
|
|
height: float,
|
|
radius: float,
|
|
mat: StandardMaterial3D,
|
|
idx: int
|
|
) -> void:
|
|
var cy: float = height * 0.5 - FLOOR_SINK
|
|
var local_center := Vector3(x, cy, z)
|
|
var nav_parent := floor_node.get_parent()
|
|
if nav_parent == null:
|
|
push_error("RandomFloorBumps: Floor has no parent; cannot spawn bump")
|
|
return
|
|
|
|
var bump_root := StaticBody3D.new()
|
|
bump_root.name = "RandomTestBump%d" % idx
|
|
bump_root.add_to_group("walkable")
|
|
bump_root.collision_layer = floor_node.collision_layer
|
|
bump_root.collision_mask = floor_node.collision_mask
|
|
nav_parent.add_child(bump_root)
|
|
bump_root.global_position = floor_node.to_global(local_center)
|
|
|
|
var mesh_inst := MeshInstance3D.new()
|
|
mesh_inst.name = "RandomTestBump%d_mesh" % idx
|
|
mesh_inst.add_to_group(BUMP_COLLISION_CONSTS_SCRIPT.RANDOM_FLOOR_BUMP_MESH_GROUP)
|
|
var cm := CylinderMesh.new()
|
|
cm.height = height
|
|
cm.top_radius = radius
|
|
cm.bottom_radius = radius
|
|
cm.radial_segments = 24
|
|
mesh_inst.mesh = cm
|
|
mesh_inst.set_surface_override_material(0, mat)
|
|
mesh_inst.position = Vector3.ZERO
|
|
bump_root.add_child(mesh_inst)
|
|
|
|
var col := CollisionShape3D.new()
|
|
col.name = "RandomTestBump%d_shape" % idx
|
|
var csh := CylinderShape3D.new()
|
|
csh.height = height
|
|
csh.radius = minf(
|
|
radius + BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_EXTRA,
|
|
BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_MAX
|
|
)
|
|
col.shape = csh
|
|
col.position = Vector3.ZERO
|
|
bump_root.add_child(col)
|