Reference · Updated 2552.07.31.08.07
Aim Target Refactor — Flowchart
Companion visualization for AimTargetRefactor.md.
Companion visualization for AimTargetRefactor.md.
The plan progresses through six independently testable phases. The crucial checkpoint is Phase 2: diagnose BUG-028 before changing the fire or HUD paths.
flowchart TD
P0["Current design<br/>Fire and HUD use separate traces<br/>Blueprint pushes state every tick<br/>Reticles are destroyed and recreated"]
P1["Phase 1 — Shared ray and classification<br/>Add ESLAimTarget and FSLAimTarget<br/>BuildAimRay on WeaponsComponent<br/>Add pure ClassifyHit tests"]
G1{"Headless tests pass?<br/>Gameplay unchanged?"}
P2["Phase 2 — Player perception<br/>Add PlayerPerceptionComponent<br/>Resolve targets at a throttled rate<br/>Publish only when target kind changes<br/>Add Debug and Rate console variables"]
G2{"Diagnose BUG-028<br/>on host and client"}
D2["Use debug view to distinguish:<br/>• trace hits nothing<br/>• trace hits wrong actor<br/>• classification is wrong<br/>• widget displays wrong state"]
P3["Phase 3 — Unify the fire path<br/>Shots adopt BuildAimRay"]
G3{"Single-player and<br/>two-player fire tests pass?"}
P4["Phase 4 — Connect the HUD<br/>HUD binds to OnAimTargetChanged<br/>C++ drives reticle target state<br/>Delete Blueprint target trace"]
G4{"Red reticle works<br/>on host and client?"}
P5["Phase 5 — Remove Blueprint tick logic<br/>Move spread and equip visibility to C++<br/>Leave Blueprint Event Tick empty"]
G5{"Spread and equip-hide<br/>behave as before?"}
P6["Phase 6 — Cache reticles<br/>Create each reticle once<br/>Collapse and un-collapse on swaps<br/>Keep every cached reticle bound"]
G6{"Widget count remains flat<br/>through repeated swaps?"}
DONE["Target architecture<br/>One shared aim ray<br/>Local-only perception<br/>Change-only events<br/>No Blueprint tick<br/>Stable reticle identities<br/>Deterministic collision behavior"]
P0 --> P1 --> G1
G1 -- No --> P1
G1 -- Yes --> P2
P2 --> D2 --> G2
G2 -- Cause unknown --> P2
G2 -- Cause known --> P3
P3 --> G3
G3 -- No --> P3
G3 -- Yes --> P4
P4 --> G4
G4 -- No --> D2
G4 -- Yes --> P5
P5 --> G5
G5 -- No --> P5
G5 -- Yes --> P6
P6 --> G6
G6 -- No --> P6
G6 -- Yes --> DONE
#Resulting runtime flow
flowchart LR
W["WeaponsComponent<br/>BuildAimRay()"]
P["PlayerPerceptionComponent<br/>Local player only<br/>Resolve at about 30 Hz"]
C["ClassifyHit()<br/>None / Hostile / Friendly / Interactable"]
E{"Target kind changed?"}
H["HUD and all cached reticles<br/>receive OnAimTargetChanged"]
F["Fire path<br/>uses the same aim ray"]
V["Active reticle displays<br/>the correct state immediately"]
W --> P --> C --> E
E -- Yes --> H --> V
E -- No --> P
W --> F
The central idea is: BuildAimRay() becomes the single source of truth, perception determines what that ray hits, and the HUD reacts only when the classification changes.