Better pinch-to-zoom

The horrific pinch-to-zoom implementation that I had in my code up until recently was interfering with user testing. When I say user testing, I really mean that I show the game to my work colleagues and get feedback on what is or isn’t working.

The problem is that I had to apologise all the time about the crappy camera pan and zoom which was annoyingly jerky and nothing like Google or Apple maps.

I needed to find a solution and in the process found some posts like this and this, both of which followed my own naive approach to pinch zoom, i.e. useless for zoom.

Field of View

One of the things that really confused me was that often people were changing the field of view in order to achieve the zoom. I thought moving the camera closer or further away made more sense but maybe that’s because I don’t use SLR cameras very often (I’m no photographer). That’s essentially what changing of the FOV mimics; the camera stays still and the lens zooms in/out.

Perhaps I figured that if a camera pan is achieved by moving the camera then a camera zoom would also move the camera. After all, I want to ‘fly’ the camera around the scene. Plus I didn’t actually want to mess with the FOV because it puts distortion on the 3D world (it at least changes it).

It was educational though, even if what people said on forums created some confusion. It turns out that a camera dolly has nothing to do with a dolly zoom.

Never immediate, always transitioning

Finally I found a gem. The author wasn’t even writing about camera zoom but rather about linear interpolation; I can’t even remember how I came to be looking into LERP.

Ignoring his grammar, the author’s conclusion struck a chord…

In general, is a fairly common mistake in beginner videogame developers that elements in the games are either in position A or B. For us, programmers, is much easier the world were things are never in a “travelling” or “transition” status. [sic] – Juan Gomez

The jerkiness of my camera zoom was because I was moving the camera immediately from A to B rather than letting the update loop transition the camera to the new position. Position B needed to be a requested destination to which the camera moved toward every clock tick. The LERP function smoothed this transition further because it can be set to accelerate away from A and decelerates into B.

And with that, another problem was solved. Yay.