As it turns out, writing gesture detection is not an easy task. I gave it a shot anyway, and wrote a re-usable scene for the awesome free software Godot Game Engine.

It all started when I decided to switch the focus of my work-in-progress game Sawdust to "mobile-first". To provide a more tactile and intuitive interface, I needed to detect "twist" gestures for rotating pieces, and "double-tap" gestures for placing them. Down the rabbit hole I went, and I built a re-usable drop-in script for detecting a variety of gestures on mobile.

godot-gesture library

The code is MIT-licensed and ready to drop into your project, so if you want twist, pinch, two-finger drag, or double-tap gesture detection within your project, get it here:

Example, debugging on computer

Methodology

It's quite likely I wasn't looking in the right places, but I couldn't find any readily usable information on detecting these gestures, so the general philosophy I used is as follows:

  • Gesture events only register when the 2nd finger is lifted

  • "Votes" are summed up for how closely it follows certain rules to trigger each of the 3 events checked

  • The event with the highest vote "wins" and is triggered

Tap and double-tap events are easy. Two-finger drag is fairly easy too. Things get trickier with pinch, twist, and distinguishing between these three. The "votes" for each event then are as follows:

  • If one finger crosses an axis of the average position of the other, while keeping roughly the same distance from it, then that is a twist event, with the consistency of the distance determining it's "votes"

  • If the distance traveled of two fingers roughly "cancels each other out" when summed as vector, then its a pinch in or out, with "how opposite" the two vectors are being the votes

  • If the vector traveled of two fingers is roughly the same, then it's a two finger drag event, with the average distance being the votes

As I said, not sure if these are the best criteria, but after tweaking a few thresholds it seems to work fairly well on my tablet device, certainly well enough for my usage. I'd love to see better implementations, however.


Update: I added event debouncing to distinguish simple drags / taps.