mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
perf(hud): stop flight instruments redrawing when values have settled
hud_gauge, hud_attitude_indicator, and hud_heading_tape now skip queue_redraw() when the newly-lerped value hasn't moved past a small epsilon, instead of redrawing every frame forever. Angle-wrapping values (heading, attitude roll) use a new shared angle_delta_deg helper on HudInstrument so the wrap boundary doesn't read as a false jump. HUD.tscn's Instruments node now sets process_mode = 1 (PAUSABLE), overriding the inherited ALWAYS mode from the HUD root so instruments stop processing during the post-match pause freeze, while sibling ResultOverlay keeps running its win-screen tween.
This commit is contained in:
@@ -171,6 +171,7 @@ text = "0 - 0"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Instruments" type="Control" parent="Control"]
|
||||
process_mode = 1
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
||||
@@ -26,11 +26,19 @@ func set_attitude(pitch_deg: float, roll_deg: float) -> void:
|
||||
_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)
|
||||
_pitch = lerpf(_pitch, _target_pitch, t)
|
||||
_roll = lerp_angle_deg(_roll, _target_roll, t)
|
||||
queue_redraw()
|
||||
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:
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
|
||||
@@ -26,8 +26,14 @@ func set_value(value: float) -> void:
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var t := _smoothing_weight(delta)
|
||||
_value = lerpf(_value, _target, t)
|
||||
queue_redraw()
|
||||
var new_value := lerpf(_value, _target, t)
|
||||
# Redraw threshold scales with the gauge's own range so it stays
|
||||
# imperceptible whether this is a 0-12 altitude gauge or a 0-100 thrust
|
||||
# bar, while skipping the redraw once the lerp has visually settled.
|
||||
var changed := absf(new_value - _value) > max_value * 0.001
|
||||
_value = new_value
|
||||
if changed:
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
|
||||
@@ -26,10 +26,16 @@ func set_heading(heading_deg: float) -> void:
|
||||
_target_heading = heading_deg
|
||||
|
||||
|
||||
# Below this, the tape has visually settled — skip the redraw.
|
||||
const REDRAW_EPSILON_DEG := 0.05
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var t := _smoothing_weight(delta)
|
||||
_heading = fmod(lerp_angle_deg(_heading, _target_heading, t) + 360.0, 360.0)
|
||||
queue_redraw()
|
||||
var new_heading := fmod(lerp_angle_deg(_heading, _target_heading, t) + 360.0, 360.0)
|
||||
var changed := absf(angle_delta_deg(_heading, new_heading)) > REDRAW_EPSILON_DEG
|
||||
_heading = new_heading
|
||||
if changed:
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
|
||||
@@ -13,5 +13,13 @@ static func lerp_angle_deg(from: float, to: float, weight: float) -> float:
|
||||
return rad_to_deg(lerp_angle(deg_to_rad(from), deg_to_rad(to), weight))
|
||||
|
||||
|
||||
# Shortest signed distance from `from` to `to` in degrees, wrapped to
|
||||
# [-180, 180]. Use this (never a plain subtraction) to decide whether an
|
||||
# angle that wraps around (heading, roll) has moved enough to redraw —
|
||||
# a naive delta gives a false-large jump at the 0/360 boundary.
|
||||
static func angle_delta_deg(from: float, to: float) -> float:
|
||||
return wrapf(to - from, -180.0, 180.0)
|
||||
|
||||
|
||||
func _smoothing_weight(delta: float) -> float:
|
||||
return 1.0 - exp(-SMOOTHING * delta) # frame-rate independent
|
||||
|
||||
@@ -25,8 +25,6 @@ Bugs found in an adversarial review. None are gameplay- or physics-affecting, so
|
||||
|
||||
## Performance
|
||||
|
||||
- [x] Gate `Ship._emit_telemetry_data()` — it runs `get_euler()` + trig per ship per physics tick for every ship, including AI ships nobody displays and `--headless` training where no HUD exists. Gate on having signal connections, and `set_physics_process(false)` when headless (`arena_boundary.gd` already does this correctly for its `_process`).
|
||||
- [ ] Stop the HUD instruments redrawing once settled: all five `queue_redraw()` every frame forever, re-recording canvas items with `draw_string` glyph work, and `HUD.tscn` sets `process_mode = 3` so it continues while paused.
|
||||
- [ ] Shared per-team materials instead of `Ship._apply_team_color()` allocating a fresh `StandardMaterial3D` and assigning it as `material_override` (and running at least twice per ship — once from `_ready`, once from the `team` setter). Removes the allocation and lets same-team ships batch.
|
||||
- [ ] Merge each goal's visuals into one `ArrayMesh` with a hull surface and a net surface — currently 11 `MeshInstance3D`s and 4 materials per goal, ~22 draw calls for a static prop. `arena_boundary.gd:333` already demonstrates the `SurfaceTool` technique in this codebase.
|
||||
- [ ] Merge the four non-tinted ship meshes (Hull/Canopy/EngineGlowL/R) into one — 6 draw calls per ship down to 3. Irrelevant at 1v1; 36 calls before VFX at 3v3.
|
||||
|
||||
Reference in New Issue
Block a user