Реалізація дотикових керувань для мобільних ігор (дотики, свайпи, жести)
Unity обробляє дотики на мобільних пристроях через Input.GetTouch() або новий InputSystem—і між ними велика прірва. Старий API не розрізняє дотик від початку свайпу, поки палець не піднімається. Для ігор, де реакція на дотик повинна бути миттєвою, це неприйнятно.
Де ломаються більшість реалізацій
Найчастіша помилка: розпізнавання жестів на основі TouchPhase.Ended. Розробники порівнюють позиції в Began та Ended, обчислюють вектор—і отримують свайп. Працює на пристрої розробника при 60 FPS. На телефоні з 30 FPS та дросселюванням через перегрів (типово для бюджетних Android-пристроїв), дельта між кадрами зростає, і короткий дотик за таймером класифікується як свайп.
Правильний підхід: відстежувати рух у фазах Stationary та Moved, додати поріг відстані (sqrMagnitude > threshold) та поріг часу (Time.time - touchStartTime < tapMaxDuration). Unity це не надає з коробки—вам потрібен власний GestureRecognizer.
У проекті на Godot 4 з InputEventScreenTouch та InputEventScreenDrag ситуація трохи краща: рушій розділяє події на рівні API. Але мультитач—це окрема історія. index у InputEventScreenTouch дає порядковий номер пальця, і при швидкому зняттю одного пальця index-и можуть перепокладатися, ламаючи логіку двопальцевих жестів.
Побудова системи жестів
Для Unity напишіть TouchInputManager як singleton MonoBehaviour, який на кожному кадрі в Update() перебирає Input.touches і розкладає дотики на автомати стану—по одному FSM на кожен активний fingerId. Стани: Idle → Pressing → Tapping/Swiping/Holding. Переходи залежать від відстані та часу.
Вихід: події OnTap(Vector2 position), OnSwipe(Vector2 direction, float velocity), OnHold(Vector2 position, float duration), OnPinch(float delta). Ігрові системи підписуються на ці події через C# делегати або UnityEvent, не знаючи про Input.GetTouch.
Для Flutter-ігор на flame engine використовуйте TapDetector, PanDetector, ScaleDetector з пакету flame. Вони правильно працюють на вершині Flutter GestureArena—кожен детектор бере участь у арбітражі жесту, а переможець визначається за пріоритетом. Важливо: ScaleDetector та PanDetector конфліктують, якщо не встановити behavior: HitTestBehavior.opaque на батьківському віджеті.
Реальний кейс: Свайп-атаки в RPG
В одному проекті (top-down RPG, Unity 2022.3 LTS) потрібні були спрямовані свайп-атаки з восьма напрямків. Проста нормалізація вектора давала нестійкий результат—діагональні напрямки срабатували рідше, тому що користувачі рідко проводять строго під 45°. Рішення: зони допуску ±30° замість стандартних ±22.5°, плюс взвешення за швидкістю свайпу—швидкі свайпи менш точні, повільні—точніші. Після цього процент правильного розпізнавання зростав з 78% до 94% за даними Firebase Analytics (користувацька подія gesture_recognized).
Крім того, ми додали візуальний зворотний зв'язок через LineRenderer, який малює слід свайпу з затуванням. Без нього гравці не знають, прийняла гра їхній жест чи ні.
Мультитач та граничні випадки
Pinch-zoom реалізується через відстань між двома Touch об'єктами з різними fingerId. Головна подвідна камінь: коли третій палець торкається екрана під час pinch. Без обробки цього сценарію fingerId-и зміщуються і zoom стрибає. Рішення: зафіксуйте два fingerId при старті pinch і ігноруйте всі нові дотики до завершення жесту.
На Android крім того перевірте MotionEvent.ACTION_POINTER_DOWN та ACTION_POINTER_UP через нативний плагін, якщо вам потрібен доступ до тиску та площі контакту—Input.GetTouch у Unity не надає цих даних повністю.
Тривалість та обсяг робіт
Базова система (дотик, свайп, утримування) для однієї платформи: 2–4 дні. Повна система з мультитачем, pinch, кастомними жестами та інтеграцією з механіками гри: 1–2 тижні. Вартість розраховується індивідуально після аналізу вимог проекту.







