Render bathymetric sonar surface

This commit is contained in:
chindit committed 2026-10-06 07:59:50 +02:00
1 parent fdebbafeae
commit b6f6b53a70
7 files changed
+305 -135

No files matched your search

@@ -19,7 +19,7 @@ const ProductionInputAdapter = preload(
"res://game/infrastructure/input/production_input_adapter.gd"
)
const TEST_COUNT := 69
const TEST_COUNT := 78
var _failures: Array[String] = []
@@ -125,6 +125,28 @@ func _test_vehicle_slice(composition: VerticalSliceRoot) -> void:
_expect(instruments.get_node("%WindowFrame") is MeshInstance3D, "cockpit has a physical porthole frame")
_expect(instruments.get_node("%Dashboard") is Node3D, "cockpit has a physical dashboard")
_expect(instruments.get_node("%SonarScreen") is MeshInstance3D, "cockpit reserves a physical sonar display")
var sonar_monitor := instruments.get_node("SonarMonitor") as Node3D
var sonar_screen := instruments.get_node("%SonarScreen") as MeshInstance3D
var sonar_housing := instruments.get_node("SonarMonitor/Housing") as MeshInstance3D
var cockpit_camera := camera.get_node("Camera") as Camera3D
var electrical_bank := detailing.get_node("SideEquipment/ElectricalBank") as Node3D
_expect(sonar_monitor.position.x > 0.5, "cockpit sonar is mounted on the right side")
_expect(
_sonar_screen_faces_camera(sonar_screen, cockpit_camera),
"right-side sonar display faces the pilot"
)
_expect(
_sonar_screen_is_ahead_of_bank(sonar_screen, electrical_bank),
"right-side electrical equipment does not hide the sonar display"
)
_expect(
_sonar_screen_clears_housing(sonar_screen, sonar_housing),
"sonar texture clears its housing without depth overlap"
)
_expect(
instruments.find_children("SonarReferenceTrace", "MeshInstance3D", true).is_empty(),
"cockpit sonar does not invent a decorative profile"
)
_expect(detailing.pressure_hull_rib_count() >= 6, "cockpit exposes reinforced pressure-hull structure")
_expect(detailing.pipe_segment_count() >= 13, "cockpit exposes a complete life-support pipe run")
_expect(absf(detailing.battery_needle_degrees()) > 100.0, "analog battery gauge follows the dive snapshot")
@@ -148,6 +170,7 @@ func _test_vehicle_slice(composition: VerticalSliceRoot) -> void:
instruments.sonar_texture() == sonar_display.sonar_texture(),
"physical and expanded sonar views share one texture"
)
_expect(sonar_display.idle_prompt_visible(), "idle sonar explains how to emit a scan")
adapter.sonar_scan_requested.emit()
var first_scan = sonar_service.current_scan()
@@ -155,9 +178,12 @@ func _test_vehicle_slice(composition: VerticalSliceRoot) -> void:
_expect(first_scan.samples.observed_count() > 1000, "reference acquisition captures dense bathymetry")
_expect(first_scan.contacts.size() >= 1, "metal calibration target becomes a distinct contact")
_expect("RELEVÉ EN COURS" in sonar_display.status_text(), "sonar display reports progressive reveal")
for frame in 8:
_expect(not sonar_display.idle_prompt_visible(), "sonar data replaces the idle instruction")
for frame in 18:
await physics_frame
_expect(sonar_display.built_row_count() > 0, "renderer reveals near rows incrementally")
_expect(sonar_display.built_triangle_count() >= 90, "sonar renders a dense relief surface, not a line")
_expect(sonar_display.built_grid_segment_count() > 0, "sonar overlays a perspective grid on the relief")
adapter.sonar_view_toggle_requested.emit()
_expect(sonar_display.is_expanded(), "sonar can expand without pausing the dive")
adapter.sonar_view_toggle_requested.emit()
@@ -276,6 +302,47 @@ func _pressed_key(keycode: Key) -> InputEventKey:
return event
func _sonar_screen_faces_camera(
sonar_screen: MeshInstance3D,
cockpit_camera: Camera3D
) -> bool:
if sonar_screen == null or cockpit_camera == null:
return false
var direction_to_camera := (
cockpit_camera.global_position - sonar_screen.global_position
).normalized()
return sonar_screen.global_basis.z.normalized().dot(direction_to_camera) > 0.85
func _sonar_screen_is_ahead_of_bank(
sonar_screen: MeshInstance3D,
electrical_bank: Node3D
) -> bool:
if sonar_screen == null or electrical_bank == null:
return false
for child: Node in electrical_bank.get_children():
if child is MeshInstance3D and child.name.begins_with("JunctionBox"):
if sonar_screen.global_position.z <= (child as MeshInstance3D).global_position.z:
return false
return true
func _sonar_screen_clears_housing(
sonar_screen: MeshInstance3D,
sonar_housing: MeshInstance3D
) -> bool:
if sonar_screen == null or sonar_housing == null:
return false
var housing_box := sonar_housing.mesh as BoxMesh
if housing_box == null:
return false
var housing_front_z := (
sonar_housing.position.z
+ housing_box.size.z * sonar_housing.scale.z * 0.5
)
return sonar_screen.position.z >= housing_front_z + 0.005
func _binding_for(adapter: ProductionInputAdapter, action_id: StringName) -> String:
for binding in adapter.binding_snapshots():
if binding.action_id == action_id: