(js: VirtualJoystick)
| 83 | } |
| 84 | |
| 85 | export function updateVirtualJoystick(js: VirtualJoystick): void { |
| 86 | const screenW = getScreenWidth(); |
| 87 | const touchCount = getTouchCount(); |
| 88 | |
| 89 | // If already active, check if our finger is still down |
| 90 | if (js.active) { |
| 91 | let stillActive = false; |
| 92 | for (let i = 0; i < touchCount; i++) { |
| 93 | const tx = getTouchX(i); |
| 94 | const ty = getTouchY(i); |
| 95 | if (i === js.touchIndex && tx !== 0 && ty !== 0) { |
| 96 | stillActive = true; |
| 97 | break; |
| 98 | } |
| 99 | } |
| 100 | // Also check that the touch index is still within count |
| 101 | if (js.touchIndex >= touchCount) { |
| 102 | stillActive = false; |
| 103 | } |
| 104 | if (!stillActive) { |
| 105 | js.active = false; |
| 106 | js.touchIndex = -1; |
| 107 | js.valueX = 0; |
| 108 | js.valueY = 0; |
| 109 | injectGamepadAxis(js.axisX, 0); |
| 110 | injectGamepadAxis(js.axisY, 0); |
| 111 | return; |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | // Look for a new touch if not active |
| 116 | if (!js.active) { |
| 117 | for (let i = 0; i < touchCount; i++) { |
| 118 | if (claimedTouches.has(i)) continue; |
| 119 | const tx = getTouchX(i); |
| 120 | const ty = getTouchY(i); |
| 121 | if (tx === 0 && ty === 0) continue; |
| 122 | |
| 123 | // Check if touch is in the correct zone |
| 124 | const inZone = js.zone === 'left' ? tx < screenW / 2 : tx >= screenW / 2; |
| 125 | if (!inZone) continue; |
| 126 | |
| 127 | // PUBG-style: joystick origin appears at touch position |
| 128 | js.active = true; |
| 129 | js.touchIndex = i; |
| 130 | js.originX = tx; |
| 131 | js.originY = ty; |
| 132 | js.handleX = tx; |
| 133 | js.handleY = ty; |
| 134 | claimedTouches.add(i); |
| 135 | break; |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | if (!js.active) return; |
| 140 | |
| 141 | claimedTouches.add(js.touchIndex); |
| 142 |
nothing calls this directly
no test coverage detected