mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
04691aaa48
Lands the non-networked Phase 0 tasks from multiplayer-todo.md (ship/camera/ arena refactors, sim constants, background FPS handling) plus a first pass at exposing graphics/performance settings (presets, resolution scaling, vsync, FPS cap, perf overlay) and a GPU profiling harness for the real-hardware follow-up in task 0.15b.
109 lines
4.2 KiB
GDScript
109 lines
4.2 KiB
GDScript
class_name HudAttitudeIndicator
|
|
extends HudInstrument
|
|
|
|
# Aircraft-style attitude indicator (artificial horizon): the sky/ground disc
|
|
# rolls and the pitch ladder scrolls behind a fixed ship symbol, so pitch and
|
|
# roll are readable at a glance. Pure _draw code — no textures. A dumb display:
|
|
# HUDController pushes values in via set_attitude; it never reads the ship.
|
|
|
|
const SKY_COLOR := Color(0.10, 0.24, 0.42, 0.9)
|
|
const GROUND_COLOR := Color(0.22, 0.15, 0.10, 0.9)
|
|
const LINE_COLOR := Color(0.85, 0.92, 1.0, 0.9)
|
|
const SHIP_SYMBOL_COLOR := Color(1.0, 0.8, 0.2)
|
|
const RING_COLOR := Color(0.5, 0.85, 1.0, 0.7)
|
|
|
|
# Instrument scale: degrees of pitch visible from centre to rim.
|
|
const PITCH_RANGE := 45.0
|
|
|
|
var _target_pitch := 0.0
|
|
var _target_roll := 0.0
|
|
var _pitch := 0.0
|
|
var _roll := 0.0
|
|
|
|
|
|
func set_attitude(pitch_deg: float, roll_deg: float) -> void:
|
|
_target_pitch = pitch_deg
|
|
_target_roll = roll_deg
|
|
|
|
|
|
# Below this, both axes have visually settled — skip the redraw.
|
|
const REDRAW_EPSILON_DEG := 0.05
|
|
|
|
func _process(delta: float) -> void:
|
|
var t := _smoothing_weight(delta)
|
|
var new_pitch := lerpf(_pitch, _target_pitch, t)
|
|
var new_roll := lerp_angle_deg(_roll, _target_roll, t)
|
|
var changed := absf(new_pitch - _pitch) > REDRAW_EPSILON_DEG \
|
|
or absf(angle_delta_deg(_roll, new_roll)) > REDRAW_EPSILON_DEG
|
|
_pitch = new_pitch
|
|
_roll = new_roll
|
|
if changed:
|
|
_throttled_redraw(delta)
|
|
|
|
|
|
func _draw() -> void:
|
|
var center := size / 2.0
|
|
var radius := minf(size.x, size.y) / 2.0 - 10.0
|
|
var px_per_deg := radius / PITCH_RANGE
|
|
# Screen y grows downward, so nose-up (positive pitch) pushes the horizon
|
|
# down the instrument (+y) and reveals more sky.
|
|
var horizon_y := clampf(_pitch * px_per_deg, -radius, radius)
|
|
var roll_rad := deg_to_rad(_roll)
|
|
|
|
# Everything inside the dial is drawn in the horizon frame: rotated
|
|
# opposite to roll so the horizon stays level while the instrument banks.
|
|
draw_set_transform(center, -roll_rad, Vector2.ONE)
|
|
|
|
# Ground disc, then the sky as the circle segment above the horizon chord.
|
|
draw_circle(Vector2.ZERO, radius, GROUND_COLOR)
|
|
var sky := PackedVector2Array()
|
|
for i in 97:
|
|
# Start sampling at the bottom of the circle (excluded region) so the
|
|
# kept arc through the top is contiguous.
|
|
var ang := PI / 2.0 + float(i) * TAU / 96.0
|
|
var p := Vector2(cos(ang), sin(ang)) * radius
|
|
if p.y < horizon_y:
|
|
sky.append(p)
|
|
if sky.size() >= 3:
|
|
draw_colored_polygon(sky, SKY_COLOR)
|
|
|
|
# Horizon line, clipped to the dial.
|
|
if absf(horizon_y) < radius:
|
|
var half_chord := sqrt(radius * radius - horizon_y * horizon_y)
|
|
draw_line(Vector2(-half_chord, horizon_y), Vector2(half_chord, horizon_y), LINE_COLOR, 2.0)
|
|
|
|
# Pitch ladder: rungs every 10 degrees, labelled, scrolling with pitch.
|
|
var font := ThemeDB.fallback_font
|
|
for ladder_deg: int in [-30, -20, -10, 10, 20, 30]:
|
|
var y := horizon_y - ladder_deg * px_per_deg
|
|
if absf(y) > radius - 12.0:
|
|
continue
|
|
var half_w := 22.0 if ladder_deg % 20 == 0 else 14.0
|
|
draw_line(Vector2(-half_w, y), Vector2(half_w, y), LINE_COLOR, 1.0)
|
|
draw_string(font, Vector2(half_w + 4.0, y + 4.0), str(absi(ladder_deg)),
|
|
HORIZONTAL_ALIGNMENT_LEFT, -1, 10, LINE_COLOR)
|
|
|
|
# Roll pointer: triangle at the dial's top edge in the horizon frame, so
|
|
# it swings against the fixed tick marks as the ship banks.
|
|
draw_colored_polygon(PackedVector2Array([
|
|
Vector2(0, -radius + 2.0), Vector2(-5, -radius + 12.0), Vector2(5, -radius + 12.0),
|
|
]), SHIP_SYMBOL_COLOR)
|
|
|
|
# Back to the instrument frame for the fixed furniture.
|
|
draw_set_transform(center, 0.0, Vector2.ONE)
|
|
|
|
# Roll scale ticks at 0, +/-30, +/-60 degrees around the top of the dial.
|
|
for tick_deg: int in [-60, -30, 0, 30, 60]:
|
|
var ang := deg_to_rad(float(tick_deg)) - PI / 2.0
|
|
var dir := Vector2(cos(ang), sin(ang))
|
|
var tick_len := 8.0 if tick_deg == 0 else 5.0
|
|
draw_line(dir * radius, dir * (radius + tick_len), RING_COLOR, 2.0)
|
|
|
|
# Fixed ship symbol: wings + centre dot, what the ladder is read against.
|
|
draw_line(Vector2(-34, 0), Vector2(-10, 0), SHIP_SYMBOL_COLOR, 3.0)
|
|
draw_line(Vector2(10, 0), Vector2(34, 0), SHIP_SYMBOL_COLOR, 3.0)
|
|
draw_line(Vector2(-10, 0), Vector2(0, 5), SHIP_SYMBOL_COLOR, 3.0)
|
|
draw_line(Vector2(0, 5), Vector2(10, 0), SHIP_SYMBOL_COLOR, 3.0)
|
|
|
|
draw_arc(Vector2.ZERO, radius, 0.0, TAU, 96, RING_COLOR, 2.0, true)
|