Quality Gate / Quality Gate (pull_request) Successful in 9m4s
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>
102 lines
3.2 KiB
GDScript
102 lines
3.2 KiB
GDScript
class_name CockpitAnalogGauges
|
|
extends Node3D
|
|
|
|
## Drives the imported gauge panel model: four needles and its six pilot lights.
|
|
## The model scene is instanced by `cockpit_interior.tscn`; this script only
|
|
## rotates needles and sets emission, it never rebuilds geometry.
|
|
|
|
const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh_factory.gd")
|
|
|
|
## Printed dial sweep: ratio 0 points lower-left, ratio 1 lower-right, clockwise.
|
|
const NEEDLE_DEGREES_AT_ZERO := 120.0
|
|
const NEEDLE_DEGREES_AT_FULL := -120.0
|
|
## The snapshot carries no per-instrument lamp state, so the panel pilot lights
|
|
## stay dark; the alert level is reported by `CockpitAlertBox`.
|
|
const PILOT_LIGHT_REST_ENERGY := 0.0
|
|
## Scales the dial backlight baked in the model (1.0 = as exported), so the
|
|
## paper reads as lit ivory without outshining the cabin's warm lamps.
|
|
const DIAL_BACKLIGHT_ENERGY := 0.7
|
|
|
|
const NEEDLE_NAMES: Array[String] = [
|
|
"Needle_Oxygen",
|
|
"Needle_Battery",
|
|
"Needle_Hull",
|
|
"Needle_Depth",
|
|
]
|
|
|
|
var _needles: Dictionary[String, Node3D] = {}
|
|
var _dials: MeshInstance3D
|
|
var _pilot_light_materials: Array[BaseMaterial3D] = []
|
|
|
|
|
|
func _ready() -> void:
|
|
for needle_name: String in NEEDLE_NAMES:
|
|
var needle := find_child(needle_name, true, false) as Node3D
|
|
if needle == null:
|
|
push_error("Gauge panel model has no %s node" % needle_name)
|
|
continue
|
|
_needles[needle_name] = needle
|
|
_dials = find_child("GaugeDials", true, false) as MeshInstance3D
|
|
var dial_material := CockpitMeshFactory.own_surface_material(_dials)
|
|
if dial_material != null:
|
|
dial_material.emission_energy_multiplier = DIAL_BACKLIGHT_ENERGY
|
|
for light: Node in find_children("Light_*", "MeshInstance3D", true, false):
|
|
var material := CockpitMeshFactory.own_surface_material(light as MeshInstance3D)
|
|
if material != null:
|
|
material.emission_energy_multiplier = PILOT_LIGHT_REST_ENERGY
|
|
_pilot_light_materials.append(material)
|
|
|
|
|
|
func present(
|
|
oxygen_ratio: float,
|
|
battery_ratio: float,
|
|
hull_ratio: float,
|
|
depth_ratio: float
|
|
) -> void:
|
|
_set_needle_ratio("Needle_Oxygen", oxygen_ratio)
|
|
_set_needle_ratio("Needle_Battery", battery_ratio)
|
|
_set_needle_ratio("Needle_Hull", hull_ratio)
|
|
_set_needle_ratio("Needle_Depth", depth_ratio)
|
|
|
|
|
|
func gauge_count() -> int:
|
|
return _needles.size()
|
|
|
|
|
|
func pilot_light_count() -> int:
|
|
return _pilot_light_materials.size()
|
|
|
|
|
|
func lit_pilot_light_count() -> int:
|
|
var count := 0
|
|
for material: BaseMaterial3D in _pilot_light_materials:
|
|
if material.emission_energy_multiplier > 0.0:
|
|
count += 1
|
|
return count
|
|
|
|
|
|
func needle_degrees(needle_name: String) -> float:
|
|
var needle: Node3D = _needles.get(needle_name)
|
|
return 0.0 if needle == null else needle.rotation_degrees.z
|
|
|
|
|
|
func battery_needle_degrees() -> float:
|
|
return needle_degrees("Needle_Battery")
|
|
|
|
|
|
func dial_texture_is_loaded() -> bool:
|
|
if _dials == null or _dials.mesh == null or _dials.mesh.get_surface_count() == 0:
|
|
return false
|
|
var material := _dials.mesh.surface_get_material(0) as BaseMaterial3D
|
|
return material != null and material.albedo_texture != null
|
|
|
|
|
|
func _set_needle_ratio(needle_name: String, ratio: float) -> void:
|
|
var needle: Node3D = _needles.get(needle_name)
|
|
if needle != null:
|
|
needle.rotation_degrees.z = lerpf(
|
|
NEEDLE_DEGREES_AT_ZERO,
|
|
NEEDLE_DEGREES_AT_FULL,
|
|
clampf(ratio, 0.0, 1.0)
|
|
)
|