CN·IOS
TH·EN
TOUCH CONTROLS · RTS NATIVE

Gesture mapping

นิ้วคุณคือเมาส์. แต่ RTS ต้องการ "selection box หรือ camera pan" — เราสอน gesture ให้รู้จัก: tap-select, drag-box, long-press = right-click, 2-finger pan, pinch zoom.

The gestures

Single tap

= LEFT-CLICK
select unit / place waypoint

Drag

= BOX-SELECT
rubber-band selection rect

Long-press

= RIGHT-CLICK
deselect / context menu

Two-finger drag

= CAMERA PAN
scroll the map

⇱⇲

Pinch

= ZOOM
camera zoom in / out

Cancel mid-drag

= CANCEL HOVER
second touch kills gesture

Why this works

Engine เก่าของ C&C ถูกออกแบบมาให้เมาส์ทำงานเป็นหลัก — ทุก UI hit-test, ทุก game state ผูกกับ mouse event. แทนที่จะ rewrite UI layer (เดือนนับ), เราส่ง touch event ผ่าน SDL3 เป็น synthetic mouse event โดยตรง:

SDL3 fakeMouse

SDL3 มี fake mouse API — เรา map touch state เป็น mouse down/move/up ตาม gesture type.

// pseudocode — real code lives in Core/GameEngine/Source/GameClient/Input/Mouse.cpp
if (touchType == TOUCH_DOWN)    SDL_SendFakeMouseMotion(0, x, y);
if (touchType == TOUCH_UP)      SDL_SendFakeMouseButton(0, SDL_BUTTON_LEFT, SDL_RELEASED);
if (gesture == LONG_PRESS)      SDL_SendFakeMouseButton(0, SDL_BUTTON_RIGHT, SDL_PRESSED);

Heuristic for "box vs pan"

The hard part: a drag could be a selection-box OR a camera pan. We disambiguate by:

  • Velocity threshold: slow = box, fast = pan
  • Movement >30% of screen: probably a pan, abort selection
  • Second touch starts: instantly treat as pan + send cancel-up to RTS
Why not gestures all the way down? The engine's GUI code uses Win32 mouse constants directly — replacing every call site is a 4-week rewrite. Mapping fingers → synthetic mouse keeps the port tractable and reviewable upstream.