tl;dr: This post covers a couple important issues with tap-to-select and how to solve them.
Tap-to-select: Common pitfalls and a robust solution
Tap-to-select is a common mechanic in many games. However, it's often implemented poorly, and is hard to use for the player!
Let's start simple: Use an object's collision shape
In most games, each character / item / selectable-thing has a defined collision shape. This is useful for other features like detecting collisions with the level. But we can re-use this collision shape for tap-to-select. We simply check whether the position of a given mouse/touch event intersects the collision shape.
However, there are a couple important problems with this approach: overlapping objects, and zoomed-out cameras.
Dealing with object overlap
When objects overlap, and a tap intersects more than one object, a naïve implementation usually just chooses whichever object was added to the level first.
But that's not ideal. For example, if object A and object B overlap, and the tap position is near the center of object B, and near the edge of object A, then the player probably intends for the tap to select object B. We want to make sure our implementation won't return object A in this case!
A good solution for this problem is to check all of the intersected objects, and only use the object whose center is closest to the tap.
Dealing with camera zoom
Another important problem relates to camera zoom. When the camera is zoomed way out, our selectable objects become very small, and their collision shapes may be less than a few tiny pixels across. These objects will then be very difficult to tap with fat fingers on a tiny mobile-phone screen!
A good solution for this problem is to select whichever object is closest to the tap.
But we also need to make sure that the tap is still within a reasonable radius. If the player taps too far from any object, we don't want to select the closest object. So for this to work, we need to define a tap-radius for each object.
This tap radius must be defined in screen space, since a level-space radius would suffer from the original problem of getting smaller when zoomed-out.
However, a screen-space radius might not make sense when zoomed-in, since the object's level-space shape could then be a lot bigger than the screen-space radius, and the player might still expect to be able to select the object by tapping anywhere within its shape.
|Using a screen-space tap radius.|
Best of both worlds
- For each tap, we first check for all objects whose shape is intersected by the tap.
- If there is some intersected object, we use whichever intersected object is closest to the tap.
- If there is no intersected object, we then check for the closest object whose screen-radius encompasses the tap position.
|Combing level-space collision-shape and screen-space tap radius.|