An Example

Let's use the Camera2D class in our cannon example. I copied the CollisionTest file and renamed it Camera2DTest. I also renamed the GLGame class inside the file Camera2DTest, and renamed the CollisionScreen class Camera2DScreen. We'll just discuss the little changes we have to make to use our new Camera2D class.

The first thing we do is add a new member to the Camera2DScreen class: Camera2D camera;

We initialize this member in the constructor as follows: camera = new Camera2D(glGraphics, WORLD_WIDTH, WORLD_HEIGHT);

We just pass in our GLGraphics instance and the world's width and height, which we previously used as the frustum's width and height in our call to glOrthof(). All we need to do now is replace our direct OpenGL ES calls in the present() method, which looked like this:

gl.glViewport(0, 0, glGraphics.getWidth(), glGraphics.getHeight());

gl.glClear(GLl0.GL_COLOR_BUFFER_BIT);

gl.glMatrixMode(GLl0.GL_PROJECTION);

gl.glLoadIdentity();

gl.gl0rthof(0, WORLD_WIDTH, 0, WORLD_HEIGHT, 1, -1); gl.glMatrixMode(GL10.GL_M0DELVIEW);

We replace them with this:

gl.glClear(GL10.GL_COLOR_BUFFER_BIT); camera.setViewportAndMatrices();

We still have to clear the framebuffer, of course, but all the other direct OpenGL ES calls are nicely hidden inside the Camera2D.setViewportAndMatrices() method. If you run that code, you'll see that nothing has changed. Everything works like before—all we did was make things a little nicer and more flexible.

We can also simplify the update() method of the test a little. Since we added the Camera2D.touchToWorld() method to the camera class, we might as well use it. We can replace this snippet from the update method:

touchPos.x = (event.x / (float) glGraphics.getWidth())* WORLD_WIDTH; touchPos.y = (1 - event.y / (float) glGraphics.getHeight()) * WORLD_HEIGHT;

with this:

camera.touchToWorld(touchPos.set(event.x, event.y));

Neat, everything is nicely encapsulated now. But it would be very boring if we didn't use the features of our camera class to their full extent. Here's the plan: we want to have the camera look at the world in the "normal" way as long as the cannonball does not fly. That's easy; we're already doing that. We can determine whether the cannonball flies or not by checking whether the y-coordinate of its position is less than or equal to zero. Since we always apply gravity to the cannonball, it will of course fall even if we don't shoot it, so that's a cheap way to check matters.

Our new addition will come into effect when the cannonball is flying (when the y-coordinate is greater than zero). We want the camera to follow the cannonball. We can achieve this by simply setting the camera's position to the cannonball's position. That will always keep the cannonball in the center of the screen. We also want to try out our zooming functionality. Therefore well increase the zoom factor depending on the y-coordinate of the cannonball. The further away from zero, the higher the zoom factor. This will make the camera zoom out if the cannonball has a higher y-coordinate. Here's what we need to add at the end of the update() method in our test's screen:

camera.position.set(ball.position); camera.zoom = 1 + ball.position.y / WORLD_HEIGHT; } else {

camera.position.set(WORLD_WIDTH / 2, WORLD_HEIGHT / 2); camera.zoom = 1;

As long as the y-coordinate of our ball is greater then zero, the camera will follow it and zoom out. We just add a value to the standard zoom factor of 1. That value is just the relation between the ball's y-position and the world's height. If the ball's y-coordinate is at WORLD_HEIGHT, the zoom factor will be 2, so we we'll see more of our world. The way I did this is really arbitrary; you could come up with any formula that you want here—

there's nothing magical about it. In case the ball's position is less than or equal to zero, we show the world normally, as we did in the previous examples.

Was this article helpful?

0 0

Post a comment