diff --git a/game/composition/vertical_slice/vertical_slice_root.gd b/game/composition/vertical_slice/vertical_slice_root.gd index e53bbb3..eea2df7 100644 --- a/game/composition/vertical_slice/vertical_slice_root.gd +++ b/game/composition/vertical_slice/vertical_slice_root.gd @@ -130,10 +130,6 @@ func _start_dive() -> void: if definition == null: push_error("dive site definition %s cannot be loaded" % _selected_site_path) return - var definition_error := definition.validation_error() - if not definition_error.is_empty(): - push_error("dive site %s is invalid: %s" % [_selected_site_path, definition_error]) - return var world_scene := load(DIVE_WORLD_SCENE_PATH) as PackedScene if world_scene == null: return diff --git a/game/domain/sites/terrain_height_field.gd b/game/domain/sites/terrain_height_field.gd index 7866b17..610e34a 100644 --- a/game/domain/sites/terrain_height_field.gd +++ b/game/domain/sites/terrain_height_field.gd @@ -59,6 +59,11 @@ func maximum_elevation_m() -> float: return _maximum_elevation_m +## Row-major elevations (index = row * columns + column), the HeightMapShape3D layout. +func elevations_m() -> PackedFloat32Array: + return _data.elevations_m + + func elevation_at_cell(column: int, row: int) -> float: return _data.elevations_m[_data.index_of(_clamp_column(column), _clamp_row(row))] diff --git a/game/world/sites/bathymetric_terrain_actor.gd b/game/world/sites/bathymetric_terrain_actor.gd index a7fca5d..874aee4 100644 --- a/game/world/sites/bathymetric_terrain_actor.gd +++ b/game/world/sites/bathymetric_terrain_actor.gd @@ -116,12 +116,7 @@ func _build_collision() -> void: var shape := HeightMapShape3D.new() shape.map_width = _field.columns() shape.map_depth = _field.rows() - var heights := PackedFloat32Array() - heights.resize(_field.columns() * _field.rows()) - for row in _field.rows(): - for column in _field.columns(): - heights[row * _field.columns() + column] = _field.elevation_at_cell(column, row) - shape.map_data = heights + shape.map_data = _field.elevations_m() _collision = CollisionShape3D.new() _collision.name = "Collision" _collision.shape = shape diff --git a/game/world/sites/dive_site.gd b/game/world/sites/dive_site.gd index 841d86d..d73d778 100644 --- a/game/world/sites/dive_site.gd +++ b/game/world/sites/dive_site.gd @@ -21,10 +21,10 @@ var _placeholder_count := 0 func configure(definition: DiveSiteDefinition) -> String: if definition == null: return "dive site definition is missing" - var error := definition.validation_error() - if not error.is_empty(): - return error - var terrain_error := _terrain.configure(definition.height_field()) + var field := definition.height_field() + if field == null: + return "dive site definition is invalid" + var terrain_error := _terrain.configure(field) if not terrain_error.is_empty(): return terrain_error _definition = definition diff --git a/tests/unit/run_site_domain_tests.gd b/tests/unit/run_site_domain_tests.gd index 6715204..de0fdbe 100644 --- a/tests/unit/run_site_domain_tests.gd +++ b/tests/unit/run_site_domain_tests.gd @@ -7,7 +7,7 @@ const SitePlacement = preload("res://game/domain/sites/site_placement.gd") const SiteRoute = preload("res://game/domain/sites/site_route.gd") const DiveSiteDefinition = preload("res://game/domain/sites/dive_site_definition.gd") -const TEST_COUNT := 38 +const TEST_COUNT := 39 var _failures: Array[String] = [] @@ -83,10 +83,12 @@ func _test_terrain_data_validation() -> void: func _test_height_field_sampling() -> void: - var field := TerrainHeightField.from_data(_make_terrain(3, 4)) + var data := _make_terrain(3, 4) + var field := TerrainHeightField.from_data(data) _expect(field != null, "valid data yields a field") if field == null: return + _expect(field.elevations_m() == data.elevations_m, "elevations are exposed in row-major data order") _expect(field.bounds_m().is_equal_approx(Rect2(-10.0, 100.0, 4.0, 6.0)), "bounds cover (columns-1) by (rows-1) cells") _expect(field.cell_world_position(2, 3).is_equal_approx(Vector3(-6.0, -26.0, 106.0)), "cell position follows origin and cell size") _expect(is_equal_approx(field.elevation_at(-10.0, 100.0), -20.0), "elevation at a vertex is exact")