137 lines
4.0 KiB
GDScript
137 lines
4.0 KiB
GDScript
extends SceneTree
|
|
|
|
const SonarModelScript = preload("res://src/sonar_model.gd")
|
|
|
|
var _last_cells: Array[Dictionary] = []
|
|
var _last_previous_cells: Array[Dictionary] = []
|
|
var _progress_cells: Array[Dictionary] = []
|
|
var _failures: Array[String] = []
|
|
var _completion_count := 0
|
|
|
|
|
|
func _init() -> void:
|
|
_run.call_deferred()
|
|
|
|
|
|
func _run() -> void:
|
|
change_scene_to_file("res://scenes/poc_b.tscn")
|
|
await process_frame
|
|
await physics_frame
|
|
var submarine := current_scene.get_node("Submarine") as CharacterBody3D
|
|
var sonar := current_scene.get_node("SonarSystem")
|
|
var hud := current_scene.get_node("SonarHud")
|
|
sonar.ping_progress.connect(_on_ping_progress)
|
|
sonar.ping_completed.connect(_on_ping_completed)
|
|
|
|
_expect(absf(float(sonar.ping_duration()) - 2.5) < 0.001, "scan lasts 2.5 seconds")
|
|
_expect(float(sonar.max_range) >= 95.0, "bathymetric range reaches 95 metres")
|
|
_expect(float(sonar.horizontal_fov_degrees) >= 76.0, "scan covers a wider frontal area")
|
|
sonar.request_ping()
|
|
for frame in 3:
|
|
await physics_frame
|
|
_expect(_completion_count == 0, "scan does not return immediately")
|
|
for frame in 157:
|
|
await physics_frame
|
|
|
|
_expect(not _last_cells.is_empty(), "calibration scan returns structured relief cells")
|
|
_expect(
|
|
_bathymetry_cell_count(_last_cells) > 500,
|
|
"scan reconstructs a dense bathymetric surface"
|
|
)
|
|
_expect(
|
|
_last_cells[0].has("row") and _last_cells[0].has("column"),
|
|
"each return keeps its grid coordinates"
|
|
)
|
|
_expect(
|
|
_last_cells[0].has("elevation"),
|
|
"bathymetric samples encode normalized elevation"
|
|
)
|
|
_expect(_metal_cell_count(_last_cells) > 0, "calibration scan detects the metal object")
|
|
_expect(
|
|
int(hud.relief_renderer().current_face_count()) > 0,
|
|
"relief cells produce connected facets"
|
|
)
|
|
hud.set_expanded(true)
|
|
_expect(hud.is_expanded(), "sonar can expand without pausing the submarine")
|
|
hud.set_expanded(false)
|
|
|
|
var first_scan_size := _last_cells.size()
|
|
for frame in 16:
|
|
await physics_frame
|
|
submarine.controls_enabled = false
|
|
submarine.rotation.y = 0.35
|
|
sonar.request_ping()
|
|
for frame in 3:
|
|
await physics_frame
|
|
_expect(
|
|
_last_previous_cells.size() == first_scan_size,
|
|
"new scan keeps exactly one previous relief during replacement"
|
|
)
|
|
_expect(
|
|
_progress_cells.size() < first_scan_size,
|
|
"replacement starts near the submarine instead of appearing at once"
|
|
)
|
|
for frame in 157:
|
|
await physics_frame
|
|
_expect(_completion_count == 2, "second scan completes after progressive replacement")
|
|
|
|
var exit_code := 0
|
|
if _failures.is_empty():
|
|
print("POC B integration: 14 passed, 0 failed.")
|
|
else:
|
|
for failure in _failures:
|
|
push_error(failure)
|
|
print("POC B integration: %d failed." % _failures.size())
|
|
exit_code = 1
|
|
|
|
# AudioStreamGeneratorPlayback is reference-counted by the active player.
|
|
# Stop it and release the scene before quitting so the integration suite also
|
|
# verifies a clean ObjectDB shutdown.
|
|
var audio_player := current_scene.get_node_or_null("SonarAudio") as AudioStreamPlayer
|
|
if audio_player != null:
|
|
audio_player.stop()
|
|
audio_player.stream = null
|
|
await process_frame
|
|
current_scene.queue_free()
|
|
await process_frame
|
|
quit(exit_code)
|
|
|
|
|
|
func _on_ping_progress(
|
|
current_cells: Array[Dictionary],
|
|
previous_cells: Array[Dictionary],
|
|
_progress: float
|
|
) -> void:
|
|
_progress_cells = current_cells.duplicate(true)
|
|
_last_previous_cells = previous_cells.duplicate(true)
|
|
|
|
|
|
func _on_ping_completed(
|
|
current_cells: Array[Dictionary],
|
|
previous_cells: Array[Dictionary]
|
|
) -> void:
|
|
_last_cells = current_cells.duplicate(true)
|
|
_last_previous_cells = previous_cells.duplicate(true)
|
|
_completion_count += 1
|
|
|
|
|
|
func _metal_cell_count(cells: Array[Dictionary]) -> int:
|
|
var count := 0
|
|
for cell: Dictionary in cells:
|
|
if int(cell["material"]) == SonarModelScript.MaterialCategory.METAL:
|
|
count += 1
|
|
return count
|
|
|
|
|
|
func _bathymetry_cell_count(cells: Array[Dictionary]) -> int:
|
|
var count := 0
|
|
for cell: Dictionary in cells:
|
|
if String(cell.get("sample_type", "")) == "bathymetry":
|
|
count += 1
|
|
return count
|
|
|
|
|
|
func _expect(condition: bool, label: String) -> void:
|
|
if not condition:
|
|
_failures.append(label)
|