Files
Ransom-s-wake/game/presentation/cockpit/cockpit_analog_gauges.gd

266 lines
6.8 KiB
GDScript

class_name CockpitAnalogGauges
extends Node3D
const CockpitMaterialPalette = preload("res://game/presentation/cockpit/cockpit_material_palette.gd")
const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh_factory.gd")
const DiveAlertLevel = preload("res://game/domain/dive/dive_alert_level.gd")
var _materials: CockpitMaterialPalette
var _oxygen_needle: Node3D
var _battery_needle: Node3D
var _hull_needle: Node3D
var _depth_needle: Node3D
var _indicator_materials: Array[StandardMaterial3D] = []
var _active_indicator_count := 0
func _init(materials: CockpitMaterialPalette) -> void:
_materials = materials
name = "AnalogGauges"
_build_instrument_cluster()
_build_indicator_bank()
_oxygen_needle = _add_gauge(
"OxygenGauge",
Vector3(-0.52, 0.12, 0.145),
0.94,
_materials.oxygen_gauge_face
)
_battery_needle = _add_gauge(
"BatteryGauge",
Vector3(-0.22, 0.12, 0.145),
0.94,
_materials.battery_gauge_face
)
_hull_needle = _add_gauge(
"HullGauge",
Vector3(0.09, 0.12, 0.145),
0.86,
_materials.hull_gauge_face
)
_depth_needle = _add_gauge(
"DepthGauge",
Vector3(0.47, 0.12, 0.145),
1.12,
_materials.depth_gauge_face
)
func present(
oxygen_ratio: float,
battery_ratio: float,
hull_ratio: float,
depth_ratio: float,
alert_level: DiveAlertLevel.Value
) -> void:
_set_needle_ratio(_oxygen_needle, oxygen_ratio)
_set_needle_ratio(_battery_needle, battery_ratio)
_set_needle_ratio(_hull_needle, hull_ratio)
_set_needle_ratio(_depth_needle, depth_ratio)
_update_indicator_bank(alert_level)
func battery_needle_degrees() -> float:
return 0.0 if _battery_needle == null else _battery_needle.rotation_degrees.z
func indicator_count() -> int:
return _indicator_materials.size()
func gauge_count() -> int:
return 4
func active_indicator_count() -> int:
return _active_indicator_count
func _build_instrument_cluster() -> void:
CockpitMeshFactory.add_box(
"InstrumentClusterHousing",
self,
Vector3(-0.04, 0.105, 0.095),
Vector3(1.42, 0.31, 0.105),
_materials.overhead_steel
)
CockpitMeshFactory.add_box(
"InstrumentClusterFoot",
self,
Vector3(-0.04, -0.025, 0.075),
Vector3(1.48, 0.040, 0.14),
_materials.dark_steel
)
func _build_indicator_bank() -> void:
var root := Node3D.new()
root.name = "IndicatorBank"
add_child(root)
var colors: Array[Color] = [
Color(0.08, 0.72, 0.38),
Color(1.0, 0.46, 0.035),
Color(0.92, 0.035, 0.018),
]
var captions: Array[String] = ["SYS", "ATTN", "ALRM"]
for indicator_index in colors.size():
var y := 0.165 - indicator_index * 0.050
CockpitMeshFactory.add_cylinder(
"%sBezel" % captions[indicator_index],
root,
Vector3(0.68, y, 0.156),
0.016,
0.012,
_materials.brass,
Vector3(90.0, 0.0, 0.0)
)
var material := _indicator_material(colors[indicator_index])
_indicator_materials.append(material)
CockpitMeshFactory.add_cylinder(
"%sLens" % captions[indicator_index],
root,
Vector3(0.68, y, 0.165),
0.009,
0.008,
material,
Vector3(90.0, 0.0, 0.0)
)
var label := Label3D.new()
label.name = "%sLabel" % captions[indicator_index]
label.text = captions[indicator_index]
label.font_size = 8
label.pixel_size = 0.00042
label.modulate = Color(0.70, 0.67, 0.56)
label.position = Vector3(0.71, y, 0.168)
root.add_child(label)
func _indicator_material(color: Color) -> StandardMaterial3D:
var material := StandardMaterial3D.new()
material.albedo_color = color * 0.12
material.metallic = 0.05
material.roughness = 0.16
material.emission_enabled = true
material.emission = color
material.emission_energy_multiplier = 0.04
return material
func _update_indicator_bank(alert_level: DiveAlertLevel.Value) -> void:
var active_index := 0
if alert_level >= DiveAlertLevel.Value.CRITICAL:
active_index = 2
elif alert_level >= DiveAlertLevel.Value.ATTENTION:
active_index = 1
for indicator_index in _indicator_materials.size():
_indicator_materials[indicator_index].emission_energy_multiplier = (
2.8 if indicator_index == active_index else 0.04
)
_active_indicator_count = 1
func _add_gauge(
gauge_name: String,
position: Vector3,
gauge_scale: float,
face_material: Material
) -> Node3D:
var gauge := Node3D.new()
gauge.name = gauge_name
gauge.position = position
gauge.scale = Vector3(gauge_scale, gauge_scale, gauge_scale)
add_child(gauge)
CockpitMeshFactory.add_box(
"MountingPlate",
gauge,
Vector3(0.0, 0.0, -0.025),
Vector3(0.225, 0.225, 0.055),
_materials.overhead_steel
)
for screw_position: Vector2 in [
Vector2(-0.086, -0.086),
Vector2(0.086, -0.086),
Vector2(-0.086, 0.086),
Vector2(0.086, 0.086),
]:
CockpitMeshFactory.add_cylinder(
"MountingScrew",
gauge,
Vector3(screw_position.x, screw_position.y, 0.008),
0.009,
0.012,
_materials.brass,
Vector3(90.0, 0.0, 0.0)
)
_add_bezel(gauge, 0.108, 0.046, _materials.dark_steel)
_add_bezel(gauge, 0.099, 0.041, _materials.brushed_steel)
var face := MeshInstance3D.new()
var printed_face := QuadMesh.new()
printed_face.size = Vector2(0.178, 0.178)
face.mesh = printed_face
face.position.z = 0.031
face.material_override = face_material
gauge.add_child(face)
var needle_root := Node3D.new()
needle_root.name = "Needle"
needle_root.position.z = 0.038
gauge.add_child(needle_root)
CockpitMeshFactory.add_box(
"NeedleBlade",
needle_root,
Vector3(0.0, 0.030, 0.0),
Vector3(0.006, 0.060, 0.006),
_materials.dark_steel
)
CockpitMeshFactory.add_box(
"NeedleTip",
needle_root,
Vector3(0.0, 0.061, 0.001),
Vector3(0.004, 0.024, 0.006),
_materials.needle_paint
)
CockpitMeshFactory.add_box(
"NeedleCounterweight",
needle_root,
Vector3(0.0, -0.014, -0.001),
Vector3(0.013, 0.030, 0.007),
_materials.dark_steel
)
CockpitMeshFactory.add_cylinder(
"NeedleHub",
needle_root,
Vector3.ZERO,
0.018,
0.012,
_materials.dark_steel,
Vector3(90.0, 0.0, 0.0)
)
var glass := MeshInstance3D.new()
glass.name = "GaugeGlass"
var glass_mesh := CylinderMesh.new()
glass_mesh.top_radius = 0.089
glass_mesh.bottom_radius = 0.089
glass_mesh.height = 0.004
glass_mesh.radial_segments = 40
glass.mesh = glass_mesh
glass.material_override = _materials.gauge_glass
glass.rotation_degrees.x = 90.0
glass.position.z = 0.050
glass.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
gauge.add_child(glass)
return needle_root
func _add_bezel(
gauge: Node3D,
radius: float,
height: float,
material: Material
) -> void:
var bezel := MeshInstance3D.new()
var bezel_mesh := CylinderMesh.new()
bezel_mesh.top_radius = radius
bezel_mesh.bottom_radius = radius
bezel_mesh.height = height
bezel_mesh.radial_segments = 48
bezel.mesh = bezel_mesh
bezel.material_override = material
bezel.rotation_degrees.x = 90.0
gauge.add_child(bezel)
func _set_needle_ratio(needle: Node3D, ratio: float) -> void:
if needle != null:
needle.rotation_degrees.z = lerpf(125.0, -125.0, clampf(ratio, 0.0, 1.0))