fix(tools): canyons impose a floor material through rock outcrops; tighten showcase contracts
Review findings: the mesa forced rock onto the canyon bed, two runners declared the wrong TEST_COUNT, and the escarpment check could pass on the slope alone. Canyon gains floor_material, the showcase is re-baked with sand beds, the contract measures the step across the crest band, counts distinct ledges, and probes the crevasse against the open plateau. Degenerate recipe parameters now fail an assert. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
abffa737ec
commit
d91e6bd02f
8 files changed
+73
-36
No files matched your search
@@ -170,13 +170,15 @@ class Groove extends Primitive:
|
||||
## Flat-floored trench along a polyline. The floor sits depth_m below the surroundings
|
||||
## wherever the (noise-perturbed) distance to the path is under half_width_m minus
|
||||
## wall_softness_m; the walls climb over 2 * wall_softness_m; the trench closes over one
|
||||
## half-width at each end.
|
||||
## half-width at each end. floor_material (a SonarMaterial value, or NO_MATERIAL) is
|
||||
## imposed on the flat floor, so a canyon cut through a rock outcrop keeps a sand bed.
|
||||
class Canyon extends Primitive:
|
||||
var path: PackedVector2Array
|
||||
var half_width_m: float
|
||||
var depth_m: float
|
||||
var wall_softness_m: float
|
||||
var edge_amplitude_m: float
|
||||
var floor_material: int
|
||||
var _noise: FastNoiseLite
|
||||
var _length_m: float
|
||||
|
||||
@@ -186,17 +188,31 @@ class Canyon extends Primitive:
|
||||
p_depth_m: float,
|
||||
p_wall_softness_m: float,
|
||||
p_edge_seed: int,
|
||||
p_edge_amplitude_m: float
|
||||
p_edge_amplitude_m: float,
|
||||
p_floor_material: int
|
||||
) -> void:
|
||||
assert(p_path.size() >= 2, "a canyon path needs at least two vertices")
|
||||
assert(p_half_width_m > 0.0, "a canyon needs a positive half width")
|
||||
path = p_path
|
||||
half_width_m = p_half_width_m
|
||||
depth_m = p_depth_m
|
||||
wall_softness_m = p_wall_softness_m
|
||||
edge_amplitude_m = p_edge_amplitude_m
|
||||
floor_material = p_floor_material
|
||||
_noise = edge_noise(p_edge_seed, p_edge_amplitude_m)
|
||||
_length_m = path_length(p_path)
|
||||
|
||||
func elevation_delta(x_m: float, z_m: float) -> float:
|
||||
return -depth_m * _presence(x_m, z_m)
|
||||
|
||||
func material_at(x_m: float, z_m: float) -> int:
|
||||
# Full presence means the flat floor: inside the walls and clear of the end tapers.
|
||||
if floor_material != NO_MATERIAL and _presence(x_m, z_m) >= 0.999:
|
||||
return floor_material
|
||||
return NO_MATERIAL
|
||||
|
||||
## 1 on the flat floor, 0 outside the trench, in between on the walls and end tapers.
|
||||
func _presence(x_m: float, z_m: float) -> float:
|
||||
var sample := path_sample(Vector2(x_m, z_m), path)
|
||||
var distance := sample.x + edge_offset(_noise, edge_amplitude_m, x_m, z_m)
|
||||
var inside := 1.0 - smoothstep(
|
||||
@@ -205,13 +221,14 @@ class Canyon extends Primitive:
|
||||
distance
|
||||
)
|
||||
var taper := smoothstep(0.0, half_width_m, sample.y) * smoothstep(0.0, half_width_m, _length_m - sample.y)
|
||||
return -depth_m * inside * taper
|
||||
return inside * taper
|
||||
|
||||
|
||||
## Step along a polyline: the terrain drops by drop_m on the right of the travel direction
|
||||
## (south of an eastbound path), over 2 * softness_m, then keeps falling at slope_beyond.
|
||||
## The crest line is roughened by outline noise. Extend the path past the field edges:
|
||||
## beyond its ends the contour wraps around the end vertex.
|
||||
## The crest line is roughened by outline noise. The path must extend past the field
|
||||
## edges: beyond an end vertex the drop is decided by the half-plane of the last segment,
|
||||
## which leaves a seam along the path's extension.
|
||||
class Escarpment extends Primitive:
|
||||
var path: PackedVector2Array
|
||||
var drop_m: float
|
||||
@@ -228,6 +245,7 @@ class Escarpment extends Primitive:
|
||||
p_edge_seed: int,
|
||||
p_edge_amplitude_m: float
|
||||
) -> void:
|
||||
assert(p_path.size() >= 2, "an escarpment path needs at least two vertices")
|
||||
path = p_path
|
||||
drop_m = p_drop_m
|
||||
softness_m = p_softness_m
|
||||
@@ -267,6 +285,7 @@ class Outcrop extends Primitive:
|
||||
p_edge_amplitude_m: float,
|
||||
p_rock_top: bool
|
||||
) -> void:
|
||||
assert(p_radius_x_m > 0.0 and p_radius_z_m > 0.0, "an outcrop needs positive radii")
|
||||
centre = p_centre
|
||||
radius_x_m = p_radius_x_m
|
||||
radius_z_m = p_radius_z_m
|
||||
@@ -435,6 +454,7 @@ class Strata extends Modifier:
|
||||
p_centre: Vector2,
|
||||
p_radius_m: float
|
||||
) -> void:
|
||||
assert(p_layer_height_m > 0.0, "strata need a positive layer height")
|
||||
layer_height_m = p_layer_height_m
|
||||
sharpness = clampf(p_sharpness, 0.0, 0.999)
|
||||
centre = p_centre
|
||||
|
||||
@@ -5,6 +5,7 @@ extends RefCounted
|
||||
## mooring beacon at the centre. Field 512 x 512 m at 1 m, +X east, +Z south.
|
||||
|
||||
const SiteTerrainBaker = preload("res://tools/site_terrain_baker.gd")
|
||||
const SonarMaterial = preload("res://game/domain/sonar/sonar_material.gd")
|
||||
const SiteTerrainData = preload("res://game/domain/sites/site_terrain_data.gd")
|
||||
const DiveSiteDefinition = preload("res://game/domain/sites/dive_site_definition.gd")
|
||||
const SitePlacement = preload("res://game/domain/sites/site_placement.gd")
|
||||
@@ -59,15 +60,15 @@ static func recipe() -> SiteTerrainBaker.Recipe:
|
||||
# modifier (one ledge every 2.8 m across, resolvable at 1 m per cell), rippled
|
||||
# sand on the floor.
|
||||
SiteTerrainBaker.Outcrop.new(MESA_CENTRE, 95.0, 85.0, 6.0, 10.0, 101, 6.0, true),
|
||||
SiteTerrainBaker.Canyon.new(PackedVector2Array(CANYON_PATH), CANYON_HALF_WIDTH_M, CANYON_DEPTH_M, 7.0, 102, 2.0),
|
||||
SiteTerrainBaker.Canyon.new(PackedVector2Array(CANYON_PATH), CANYON_HALF_WIDTH_M, CANYON_DEPTH_M, 7.0, 102, 2.0, SonarMaterial.Value.SAND),
|
||||
SiteTerrainBaker.Ripples.new(Vector2(0.8, -0.6), 4.0, 0.25, Vector2(-130.0, -140.0), 70.0),
|
||||
|
||||
# NE — la Fente: two buttes 8-9 m high with a 6 m wide, 20 m deep slot between them.
|
||||
SiteTerrainBaker.Outcrop.new(WEST_BUTTE_CENTRE, 38.0, 70.0, 8.0, 8.0, 201, 5.0, true),
|
||||
SiteTerrainBaker.Outcrop.new(EAST_BUTTE_CENTRE, 38.0, 75.0, 9.0, 8.0, 202, 5.0, true),
|
||||
SiteTerrainBaker.Canyon.new(PackedVector2Array(CREVASSE_PATH), CREVASSE_HALF_WIDTH_M, CREVASSE_DEPTH_M, 1.0, 203, 1.0),
|
||||
SiteTerrainBaker.Canyon.new(PackedVector2Array(CREVASSE_PATH), CREVASSE_HALF_WIDTH_M, CREVASSE_DEPTH_M, 1.0, 203, 1.0, SonarMaterial.Value.SAND),
|
||||
|
||||
# SW — le Chaos: ninety boulders 2-6 m across plus six coral heads, on rippled sand.
|
||||
# SW — le Chaos: ninety boulders of 2-6 m radius plus six coral heads, on rippled sand.
|
||||
SiteTerrainBaker.BoulderField.new(BOULDER_FIELD_CENTRE, BOULDER_FIELD_RADIUS_M, 301, 90, 2.0, 6.0, 0.7),
|
||||
SiteTerrainBaker.BoulderField.new(Vector2(-100.0, 130.0), 40.0, 302, 6, 6.0, 9.0, 0.6),
|
||||
SiteTerrainBaker.Ripples.new(Vector2(1.0, 0.3), 3.5, 0.3, BOULDER_FIELD_CENTRE, 110.0),
|
||||
|
||||
Reference in new issue
Block a user