Integrate gauges into cockpit dashboard

This commit is contained in:
chindit committed 2026-10-03 09:40:36 +02:00
1 parent 0b79bf9b82
commit 53288b48c8
7 files changed
+213 -17

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@ production sous `game/` n'en dépend.
télémétrie typés.
- Habitacle 3D solidaire de la coque : hublot occultant, consoles, commandes,
éclairage, structure de coque renforcée, conduites, jauges analogiques et
emplacement réservé au sonar.
tableau d'instruments structuré, et emplacement réservé au sonar.
- Instruments physiques à valeurs réelles ; le HUD reste réservé aux alertes,
à l'éjection et aux états terminaux.
- Pause qui suspend les ticks, confirmations de sortie et premier remappage avec
+3
View File
@@ -811,6 +811,9 @@ Complément du 3 octobre 2026 : le plafond, le boîtier supérieur et les faces
jauges utilisent des textures bitmap dédiées. Les cadrans reçoivent en plus des
graduations, une aiguille peinte et une vitre distincte ; le plafonnier est
réduit et protégé par une grille pour conserver des proportions crédibles.
Les jauges de charge batterie et de pression coque sont regroupées dans un
binnacle solidaire du tableau de bord, hors du hublot. La façade du tableau est
structurée par des rails, séparateurs, vis et banques de commutateurs physiques.
- Construire une coque intérieure 3D fixe par rapport au véhicule, indépendante
du regard de la caméra.
@@ -12,8 +12,19 @@ var _pressure_needle: Node3D
func _init(materials: CockpitMaterialPalette) -> void:
_materials = materials
name = "AnalogGauges"
_battery_needle = _add_gauge("BatteryGauge", Vector3(-0.34, 0.48, -1.14), "BAT")
_pressure_needle = _add_gauge("PressureGauge", Vector3(0.34, 0.48, -1.14), "BAR")
_build_binnacle()
_battery_needle = _add_gauge(
"BatteryGauge",
Vector3(-0.095, 0.315, 0.145),
"%"
)
_pressure_needle = _add_gauge(
"PressureGauge",
Vector3(0.095, 0.315, 0.145),
"BAR"
)
_add_binnacle_label("CHARGE BAT.", Vector3(-0.095, 0.235, 0.160))
_add_binnacle_label("PRESSION COQUE", Vector3(0.095, 0.235, 0.160))
func present(battery_ratio: float, pressure_ratio: float) -> void:
@@ -25,11 +36,39 @@ func battery_needle_degrees() -> float:
return 0.0 if _battery_needle == null else _battery_needle.rotation_degrees.z
func _build_binnacle() -> void:
CockpitMeshFactory.add_box(
"BinnacleHousing",
self,
Vector3(0.0, 0.290, 0.095),
Vector3(0.40, 0.180, 0.105),
_materials.overhead_steel
)
CockpitMeshFactory.add_box(
"BinnacleFoot",
self,
Vector3(0.0, 0.205, 0.075),
Vector3(0.47, 0.040, 0.14),
_materials.dark_steel
)
func _add_binnacle_label(caption: String, position: Vector3) -> void:
var label := Label3D.new()
label.name = "%sLabel" % caption.to_pascal_case().replace(" ", "")
label.text = caption
label.font_size = 12
label.pixel_size = 0.00055
label.modulate = Color(0.76, 0.72, 0.60)
label.position = position
add_child(label)
func _add_gauge(gauge_name: String, position: Vector3, caption: String) -> Node3D:
var gauge := Node3D.new()
gauge.name = gauge_name
gauge.position = position
gauge.scale = Vector3(0.78, 0.78, 0.78)
gauge.scale = Vector3(0.62, 0.62, 0.62)
add_child(gauge)
CockpitMeshFactory.add_box(
"MountingPlate",
@@ -0,0 +1,114 @@
class_name CockpitDashboardDetailing
extends Node3D
const CockpitMaterialPalette = preload(
"res://game/presentation/cockpit/cockpit_material_palette.gd"
)
const CockpitMeshFactory = preload(
"res://game/presentation/cockpit/cockpit_mesh_factory.gd"
)
var _materials: CockpitMaterialPalette
var _control_count := 0
func _init(materials: CockpitMaterialPalette) -> void:
_materials = materials
name = "DashboardDetailing"
_build_structural_frame()
_build_switch_banks()
func control_count() -> int:
return _control_count
func apply_screen_materials(dashboard: Node3D) -> void:
for screen_name: String in ["ResourcesScreen", "NavigationScreen", "IntegrityScreen"]:
var screen := dashboard.get_node_or_null(screen_name) as MeshInstance3D
if screen != null:
screen.material_override = _materials.instrument_screen
func _build_structural_frame() -> void:
CockpitMeshFactory.add_box(
"TopRail",
self,
Vector3(0.0, 0.255, 0.115),
Vector3(1.50, 0.055, 0.055),
_materials.dark_steel
)
CockpitMeshFactory.add_box(
"BottomRail",
self,
Vector3(0.0, -0.205, 0.115),
Vector3(1.50, 0.050, 0.055),
_materials.dark_steel
)
for x: float in [-0.755, 0.755]:
CockpitMeshFactory.add_box(
"SideRail",
self,
Vector3(x, 0.025, 0.115),
Vector3(0.050, 0.46, 0.055),
_materials.dark_steel
)
for x: float in [-0.238, 0.238]:
CockpitMeshFactory.add_box(
"ScreenSeparator",
self,
Vector3(x, 0.015, 0.118),
Vector3(0.038, 0.39, 0.048),
_materials.brass
)
for screw_position: Vector2 in [
Vector2(-0.72, -0.18),
Vector2(-0.72, 0.23),
Vector2(0.72, -0.18),
Vector2(0.72, 0.23),
Vector2(-0.24, -0.18),
Vector2(0.24, -0.18),
]:
CockpitMeshFactory.add_cylinder(
"PanelScrew",
self,
Vector3(screw_position.x, screw_position.y, 0.151),
0.010,
0.010,
_materials.brass,
Vector3(90.0, 0.0, 0.0)
)
func _build_switch_banks() -> void:
_add_switch_bank(-0.59, "AUX")
_add_switch_bank(0.59, "POMPES")
func _add_switch_bank(center_x: float, caption: String) -> void:
CockpitMeshFactory.add_box(
"SwitchPlate",
self,
Vector3(center_x, -0.205, 0.145),
Vector3(0.25, 0.060, 0.020),
_materials.overhead_steel
)
for offset: float in [-0.075, -0.025, 0.025, 0.075]:
CockpitMeshFactory.add_cylinder(
"ToggleSwitch",
self,
Vector3(center_x + offset, -0.195, 0.171),
0.006,
0.030,
_materials.dark_steel,
Vector3(90.0, 0.0, 0.0)
)
_control_count += 1
var label := Label3D.new()
label.name = "%sLabel" % caption.to_pascal_case()
label.text = caption
label.font_size = 10
label.pixel_size = 0.00055
label.modulate = Color(0.72, 0.69, 0.56)
label.position = Vector3(center_x, -0.235, 0.165)
add_child(label)
+24 -12
View File
@@ -5,6 +5,9 @@ const DiveUpdate = preload("res://game/domain/dive/dive_update.gd")
const DiveAlertLevel = preload("res://game/domain/dive/dive_alert_level.gd")
const VehicleTelemetry = preload("res://game/application/dive/vehicle_telemetry.gd")
const CockpitAnalogGauges = preload("res://game/presentation/cockpit/cockpit_analog_gauges.gd")
const CockpitDashboardDetailing = preload(
"res://game/presentation/cockpit/cockpit_dashboard_detailing.gd"
)
const CockpitMaterialPalette = preload("res://game/presentation/cockpit/cockpit_material_palette.gd")
const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh_factory.gd")
@@ -14,9 +17,8 @@ var _dark_steel: Material
var _overhead_steel: Material
var _brass: Material
var _copper: Material
var _rubber: Material
var _warm_emission: StandardMaterial3D
var _analog_gauges: CockpitAnalogGauges
var _dashboard_detailing: CockpitDashboardDetailing
var _warm_practical: OmniLight3D
var _emergency_light: OmniLight3D
@@ -28,7 +30,7 @@ func _ready() -> void:
_build_life_support_pipes()
_build_overhead_console()
_build_panel_hardware()
_build_analog_gauges()
_build_dashboard_instrumentation()
_build_practical_lights()
@@ -74,6 +76,14 @@ func textures_are_loaded() -> bool:
)
func dashboard_control_count() -> int:
return 0 if _dashboard_detailing == null else _dashboard_detailing.control_count()
func gauges_are_dashboard_mounted() -> bool:
return _analog_gauges != null and _analog_gauges.get_parent() == get_parent().get_node("Dashboard")
func _create_materials() -> void:
_materials = CockpitMaterialPalette.new()
_painted_steel = _materials.painted_steel
@@ -81,8 +91,6 @@ func _create_materials() -> void:
_overhead_steel = _materials.overhead_steel
_brass = _materials.brass
_copper = _materials.copper
_rubber = _materials.rubber
_warm_emission = _materials.warm_emission
func _apply_materials_to_existing_cockpit() -> void:
@@ -91,7 +99,6 @@ func _apply_materials_to_existing_cockpit() -> void:
[
"CabinShell/LeftWall",
"CabinShell/RightWall",
"Dashboard/MainPanel",
"LeftConsole",
"RightConsole",
]
@@ -112,6 +119,7 @@ func _apply_materials_to_existing_cockpit() -> void:
[
"CabinShell/Ceiling",
"PortholeAssembly/TopBulkhead",
"Dashboard/MainPanel",
]
)
_apply_material_to_paths(
@@ -125,8 +133,6 @@ func _apply_materials_to_existing_cockpit() -> void:
"VerticalKnob",
]
)
func _apply_material_to_paths(material: Material, paths: Array[String]) -> void:
var cockpit := get_parent()
for path: String in paths:
@@ -241,7 +247,7 @@ func _build_overhead_console() -> void:
root,
Vector3(0.0, 0.895, -0.985),
Vector3(0.13, 0.010, 0.026),
_warm_emission,
_materials.warm_emission,
Vector3(-8.0, 0.0, 0.0)
)
for guard_index in 5:
@@ -262,7 +268,7 @@ func _build_overhead_console() -> void:
Vector3(x, 0.965, -0.985),
0.004,
0.018,
_rubber,
_materials.rubber,
Vector3(90.0, 0.0, 0.0)
)
@@ -302,9 +308,15 @@ func _build_panel_hardware() -> void:
root.add_child(label)
func _build_analog_gauges() -> void:
func _build_dashboard_instrumentation() -> void:
var dashboard := get_parent().get_node_or_null("Dashboard") as Node3D
if dashboard == null:
return
_dashboard_detailing = CockpitDashboardDetailing.new(_materials)
dashboard.add_child(_dashboard_detailing)
_dashboard_detailing.apply_screen_materials(dashboard)
_analog_gauges = CockpitAnalogGauges.new(_materials)
add_child(_analog_gauges)
dashboard.add_child(_analog_gauges)
func _build_practical_lights() -> void:
@@ -17,6 +17,7 @@ var rubber: Material
var gauge_face: StandardMaterial3D
var gauge_glass: StandardMaterial3D
var needle_paint: StandardMaterial3D
var instrument_screen: ShaderMaterial
var warm_emission: StandardMaterial3D
@@ -65,6 +66,7 @@ func _init() -> void:
)
gauge_glass = _glass_material()
needle_paint = _plain_material(Color(0.68, 0.055, 0.022), 0.12, 0.44)
instrument_screen = _screen_material()
warm_emission = _emissive_material(Color(0.96, 0.52, 0.18), 2.4)
@@ -167,6 +169,30 @@ func _glass_material() -> StandardMaterial3D:
return material
func _screen_material() -> ShaderMaterial:
var shader := Shader.new()
shader.code = """
shader_type spatial;
render_mode diffuse_burley, specular_schlick_ggx;
void fragment() {
vec2 centered = UV - vec2(0.5);
float vignette = 1.0 - smoothstep(0.28, 0.72, length(centered));
float scanline = 0.94 + 0.06 * sin(UV.y * 720.0);
float edge = mix(0.68, 1.0, vignette);
vec3 phosphor = vec3(0.025, 0.105, 0.11) * edge * scanline;
ALBEDO = phosphor;
EMISSION = phosphor * 0.38;
METALLIC = 0.08;
ROUGHNESS = 0.18;
SPECULAR = 0.82;
}
"""
var material := ShaderMaterial.new()
material.shader = shader
return material
func _emissive_material(color: Color, energy: float) -> StandardMaterial3D:
var material := StandardMaterial3D.new()
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
@@ -16,7 +16,7 @@ const ProductionInputAdapter = preload(
"res://game/infrastructure/input/production_input_adapter.gd"
)
const TEST_COUNT := 56
const TEST_COUNT := 58
var _failures: Array[String] = []
@@ -112,6 +112,8 @@ func _test_vehicle_slice(composition: VerticalSliceRoot) -> void:
_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")
_expect(detailing.textures_are_loaded(), "cockpit loads its overhead and analog gauge textures")
_expect(detailing.gauges_are_dashboard_mounted(), "analog gauges are mounted on the dashboard")
_expect(detailing.dashboard_control_count() >= 8, "dashboard exposes physical auxiliary controls")
_expect("kWh" in instruments.resources_text() and "kW" in instruments.resources_text(), "battery instrument has exact units")
_expect("L/min" in instruments.resources_text(), "oxygen instrument has volume and consumption")
_expect("bar" in instruments.integrity_text(), "hull instrument has current and certified pressure")