Commit graph Aetheria/Assets/Scripts/Gameplay/ShieldInterceptor.cs
Author SHA1 Message Date
Meta Vens
fb6062b8c6 Shield panel: gate reuse and Hit on the panel's own radius
The operator's play report on FieldShieldTest ("weak hits are very
janky, clicking outside the hex still makes it tremble and shatter,
pooling seems very rough") traced to two provable defects, not one
tuning constant:

- ShieldPanel.Hit had no bounds check at all. A point handed to it was
  always enqueued and injected regardless of how far outside the
  panel's own panelRadius it was.
- ShieldInterceptor.FindReusable decided reuse from a raw world-space
  chord distance to the panel's stale spawn-time Position, using
  PanelRadius*ReuseFraction (authored up to 2x) as the threshold. On a
  non-uniformly scaled/curved envelope a chord across curvature is not
  the panel's own in-plane extent, so a click clearly outside the
  rendered tiling could still measure inside threshold and get routed
  to Hit() -- which had nothing to reject it.
- Reusing a panel never refreshed its pooled DieAt, so a panel struck
  again could still expire and get returned to the pool mid-fracture
  ("pooling seems very rough").

Fix: ShieldPanel.ContainsWorldPoint is now the one owner of "is this
point within my own radius" (panel-local in-plane distance vs.
panelRadius), used both as Hit's hard gate and as FindReusable's
candidacy test (with ReuseFraction, now capped at 1, narrowing but
never widening past the physical radius). Reuse now also extends
DieAt from the moment of the new hit.

Pinned in ShieldPanelCut3Verify.CheckHitOutsideRadiusDoesNotReachPanel:
a direct Hit() and a routed Absorb() outside a panel's own radius must
enqueue nothing and leave its state buffer untouched, and a genuinely
outside click opens its own panel. Deterministic (checks the pending
queue and no-op state, not temper drift) because breakBudgetFraction
paces fracture over many frames on purpose, so temper keeps drifting
from an earlier hit alone -- a drift-based check would have been
measuring that, not this rule (caught this against the check's own
first run).

All four ShieldPanelCut<N>Verify probes pass (batchmode, real GPU
device, no -nographics).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 21:02:18 +02:00
Meta Vens
0e2fe6dc11 Add ShieldInterceptor: the interceptor presenter and panel pool (Cut 3)
R2: the shield is an interceptor. ShieldInterceptor implements IAbsorbPresenter
and converts each AbsorbEvent into a pose (intercept point projected onto the
ShieldEnvelope, normal from SurfaceNormal, size from the item's PanelRadius)
and a strike, deciding nothing else. It reuses Assets/Scripts/Prototype.cs
rather than writing a second pool.

Reuse: a second hit landing within PanelRadius*ReuseFraction of a live panel
strikes that panel (Hit only, no ResetSim) instead of spawning a new one --
this is what makes ShieldSim.compute's temper erosion observable across
multiple hits.

Pool exhaustion: when MaxLivePanels is already live, the oldest live panel
(by spawn order) is recycled in place -- reposed and re-armed for the new
intercept point -- rather than dropping the strike or growing past the
§2.3 frame budget.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 13:51:26 +02:00