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.