Reframe cockpit around industrial reference

This commit is contained in:
chindit committed 2026-10-04 09:50:41 +02:00
1 parent c2b3ac42a3
commit dffe790926
9 files changed
+146 -95

No files matched your search

+5 -4
View File
@@ -816,10 +816,11 @@ 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. structurée par des rails, séparateurs, vis et banques de commutateurs physiques.
Passe du 4 octobre 2026 : les quatre volumes rectangulaires autour du hublot Passe du 4 octobre 2026 : les quatre volumes rectangulaires autour du hublot
sont remplacés par douze panneaux annulaires bombés, séparés par des joints fins sont remplacés par une cloison annulaire bombée continue, serrée entre deux
et ceinturés par un raidisseur. Les cadrans utilisent des graduations physiques raidisseurs métalliques et boulonnée. Le tableau reprend la hiérarchie de la
et les témoins colorés provisoires sont remplacés par trois voyants encastrés ; référence `design.jpg` : quatre cadrans principaux de tailles variées, petits
un seul voyant reflète l'état d'alerte courant. afficheurs de valeurs exactes et trois voyants encastrés dont un seul reflète
l'état d'alerte courant.
- Construire une coque intérieure 3D fixe par rapport au véhicule, indépendante - Construire une coque intérieure 3D fixe par rapport au véhicule, indépendante
du regard de la caméra. du regard de la caméra.
@@ -6,8 +6,10 @@ const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh
const DiveAlertLevel = preload("res://game/domain/dive/dive_alert_level.gd") const DiveAlertLevel = preload("res://game/domain/dive/dive_alert_level.gd")
var _materials: CockpitMaterialPalette var _materials: CockpitMaterialPalette
var _oxygen_needle: Node3D
var _battery_needle: Node3D var _battery_needle: Node3D
var _pressure_needle: Node3D var _hull_needle: Node3D
var _depth_needle: Node3D
var _indicator_materials: Array[StandardMaterial3D] = [] var _indicator_materials: Array[StandardMaterial3D] = []
var _active_indicator_count := 0 var _active_indicator_count := 0
@@ -15,29 +17,49 @@ var _active_indicator_count := 0
func _init(materials: CockpitMaterialPalette) -> void: func _init(materials: CockpitMaterialPalette) -> void:
_materials = materials _materials = materials
name = "AnalogGauges" name = "AnalogGauges"
_build_binnacle() _build_instrument_cluster()
_build_indicator_bank() _build_indicator_bank()
_oxygen_needle = _add_gauge(
"OxygenGauge",
Vector3(-0.50, 0.12, 0.145),
"%",
0.72
)
_battery_needle = _add_gauge( _battery_needle = _add_gauge(
"BatteryGauge", "BatteryGauge",
Vector3(-0.095, 0.315, 0.145), Vector3(-0.22, 0.12, 0.145),
"%" "%",
0.72
) )
_pressure_needle = _add_gauge( _hull_needle = _add_gauge(
"PressureGauge", "HullGauge",
Vector3(0.095, 0.315, 0.145), Vector3(0.05, 0.12, 0.145),
"BAR" "%",
0.56
) )
_add_binnacle_label("CHARGE BAT.", Vector3(-0.095, 0.235, 0.160)) _depth_needle = _add_gauge(
_add_binnacle_label("PRESSION COQUE", Vector3(0.095, 0.235, 0.160)) "DepthGauge",
Vector3(0.40, 0.12, 0.145),
"%",
0.90
)
_add_cluster_label("OXYGÈNE", Vector3(-0.50, 0.025, 0.170))
_add_cluster_label("BATTERIE", Vector3(-0.22, 0.025, 0.170))
_add_cluster_label("COQUE", Vector3(0.05, 0.045, 0.170))
_add_cluster_label("PROFONDEUR", Vector3(0.40, 0.005, 0.170))
func present( func present(
oxygen_ratio: float,
battery_ratio: float, battery_ratio: float,
pressure_ratio: float, hull_ratio: float,
depth_ratio: float,
alert_level: DiveAlertLevel.Value alert_level: DiveAlertLevel.Value
) -> void: ) -> void:
_set_needle_ratio(_oxygen_needle, oxygen_ratio)
_set_needle_ratio(_battery_needle, battery_ratio) _set_needle_ratio(_battery_needle, battery_ratio)
_set_needle_ratio(_pressure_needle, pressure_ratio) _set_needle_ratio(_hull_needle, hull_ratio)
_set_needle_ratio(_depth_needle, depth_ratio)
_update_indicator_bank(alert_level) _update_indicator_bank(alert_level)
@@ -49,23 +71,27 @@ func indicator_count() -> int:
return _indicator_materials.size() return _indicator_materials.size()
func gauge_count() -> int:
return 4
func active_indicator_count() -> int: func active_indicator_count() -> int:
return _active_indicator_count return _active_indicator_count
func _build_binnacle() -> void: func _build_instrument_cluster() -> void:
CockpitMeshFactory.add_box( CockpitMeshFactory.add_box(
"BinnacleHousing", "InstrumentClusterHousing",
self, self,
Vector3(0.0, 0.290, 0.095), Vector3(-0.04, 0.105, 0.095),
Vector3(0.40, 0.180, 0.105), Vector3(1.26, 0.255, 0.105),
_materials.overhead_steel _materials.overhead_steel
) )
CockpitMeshFactory.add_box( CockpitMeshFactory.add_box(
"BinnacleFoot", "InstrumentClusterFoot",
self, self,
Vector3(0.0, 0.205, 0.075), Vector3(-0.04, -0.025, 0.075),
Vector3(0.47, 0.040, 0.14), Vector3(1.32, 0.040, 0.14),
_materials.dark_steel _materials.dark_steel
) )
@@ -81,11 +107,11 @@ func _build_indicator_bank() -> void:
] ]
var captions: Array[String] = ["SYS", "ATTN", "ALRM"] var captions: Array[String] = ["SYS", "ATTN", "ALRM"]
for indicator_index in colors.size(): for indicator_index in colors.size():
var x := -0.055 + indicator_index * 0.055 var y := 0.165 - indicator_index * 0.050
CockpitMeshFactory.add_cylinder( CockpitMeshFactory.add_cylinder(
"%sBezel" % captions[indicator_index], "%sBezel" % captions[indicator_index],
root, root,
Vector3(x, 0.198, 0.156), Vector3(0.205, y, 0.156),
0.016, 0.016,
0.012, 0.012,
_materials.brass, _materials.brass,
@@ -96,7 +122,7 @@ func _build_indicator_bank() -> void:
CockpitMeshFactory.add_cylinder( CockpitMeshFactory.add_cylinder(
"%sLens" % captions[indicator_index], "%sLens" % captions[indicator_index],
root, root,
Vector3(x, 0.198, 0.165), Vector3(0.205, y, 0.165),
0.009, 0.009,
0.008, 0.008,
material, material,
@@ -108,7 +134,7 @@ func _build_indicator_bank() -> void:
label.font_size = 8 label.font_size = 8
label.pixel_size = 0.00042 label.pixel_size = 0.00042
label.modulate = Color(0.70, 0.67, 0.56) label.modulate = Color(0.70, 0.67, 0.56)
label.position = Vector3(x, 0.177, 0.168) label.position = Vector3(0.235, y, 0.168)
root.add_child(label) root.add_child(label)
@@ -136,7 +162,7 @@ func _update_indicator_bank(alert_level: DiveAlertLevel.Value) -> void:
_active_indicator_count = 1 _active_indicator_count = 1
func _add_binnacle_label(caption: String, position: Vector3) -> void: func _add_cluster_label(caption: String, position: Vector3) -> void:
var label := Label3D.new() var label := Label3D.new()
label.name = "%sLabel" % caption.to_pascal_case().replace(" ", "") label.name = "%sLabel" % caption.to_pascal_case().replace(" ", "")
label.text = caption label.text = caption
@@ -147,18 +173,23 @@ func _add_binnacle_label(caption: String, position: Vector3) -> void:
add_child(label) add_child(label)
func _add_gauge(gauge_name: String, position: Vector3, caption: String) -> Node3D: func _add_gauge(
gauge_name: String,
position: Vector3,
caption: String,
gauge_scale: float
) -> Node3D:
var gauge := Node3D.new() var gauge := Node3D.new()
gauge.name = gauge_name gauge.name = gauge_name
gauge.position = position gauge.position = position
gauge.scale = Vector3(0.62, 0.62, 0.62) gauge.scale = Vector3(gauge_scale, gauge_scale, gauge_scale)
add_child(gauge) add_child(gauge)
CockpitMeshFactory.add_box( CockpitMeshFactory.add_box(
"MountingPlate", "MountingPlate",
gauge, gauge,
Vector3(0.0, 0.0, -0.025), Vector3(0.0, 0.0, -0.025),
Vector3(0.225, 0.225, 0.055), Vector3(0.225, 0.225, 0.055),
_materials.dark_steel _materials.overhead_steel
) )
for screw_position: Vector2 in [ for screw_position: Vector2 in [
Vector2(-0.086, -0.086), Vector2(-0.086, -0.086),
@@ -182,7 +213,7 @@ func _add_gauge(gauge_name: String, position: Vector3, caption: String) -> Node3
bezel_mesh.height = 0.035 bezel_mesh.height = 0.035
bezel_mesh.radial_segments = 32 bezel_mesh.radial_segments = 32
bezel.mesh = bezel_mesh bezel.mesh = bezel_mesh
bezel.material_override = _materials.brass bezel.material_override = _materials.brushed_steel
bezel.rotation_degrees.x = 90.0 bezel.rotation_degrees.x = 90.0
gauge.add_child(bezel) gauge.add_child(bezel)
var face := MeshInstance3D.new() var face := MeshInstance3D.new()
@@ -64,8 +64,8 @@ func _build_structural_frame() -> void:
CockpitMeshFactory.add_box( CockpitMeshFactory.add_box(
"ScreenSeparator", "ScreenSeparator",
self, self,
Vector3(x, 0.015, 0.118), Vector3(x, -0.075, 0.118),
Vector3(0.038, 0.39, 0.048), Vector3(0.038, 0.16, 0.048),
_materials.brass _materials.brass
) )
for screw_position: Vector2 in [ for screw_position: Vector2 in [
@@ -14,7 +14,6 @@ const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh
var _materials: CockpitMaterialPalette var _materials: CockpitMaterialPalette
var _painted_steel: Material var _painted_steel: Material
var _dark_steel: Material var _dark_steel: Material
var _overhead_steel: Material
var _brass: Material var _brass: Material
var _copper: Material var _copper: Material
var _analog_gauges: CockpitAnalogGauges var _analog_gauges: CockpitAnalogGauges
@@ -39,10 +38,12 @@ func present(update: DiveUpdate, telemetry: VehicleTelemetry) -> void:
return return
var snapshot = update.snapshot var snapshot = update.snapshot
_analog_gauges.present( _analog_gauges.present(
snapshot.oxygen.ratio,
snapshot.battery.ratio, snapshot.battery.ratio,
snapshot.hull.ratio,
clampf( clampf(
snapshot.hull.exterior_pressure_bar snapshot.depth.current_m
/ maxf(snapshot.hull.certified_pressure_bar, 0.001), / maxf(snapshot.depth.certified_m, 0.001),
0.0, 0.0,
1.0 1.0
), ),
@@ -89,7 +90,6 @@ func _create_materials() -> void:
_materials = CockpitMaterialPalette.new() _materials = CockpitMaterialPalette.new()
_painted_steel = _materials.painted_steel _painted_steel = _materials.painted_steel
_dark_steel = _materials.dark_steel _dark_steel = _materials.dark_steel
_overhead_steel = _materials.overhead_steel
_brass = _materials.brass _brass = _materials.brass
_copper = _materials.copper _copper = _materials.copper
@@ -116,7 +116,7 @@ func _apply_materials_to_existing_cockpit() -> void:
] ]
) )
_apply_material_to_paths( _apply_material_to_paths(
_overhead_steel, _materials.overhead_steel,
[ [
"CabinShell/Ceiling", "CabinShell/Ceiling",
"PortholeAssembly/TopBulkhead", "PortholeAssembly/TopBulkhead",
@@ -240,7 +240,7 @@ func _build_overhead_console() -> void:
root, root,
Vector3(0.0, 0.94, -1.06), Vector3(0.0, 0.94, -1.06),
Vector3(0.30, 0.09, 0.12), Vector3(0.30, 0.09, 0.12),
_overhead_steel, _materials.overhead_steel,
Vector3(-8.0, 0.0, 0.0) Vector3(-8.0, 0.0, 0.0)
) )
CockpitMeshFactory.add_box( CockpitMeshFactory.add_box(
@@ -30,20 +30,16 @@ func present(update: DiveUpdate, telemetry: VehicleTelemetry) -> void:
return return
var snapshot = update.snapshot var snapshot = update.snapshot
_resources_label.text = ( _resources_label.text = (
"BATTERIE\n%.1f / %.1f kWh · %.0f %%\n%.0f kW\n\nOXYGÈNE\n%.1f / %.1f L · %.0f %%\n%.1f L/min" "BAT %.1f kWh · O₂ %.0f %%\n%.0f kW · %.1f L/min"
% [ % [
snapshot.battery.remaining_kwh, snapshot.battery.remaining_kwh,
snapshot.battery.maximum_kwh,
snapshot.battery.ratio * 100.0,
snapshot.battery.current_power_kw,
snapshot.oxygen.remaining_l,
snapshot.oxygen.maximum_l,
snapshot.oxygen.ratio * 100.0, snapshot.oxygen.ratio * 100.0,
snapshot.battery.current_power_kw,
snapshot.oxygen.consumption_l_per_min, snapshot.oxygen.consumption_l_per_min,
] ]
) )
_navigation_label.text = ( _navigation_label.text = (
"PROFONDEUR\n%.1f m\nMAX. CONSEILLÉ %.1f m\n\nVITESSE\n%.2f m/s" "PROF. %.1f / %.1f m\nVIT. %.2f m/s"
% [ % [
snapshot.depth.current_m, snapshot.depth.current_m,
snapshot.depth.certified_m, snapshot.depth.certified_m,
@@ -51,10 +47,8 @@ func present(update: DiveUpdate, telemetry: VehicleTelemetry) -> void:
] ]
) )
_integrity_label.text = ( _integrity_label.text = (
"COQUE\n%.1f / %.1f · %.0f %%\n\nPRESSION\n%.2f / %.2f bar" "COQUE %.0f %% · %.2f bar\nLIMITE %.2f bar"
% [ % [
snapshot.hull.current_integrity,
snapshot.hull.maximum_integrity,
snapshot.hull.ratio * 100.0, snapshot.hull.ratio * 100.0,
snapshot.hull.exterior_pressure_bar, snapshot.hull.exterior_pressure_bar,
snapshot.hull.certified_pressure_bar, snapshot.hull.certified_pressure_bar,
+35 -35
View File
@@ -267,82 +267,82 @@ mesh = SubResource("UnitBoxMesh")
material_override = SubResource("PaintedMaterial") material_override = SubResource("PaintedMaterial")
[node name="ResourcesFrame" type="MeshInstance3D" parent="Dashboard"] [node name="ResourcesFrame" type="MeshInstance3D" parent="Dashboard"]
position = Vector3(-0.5, 0.03, 0.088) position = Vector3(-0.5, -0.075, 0.088)
scale = Vector3(0.45, 0.31, 0.025) scale = Vector3(0.45, 0.115, 0.025)
mesh = SubResource("UnitBoxMesh") mesh = SubResource("UnitBoxMesh")
material_override = SubResource("BrassMaterial") material_override = SubResource("BrassMaterial")
[node name="ResourcesScreen" type="MeshInstance3D" parent="Dashboard"] [node name="ResourcesScreen" type="MeshInstance3D" parent="Dashboard"]
position = Vector3(-0.5, 0.03, 0.102) position = Vector3(-0.5, -0.075, 0.102)
scale = Vector3(0.41, 0.27, 1) scale = Vector3(0.41, 0.085, 1)
mesh = SubResource("ScreenQuadMesh") mesh = SubResource("ScreenQuadMesh")
material_override = SubResource("ScreenMaterial") material_override = SubResource("ScreenMaterial")
[node name="ResourcesLabel" type="Label3D" parent="Dashboard"] [node name="ResourcesLabel" type="Label3D" parent="Dashboard"]
unique_name_in_owner = true unique_name_in_owner = true
position = Vector3(-0.5, 0.03, 0.108) position = Vector3(-0.5, -0.075, 0.108)
pixel_size = 0.00115 pixel_size = 0.00082
font_size = 20 font_size = 14
outline_size = 2 outline_size = 2
text = "BATTERIE\n— / — kWh\n— kW\n\nOXYGÈNE\n— / — L\n— L/min" text = "BAT — kWh · O₂ — %\n— kW · — L/min"
modulate = Color(0.45, 0.89, 0.9, 1) modulate = Color(0.45, 0.89, 0.9, 1)
[node name="NavigationFrame" type="MeshInstance3D" parent="Dashboard"] [node name="NavigationFrame" type="MeshInstance3D" parent="Dashboard"]
position = Vector3(0, 0.03, 0.088) position = Vector3(0, -0.075, 0.088)
scale = Vector3(0.4, 0.31, 0.025) scale = Vector3(0.4, 0.115, 0.025)
mesh = SubResource("UnitBoxMesh") mesh = SubResource("UnitBoxMesh")
material_override = SubResource("BrassMaterial") material_override = SubResource("BrassMaterial")
[node name="NavigationScreen" type="MeshInstance3D" parent="Dashboard"] [node name="NavigationScreen" type="MeshInstance3D" parent="Dashboard"]
position = Vector3(0, 0.03, 0.102) position = Vector3(0, -0.075, 0.102)
scale = Vector3(0.36, 0.27, 1) scale = Vector3(0.36, 0.085, 1)
mesh = SubResource("ScreenQuadMesh") mesh = SubResource("ScreenQuadMesh")
material_override = SubResource("ScreenMaterial") material_override = SubResource("ScreenMaterial")
[node name="NavigationLabel" type="Label3D" parent="Dashboard"] [node name="NavigationLabel" type="Label3D" parent="Dashboard"]
unique_name_in_owner = true unique_name_in_owner = true
position = Vector3(0, 0.03, 0.108) position = Vector3(0, -0.075, 0.108)
pixel_size = 0.00115 pixel_size = 0.00082
font_size = 20 font_size = 14
outline_size = 2 outline_size = 2
text = "PROFONDEUR\n— m\nMAX. — m\n\nVITESSE\n— m/s" text = "PROF. — / — m\nVIT. — m/s"
modulate = Color(0.45, 0.89, 0.9, 1) modulate = Color(0.45, 0.89, 0.9, 1)
[node name="IntegrityFrame" type="MeshInstance3D" parent="Dashboard"] [node name="IntegrityFrame" type="MeshInstance3D" parent="Dashboard"]
position = Vector3(0.5, 0.03, 0.088) position = Vector3(0.5, -0.075, 0.088)
scale = Vector3(0.45, 0.31, 0.025) scale = Vector3(0.45, 0.115, 0.025)
mesh = SubResource("UnitBoxMesh") mesh = SubResource("UnitBoxMesh")
material_override = SubResource("BrassMaterial") material_override = SubResource("BrassMaterial")
[node name="IntegrityScreen" type="MeshInstance3D" parent="Dashboard"] [node name="IntegrityScreen" type="MeshInstance3D" parent="Dashboard"]
position = Vector3(0.5, 0.03, 0.102) position = Vector3(0.5, -0.075, 0.102)
scale = Vector3(0.41, 0.27, 1) scale = Vector3(0.41, 0.085, 1)
mesh = SubResource("ScreenQuadMesh") mesh = SubResource("ScreenQuadMesh")
material_override = SubResource("ScreenMaterial") material_override = SubResource("ScreenMaterial")
[node name="IntegrityLabel" type="Label3D" parent="Dashboard"] [node name="IntegrityLabel" type="Label3D" parent="Dashboard"]
unique_name_in_owner = true unique_name_in_owner = true
position = Vector3(0.5, 0.03, 0.108) position = Vector3(0.5, -0.075, 0.108)
pixel_size = 0.00115 pixel_size = 0.00082
font_size = 20 font_size = 14
outline_size = 2 outline_size = 2
text = "COQUE\n— / —\n\nPRESSION\n— / — bar" text = "COQUE — % · — bar\nLIMITE — bar"
modulate = Color(0.45, 0.89, 0.9, 1) modulate = Color(0.45, 0.89, 0.9, 1)
[node name="ReturnLabel" type="Label3D" parent="Dashboard"] [node name="ReturnLabel" type="Label3D" parent="Dashboard"]
unique_name_in_owner = true unique_name_in_owner = true
position = Vector3(0.32, 0.205, 0.108) position = Vector3(0.61, 0.245, 0.17)
pixel_size = 0.00082 pixel_size = 0.00062
font_size = 15 font_size = 12
outline_size = 2 outline_size = 2
text = "RETOUR · INCONNU" text = "RETOUR · INCONNU"
modulate = Color(1, 0.75, 0.2, 1) modulate = Color(1, 0.75, 0.2, 1)
[node name="StatusLabel" type="Label3D" parent="Dashboard"] [node name="StatusLabel" type="Label3D" parent="Dashboard"]
unique_name_in_owner = true unique_name_in_owner = true
position = Vector3(-0.34, 0.205, 0.108) position = Vector3(-0.61, 0.245, 0.17)
pixel_size = 0.00082 pixel_size = 0.00062
font_size = 15 font_size = 12
outline_size = 2 outline_size = 2
text = "SYSTÈMES · NORMAL" text = "SYSTÈMES · NORMAL"
modulate = Color(0.45, 0.89, 0.9, 1) modulate = Color(0.45, 0.89, 0.9, 1)
@@ -413,16 +413,16 @@ text = "SONAR\nMODULE EN ATTENTE"
modulate = Color(0.34, 0.6, 0.6, 1) modulate = Color(0.34, 0.6, 0.6, 1)
[node name="EmergencyDial" type="MeshInstance3D" parent="."] [node name="EmergencyDial" type="MeshInstance3D" parent="."]
position = Vector3(-0.6, 0.39, -1.15) position = Vector3(-0.7, 0.32, -1.15)
scale = Vector3(0.38, 0.38, 0.38) scale = Vector3(0.18, 0.18, 0.18)
rotation_degrees = Vector3(90, 0, 0) rotation_degrees = Vector3(90, 0, 0)
mesh = SubResource("DialMesh") mesh = SubResource("DialMesh")
material_override = SubResource("RedMaterial") material_override = SubResource("RedMaterial")
[node name="EmergencyLabel" type="Label3D" parent="."] [node name="EmergencyLabel" type="Label3D" parent="."]
position = Vector3(-0.6, 0.3, -1.125) position = Vector3(-0.7, 0.275, -1.125)
pixel_size = 0.0009 pixel_size = 0.00072
font_size = 15 font_size = 12
outline_size = 2 outline_size = 2
text = "ÉJECTION · X" text = "ÉJECTION · X"
modulate = Color(1, 0.48, 0.38, 1) modulate = Color(1, 0.48, 0.38, 1)
@@ -11,6 +11,7 @@ const GAUGE_FACE_TEXTURE_PATH := (
var painted_steel: Material var painted_steel: Material
var dark_steel: Material var dark_steel: Material
var overhead_steel: StandardMaterial3D var overhead_steel: StandardMaterial3D
var brushed_steel: StandardMaterial3D
var brass: Material var brass: Material
var copper: Material var copper: Material
var rubber: Material var rubber: Material
@@ -43,6 +44,7 @@ func _init() -> void:
0.56, 0.56,
Vector3(1.6, 1.6, 1.6) Vector3(1.6, 1.6, 1.6)
) )
brushed_steel = _plain_material(Color(0.27, 0.30, 0.29), 0.82, 0.30)
brass = _weathered_material( brass = _weathered_material(
Color(0.28, 0.18, 0.045), Color(0.28, 0.18, 0.045),
Color(0.08, 0.16, 0.13), Color(0.08, 0.16, 0.13),
@@ -8,9 +8,10 @@ const CockpitMeshFactory = preload(
"res://game/presentation/cockpit/cockpit_mesh_factory.gd" "res://game/presentation/cockpit/cockpit_mesh_factory.gd"
) )
const PANEL_COUNT := 12 const PANEL_COUNT := 1
const ANGULAR_STEPS := 4 const FASTENER_COUNT := 16
const RADIAL_STEPS := 3 const ANGULAR_STEPS := 64
const RADIAL_STEPS := 4
const INNER_RADIUS := 0.72 const INNER_RADIUS := 0.72
const OUTER_RADIUS := 1.11 const OUTER_RADIUS := 1.11
@@ -21,6 +22,7 @@ var _panel_count := 0
func _ready() -> void: func _ready() -> void:
_materials = CockpitMaterialPalette.new() _materials = CockpitMaterialPalette.new()
_hide_rectangular_whitebox() _hide_rectangular_whitebox()
_style_existing_frame()
_build_curved_panels() _build_curved_panels()
_build_outer_rib() _build_outer_rib()
_build_fasteners() _build_fasteners()
@@ -45,12 +47,20 @@ func _hide_rectangular_whitebox() -> void:
whitebox.visible = false whitebox.visible = false
func _style_existing_frame() -> void:
var frame := get_parent().get_node_or_null("WindowFrame") as MeshInstance3D
if frame != null:
frame.material_override = _materials.brushed_steel
for child: Node in get_parent().get_children():
if child is MeshInstance3D and child.name.begins_with("Bolt"):
(child as MeshInstance3D).material_override = _materials.dark_steel
func _build_curved_panels() -> void: func _build_curved_panels() -> void:
var panel_angle := TAU / float(PANEL_COUNT) var panel_angle := TAU / float(PANEL_COUNT)
var seam_half_width := deg_to_rad(0.22)
for panel_index in PANEL_COUNT: for panel_index in PANEL_COUNT:
var start_angle := panel_index * panel_angle + seam_half_width var start_angle := panel_index * panel_angle
var end_angle := (panel_index + 1) * panel_angle - seam_half_width var end_angle := (panel_index + 1) * panel_angle
var panel := MeshInstance3D.new() var panel := MeshInstance3D.new()
panel.name = "PressurePanel%02d" % (panel_index + 1) panel.name = "PressurePanel%02d" % (panel_index + 1)
panel.mesh = _create_curved_panel_mesh(start_angle, end_angle) panel.mesh = _create_curved_panel_mesh(start_angle, end_angle)
@@ -128,11 +138,23 @@ func _build_outer_rib() -> void:
rib.rotation_degrees.x = 90.0 rib.rotation_degrees.x = 90.0
rib.position.z = 0.025 rib.position.z = 0.025
add_child(rib) add_child(rib)
var inner_rib := MeshInstance3D.new()
inner_rib.name = "InnerPressureRib"
var inner_torus := TorusMesh.new()
inner_torus.inner_radius = 0.695
inner_torus.outer_radius = 0.755
inner_torus.rings = 64
inner_torus.ring_segments = 12
inner_rib.mesh = inner_torus
inner_rib.material_override = _materials.brushed_steel
inner_rib.rotation_degrees.x = 90.0
inner_rib.position.z = 0.075
add_child(inner_rib)
func _build_fasteners() -> void: func _build_fasteners() -> void:
for fastener_index in PANEL_COUNT: for fastener_index in FASTENER_COUNT:
var angle := (fastener_index + 0.5) * TAU / float(PANEL_COUNT) var angle := (fastener_index + 0.5) * TAU / float(FASTENER_COUNT)
CockpitMeshFactory.add_cylinder( CockpitMeshFactory.add_cylinder(
"OuterFastener", "OuterFastener",
self, self,
@@ -19,7 +19,7 @@ const ProductionInputAdapter = preload(
"res://game/infrastructure/input/production_input_adapter.gd" "res://game/infrastructure/input/production_input_adapter.gd"
) )
const TEST_COUNT := 64 const TEST_COUNT := 65
var _failures: Array[String] = [] var _failures: Array[String] = []
@@ -131,8 +131,9 @@ func _test_vehicle_slice(composition: VerticalSliceRoot) -> void:
_expect(detailing.textures_are_loaded(), "cockpit loads its overhead and analog gauge textures") _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.gauges_are_dashboard_mounted(), "analog gauges are mounted on the dashboard")
_expect(detailing.dashboard_control_count() >= 8, "dashboard exposes physical auxiliary controls") _expect(detailing.dashboard_control_count() >= 8, "dashboard exposes physical auxiliary controls")
_expect(pressure_bulkhead.panel_count() == 12, "porthole bulkhead uses twelve curved pressure panels") _expect(pressure_bulkhead.panel_count() == 1, "porthole bulkhead uses one continuous curved shell")
_expect(pressure_bulkhead.rectangular_whitebox_is_hidden(), "porthole rectangular whitebox is hidden") _expect(pressure_bulkhead.rectangular_whitebox_is_hidden(), "porthole rectangular whitebox is hidden")
_expect(analog_gauges.gauge_count() == 4, "dashboard exposes four primary analog instruments")
_expect(analog_gauges.indicator_count() == 3, "instrument binnacle exposes three inset pilot lights") _expect(analog_gauges.indicator_count() == 3, "instrument binnacle exposes three inset pilot lights")
_expect(analog_gauges.active_indicator_count() == 1, "exactly one pilot light reflects the alert state") _expect(analog_gauges.active_indicator_count() == 1, "exactly one pilot light reflects the alert state")
_expect("kWh" in instruments.resources_text() and "kW" in instruments.resources_text(), "battery instrument has exact units") _expect("kWh" in instruments.resources_text() and "kW" in instruments.resources_text(), "battery instrument has exact units")