## Camera in 2D

Figure 8-19. The view frustum for our 2D world, again gl.glOrthof(x, x + FRUSTUM_WIDTH, y, y + FRUSTUM_HEIGHT, 1, -1); Figure 8-20 shows what that means.

gl.glOrthof(x, x + FRUSTUM_WIDTH, y, y + FRUSTUM_HEIGHT, 1, -1); Figure 8-20 shows what that means.

Figure 8-20. Moving the frustum around

By this we simply specify the bottom-left corner of our view frustum in the world space. This is already sufficient to implement a freely movable 2D camera. But we can do better. What about not specifying the bottom-left corner of the view frustum with x and y, but instead specifying the center of the view frustum? That way we could easily center our view frustum on an object at a specific location — say, the cannonball from our preceding example:

gl.glOrthof(x - FRUSTUM_WIDTH / 2, x + FRUSTUM_WIDTH / 2, y - FRUSTUM_HEIGHT / 2, y + FRUSTUM_HEIGHT / 2, 1, -1);

Figure 8-21 shows what this looks like.

Figure 8-21. Specifying the view frustum in terms of its center

That's still not all we can do with glOrthof(). What about zooming? Let's think about this for a little while. We know that via glViewportf() we can tell OpenGL ES what gl.glOrthof(x - FRUSTUM_WIDTH / 2, x + FRUSTUM_WIDTH / 2, y - FRUSTUM_HEIGHT / 2, y + FRUSTUM_HEIGHT / 2, 1, -1);

Figure 8-21 shows what this looks like.

A

portion of our screen to render the contents of our view frustum to. OpenGL ES will automatically stretch and scale the output to align with the viewport. Now, if we make the width and height of our view frustum smaller, we will simply show a smaller region of our world on the screen. That's zooming in. If we make the frustum bigger, we'll show more of our world—that's zooming out. We can therefore introduce a zoom factor and multiply it by our frustum's width and height to zoom in an out. A factor of 1 will show us the world as in Figure 8-21, using the normal frustum width and height. A factor smaller than 1 will zoom in on the center of our view frustum. And a factor bigger than 1 will zoom out, showing us more of our world (e.g., setting the zoom factor to 2 will show us twice as much of our world). Here's how we can use glOrthof() to do that for us:

gl.glOrthof(x - FRUSTUM_WIDTH / 2 * zoom, x + FRUSTUM_WIDTH / 2 * zoom, y -FRUSTUM_HEIGHT / 2 * zoom, y + FRUSTUM_HEIGHT / 2 * zoom, 1, -l);

Dead simple! We can now create a camera class that has a position it is looking at (the center of the view frustum), a standard frustum width and height, and a zoom factor that makes the frustum smaller or bigger, thereby showing us either less of our world (zooming in) or more of our world (zooming out). Figure 8-22 shows a view frustum with a zoom factor of 0.5 (the inner gray box), and one with a zoom factor of 1 (the outer, transparent box).

Figure 8-22. Zooming by manipulating the frustum size

To make our lives complete we should add one more thing. Imagine that we touch the screen and want to figure out what point in our 2D world we touched. We already did this a couple of times in our iteratively improving cannon examples. With a view frustum configuration that does not factor in the camera's position and zoom, as in Figure 8-19, we had the following equations (see the update() method of our cannon examples):

worldX = (touchX / Graphics.getWidth()) x FRUSTUM_WIDTH; worldY = (l - touchY / Graphics.getHeight()) x FRUSTUM_HEIGHT;

Figure 8-22. Zooming by manipulating the frustum size

We first normalize the touch x- and y-coordinates to the range 0 to 1 by dividing by the screen's width and height, and then we scale them so that they are expressed in terms of our world space by multiplying them with the frustum's width and height. All we need to do is factor in the position of the view frustum as well as the zoom factor. Here's how we do that:

worldX = (touchX / Graphics.getWidth()) x FRUSTUM_WIDTH + x - FRUSTUM_WIDTH / 2; worldY = (l - touchY / Graphics.getHeight()) x FRUSTUM_HEIGHT + y - FRUSTUM_HEIGHT / 2;

Here, x and y are our camera's position in world space.

+1 0