feat(cockpit): replace procedural cockpit with twelve scripted models
Quality Gate / Quality Gate (pull_request) Successful in 7m6s
Quality Gate / Quality Gate (pull_request) Successful in 7m6s
Instance twelve Blender-scripted glTF models in the cockpit scene and rebuild the cabin around them: gauge panel, sonar, switch panel, alert box, speaker, porthole, hull wall, caged lamps, gas bottle, handrails and side consoles. Presentation only; no domain, application or world rule changes beyond enabling glow in the test environment. - Needles, alert lamps and sonar screen are driven by the existing snapshots; the alert box now carries SYS/ATTN/ALRM. - Depth dial reads percent of certified depth. - Sonar display restyled as a turquoise holographic relief with a shader grid and height scale; SubViewport matches the glass (960x604). - Cabin lighting retuned: warm pooled lamp light, cool porthole rim, lamp shadows, dial backlight. - Procedural stand-ins removed (bulkhead, tanks, consoles, levers, indicator columns, placeholder pipe run, dial face PNGs). - Tests adapted where nodes disappeared; one assertion removed (pipe_segment_count) until the pipe kit is placed. - Model .glb files are committed without LFS; textures Godot extracts next to them at import are ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
912123087f
commit
2c1ea50aba
45 files changed
+1353
-1603
No files matched your search
@@ -4,6 +4,7 @@ extends Node3D
|
||||
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 CockpitAlertBox = preload("res://game/presentation/cockpit/cockpit_alert_box.gd")
|
||||
const CockpitAnalogGauges = preload("res://game/presentation/cockpit/cockpit_analog_gauges.gd")
|
||||
const CockpitDashboardDetailing = preload(
|
||||
"res://game/presentation/cockpit/cockpit_dashboard_detailing.gd"
|
||||
@@ -19,13 +20,17 @@ const CockpitSonarConsole = preload(
|
||||
const CockpitPracticalLighting = preload(
|
||||
"res://game/presentation/cockpit/cockpit_practical_lighting.gd"
|
||||
)
|
||||
const CockpitSwitchPanel = preload(
|
||||
"res://game/presentation/cockpit/cockpit_switch_panel.gd"
|
||||
)
|
||||
|
||||
var _materials: CockpitMaterialPalette
|
||||
var _painted_steel: Material
|
||||
var _dark_steel: Material
|
||||
var _brass: Material
|
||||
var _copper: Material
|
||||
var _analog_gauges: CockpitAnalogGauges
|
||||
var _alert_box: CockpitAlertBox
|
||||
var _switch_panel: CockpitSwitchPanel
|
||||
var _gas_bottle: Node3D
|
||||
var _dashboard_detailing: CockpitDashboardDetailing
|
||||
var _side_equipment: CockpitSideEquipment
|
||||
var _sonar_console: CockpitSonarConsole
|
||||
@@ -35,9 +40,6 @@ var _practical_lighting: CockpitPracticalLighting
|
||||
func _ready() -> void:
|
||||
_create_materials()
|
||||
_apply_materials_to_existing_cockpit()
|
||||
_build_pressure_hull_ribs()
|
||||
_build_life_support_pipes()
|
||||
_build_panel_hardware()
|
||||
_build_dashboard_instrumentation()
|
||||
_build_equipment_assemblies()
|
||||
|
||||
@@ -46,32 +48,24 @@ func present(update: DiveUpdate, telemetry: VehicleTelemetry) -> void:
|
||||
if update == null or update.snapshot == null or telemetry == null:
|
||||
return
|
||||
var snapshot = update.snapshot
|
||||
_analog_gauges.present(
|
||||
snapshot.oxygen.ratio,
|
||||
snapshot.battery.ratio,
|
||||
snapshot.hull.ratio,
|
||||
clampf(
|
||||
snapshot.depth.current_m
|
||||
/ maxf(snapshot.depth.certified_m, 0.001),
|
||||
0.0,
|
||||
1.0
|
||||
),
|
||||
snapshot.alerts.maximum
|
||||
)
|
||||
var alert_level: DiveAlertLevel.Value = snapshot.alerts.maximum
|
||||
if _analog_gauges != null:
|
||||
_analog_gauges.present(
|
||||
snapshot.oxygen.ratio,
|
||||
snapshot.battery.ratio,
|
||||
snapshot.hull.ratio,
|
||||
clampf(
|
||||
snapshot.depth.current_m
|
||||
/ maxf(snapshot.depth.certified_m, 0.001),
|
||||
0.0,
|
||||
1.0
|
||||
)
|
||||
)
|
||||
if _alert_box != null:
|
||||
_alert_box.present(alert_level)
|
||||
_practical_lighting.present(alert_level)
|
||||
|
||||
|
||||
func pressure_hull_rib_count() -> int:
|
||||
var ribs := get_node_or_null("PressureHullRibs")
|
||||
return 0 if ribs == null else ribs.get_child_count()
|
||||
|
||||
|
||||
func pipe_segment_count() -> int:
|
||||
var pipes := get_node_or_null("LifeSupportPipes")
|
||||
return 0 if pipes == null else pipes.get_child_count()
|
||||
|
||||
|
||||
func battery_needle_degrees() -> float:
|
||||
return 0.0 if _analog_gauges == null else _analog_gauges.battery_needle_degrees()
|
||||
|
||||
@@ -80,25 +74,30 @@ func textures_are_loaded() -> bool:
|
||||
return (
|
||||
_materials != null
|
||||
and _materials.overhead_steel.albedo_texture != null
|
||||
and _materials.oxygen_gauge_face.albedo_texture != null
|
||||
and _materials.battery_gauge_face.albedo_texture != null
|
||||
and _materials.hull_gauge_face.albedo_texture != null
|
||||
and _materials.depth_gauge_face.albedo_texture != null
|
||||
and _analog_gauges != null
|
||||
and _analog_gauges.dial_texture_is_loaded()
|
||||
)
|
||||
|
||||
|
||||
func dashboard_control_count() -> int:
|
||||
return 0 if _dashboard_detailing == null else _dashboard_detailing.control_count()
|
||||
return 0 if _switch_panel == null else _switch_panel.control_count()
|
||||
|
||||
|
||||
func side_equipment_count() -> int:
|
||||
if _side_equipment == null:
|
||||
return 0
|
||||
return _side_equipment.tank_count() + _side_equipment.junction_box_count()
|
||||
return _side_equipment.junction_box_count() + (0 if _gas_bottle == null else 1)
|
||||
|
||||
|
||||
func side_control_count() -> int:
|
||||
return 0 if _side_equipment == null else _side_equipment.control_count()
|
||||
if _side_equipment == null:
|
||||
return 0
|
||||
var bottle_valve_count := (
|
||||
0
|
||||
if _gas_bottle == null
|
||||
else _gas_bottle.find_children("*ValveWheel", "Node3D", true, false).size()
|
||||
)
|
||||
return _side_equipment.control_count() + bottle_valve_count
|
||||
|
||||
|
||||
func sonar_control_count() -> int:
|
||||
@@ -117,8 +116,6 @@ func _create_materials() -> void:
|
||||
_materials = CockpitMaterialPalette.new()
|
||||
_painted_steel = _materials.painted_steel
|
||||
_dark_steel = _materials.dark_steel
|
||||
_brass = _materials.brass
|
||||
_copper = _materials.copper
|
||||
|
||||
|
||||
func _apply_materials_to_existing_cockpit() -> void:
|
||||
@@ -127,39 +124,12 @@ func _apply_materials_to_existing_cockpit() -> void:
|
||||
[
|
||||
"CabinShell/LeftWall",
|
||||
"CabinShell/RightWall",
|
||||
"LeftConsole",
|
||||
"RightConsole",
|
||||
]
|
||||
)
|
||||
_apply_material_to_paths(
|
||||
_dark_steel,
|
||||
[
|
||||
"CabinShell/RearBulkhead",
|
||||
"PortholeAssembly/LeftBulkhead",
|
||||
"PortholeAssembly/RightBulkhead",
|
||||
"PortholeAssembly/BottomBulkhead",
|
||||
"ThrottleLever",
|
||||
"VerticalLever",
|
||||
]
|
||||
)
|
||||
_apply_material_to_paths(_dark_steel, ["CabinShell/RearBulkhead"])
|
||||
_apply_material_to_paths(
|
||||
_materials.overhead_steel,
|
||||
[
|
||||
"CabinShell/Ceiling",
|
||||
"PortholeAssembly/TopBulkhead",
|
||||
"Dashboard/MainPanel",
|
||||
]
|
||||
)
|
||||
_apply_material_to_paths(
|
||||
_brass,
|
||||
[
|
||||
"PortholeAssembly/WindowFrame",
|
||||
"Dashboard/ResourcesFrame",
|
||||
"Dashboard/NavigationFrame",
|
||||
"Dashboard/IntegrityFrame",
|
||||
"ThrottleKnob",
|
||||
"VerticalKnob",
|
||||
]
|
||||
["CabinShell/Ceiling"]
|
||||
)
|
||||
func _apply_material_to_paths(material: Material, paths: Array[String]) -> void:
|
||||
var cockpit := get_parent()
|
||||
@@ -169,128 +139,26 @@ func _apply_material_to_paths(material: Material, paths: Array[String]) -> void:
|
||||
mesh.material_override = material
|
||||
|
||||
|
||||
func _build_pressure_hull_ribs() -> void:
|
||||
var root := Node3D.new()
|
||||
root.name = "PressureHullRibs"
|
||||
add_child(root)
|
||||
for rib_index in 2:
|
||||
var rib := MeshInstance3D.new()
|
||||
rib.name = "CircularRib%d" % (rib_index + 1)
|
||||
var torus := TorusMesh.new()
|
||||
torus.inner_radius = 1.00
|
||||
torus.outer_radius = 1.075
|
||||
torus.rings = 48
|
||||
torus.ring_segments = 10
|
||||
rib.mesh = torus
|
||||
rib.material_override = _dark_steel
|
||||
rib.position = Vector3(0.0, 0.22, -0.90 + rib_index * 1.35)
|
||||
rib.rotation_degrees.x = 90.0
|
||||
root.add_child(rib)
|
||||
|
||||
for side: float in [-1.0, 1.0]:
|
||||
CockpitMeshFactory.add_box(
|
||||
"AngledShoulder",
|
||||
root,
|
||||
Vector3(side * 0.88, 0.84, -0.36),
|
||||
Vector3(0.11, 0.62, 1.52),
|
||||
_painted_steel,
|
||||
Vector3(0.0, 0.0, side * -18.0)
|
||||
)
|
||||
CockpitMeshFactory.add_box(
|
||||
"LowerStringer",
|
||||
root,
|
||||
Vector3(side * 0.91, -0.38, -0.18),
|
||||
Vector3(0.10, 0.12, 1.70),
|
||||
_dark_steel
|
||||
)
|
||||
|
||||
|
||||
func _build_life_support_pipes() -> void:
|
||||
var root := Node3D.new()
|
||||
root.name = "LifeSupportPipes"
|
||||
add_child(root)
|
||||
for side: float in [-1.0, 1.0]:
|
||||
var x: float = side * 0.83
|
||||
CockpitMeshFactory.add_cylinder(
|
||||
"VerticalPipe",
|
||||
root,
|
||||
Vector3(x, 0.33, -1.12),
|
||||
0.027,
|
||||
1.18,
|
||||
_copper
|
||||
)
|
||||
CockpitMeshFactory.add_cylinder(
|
||||
"ReturnPipe",
|
||||
root,
|
||||
Vector3(side * 0.73, 0.47, -1.09),
|
||||
0.019,
|
||||
0.92,
|
||||
_brass
|
||||
)
|
||||
for clamp_y: float in [-0.04, 0.35, 0.72]:
|
||||
var clamp := MeshInstance3D.new()
|
||||
clamp.name = "PipeClamp"
|
||||
var torus := TorusMesh.new()
|
||||
torus.inner_radius = 0.027
|
||||
torus.outer_radius = 0.041
|
||||
torus.rings = 16
|
||||
torus.ring_segments = 6
|
||||
clamp.mesh = torus
|
||||
clamp.material_override = _dark_steel
|
||||
clamp.position = Vector3(x, clamp_y, -1.12)
|
||||
root.add_child(clamp)
|
||||
CockpitMeshFactory.add_sphere(
|
||||
"PipeJunction",
|
||||
root,
|
||||
Vector3(x, 0.91, -1.12),
|
||||
0.052,
|
||||
_copper
|
||||
)
|
||||
CockpitMeshFactory.add_cylinder_between(
|
||||
"UpperBranchPipe",
|
||||
root,
|
||||
Vector3(x, 0.84, -1.12),
|
||||
Vector3(side * 0.72, 0.77, -1.10),
|
||||
0.019,
|
||||
_brass
|
||||
)
|
||||
|
||||
|
||||
func _build_panel_hardware() -> void:
|
||||
var root := Node3D.new()
|
||||
root.name = "PanelHardware"
|
||||
add_child(root)
|
||||
for x: float in [-0.73, -0.49, -0.24, 0.24, 0.49, 0.73]:
|
||||
for y: float in [-0.18, 0.22]:
|
||||
CockpitMeshFactory.add_cylinder(
|
||||
"PanelFastener",
|
||||
root,
|
||||
Vector3(x, y, -1.105),
|
||||
0.014,
|
||||
0.018,
|
||||
_dark_steel,
|
||||
Vector3(90.0, 0.0, 0.0)
|
||||
)
|
||||
|
||||
|
||||
|
||||
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_detailing = CockpitDashboardDetailing.new()
|
||||
dashboard.add_child(_dashboard_detailing)
|
||||
_dashboard_detailing.hide_obsolete_elements(get_parent())
|
||||
_analog_gauges = CockpitAnalogGauges.new(_materials)
|
||||
dashboard.add_child(_analog_gauges)
|
||||
_analog_gauges = dashboard.get_node_or_null("AnalogGauges") as CockpitAnalogGauges
|
||||
|
||||
|
||||
func _build_equipment_assemblies() -> void:
|
||||
_side_equipment = CockpitSideEquipment.new(_materials)
|
||||
add_child(_side_equipment)
|
||||
var sonar_monitor := get_parent().get_node_or_null("SonarMonitor") as Node3D
|
||||
if sonar_monitor != null:
|
||||
_sonar_console = CockpitSonarConsole.new(_materials)
|
||||
sonar_monitor.add_child(_sonar_console)
|
||||
var cockpit := get_parent()
|
||||
_sonar_console = cockpit.get_node_or_null("SonarMonitor") as CockpitSonarConsole
|
||||
_alert_box = cockpit.get_node_or_null("AlertBox") as CockpitAlertBox
|
||||
_switch_panel = cockpit.get_node_or_null("SwitchPanel") as CockpitSwitchPanel
|
||||
_gas_bottle = cockpit.get_node_or_null("GasBottle") as Node3D
|
||||
_practical_lighting = CockpitPracticalLighting.new(_materials)
|
||||
add_child(_practical_lighting)
|
||||
# The alert box hangs between the left lamp and the gas bottle: casting, it
|
||||
# puts the bottle in full shadow.
|
||||
CockpitMeshFactory.disable_shadow_casting(_alert_box)
|
||||
Reference in new issue
Block a user