Quick answer: Track each touch by its TouchID, not by touch index. Indices renumber as fingers lift; the ID is stable for the life of that touch.
A twin-stick mobile game uses touch 0 for the move stick and touch 1 for the aim stick. Lift the move finger and the aim stick suddenly jumps — the aim touch became index 0.
Index vs ID
- Touch index (0, 1, 2…): the position in the current touch list. When a finger lifts, everything after it shifts down.
- TouchID: a unique number assigned when the touch starts, stable until it ends.
Tracking by index means “touch 1” can silently become a different finger.
Capture the ID on Start
On touch start (over MoveStickZone):
Set move_touch_id to Touch.TouchID
On touch start (over AimStickZone):
Set aim_touch_id to Touch.TouchID
Read by ID Each Frame
For each touch:
Touch.TouchID = move_touch_id
→ Set move_vector from Touch.X, Touch.Y
Touch.TouchID = aim_touch_id
→ Set aim_vector from Touch.X, Touch.Y
On any touch end:
Touch.TouchID = move_touch_id → Set move_touch_id to -1
Touch.TouchID = aim_touch_id → Set aim_touch_id to -1
Each stick follows its own finger regardless of how the index list reorders.
Verifying
Hold both sticks, lift either finger, re-touch — the other stick never jumps. The two controls stay independently bound to their fingers.
“Touch index reshuffles; TouchID doesn’t. Bind controls to the ID, captured on touch start.”
Same principle for pinch-zoom — capture the two IDs at gesture start and track those, not ‘touch 0 and touch 1’.