Now we are going to look quickly at using a camera, something we haven’t used in any of the prior tutorials. Using a camera has a couple of advantages. It gives you an easier way of dealing with device resolution as LibGDX will scale the results up to match your device resolution. It also makes it easier to move the view around when your scene is larger than a single screen. That is exactly what we are going to do in the code example below.
I am using a large ( 2048×1024 ) image that I obtained here.
Alright, now the code:
package com.gamefromscratch;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.input.GestureDetector.GestureListener;
import com.badlogic.gdx.math.Vector2;
public class CameraDemo implements ApplicationListener, GestureListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;
@Override
public void create() {
camera = new OrthographicCamera(1280, 720);
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal(“data/Toronto2048wide.jpg”));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
sprite = new Sprite(texture);
sprite.setOrigin(0,0);
sprite.setPosition(-sprite.getWidth()/2,-sprite.getHeight()/2);
Gdx.input.setInputProcessor(new GestureDetector(this));
}
@Override
public void dispose() {
batch.dispose();
texture.dispose();
}
@Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
}
@Override
public void resize(int width, int height) {
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public boolean touchDown(float x, float y, int pointer, int button) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean tap(float x, float y, int count, int button) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean longPress(float x, float y) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean fling(float velocityX, float velocityY, int button) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
// TODO Auto-generated method stub
camera.translate(deltaX,0);
camera.update();
return false;
}
@Override
public boolean zoom(float initialDistance, float distance) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2,
Vector2 pointer1, Vector2 pointer2) {
// TODO Auto-generated method stub
return false;
}
}
Additionally in Main.java I changed the resolution to 720p like so:
package com.gamefromscratch;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = “camera”;
cfg.useGL20 = false;
cfg.width = 1280;
cfg.height = 720;
new LwjglApplication(new CameraDemo(), cfg);
}
}
When you run it you will see:
Other then being an image of my cities skyline, its pan-able. You can swipe left or right to pan the image around.
The code is mostly familiar at this point, but the important new line is:
camera = new OrthographicCamera(1280, 720);
This is where we create the camera. There are two kinds of cameras in LibGDX, Orthographic and Perspective. Basically an orthographic camera renders what is in the scene exactly the size it is. A perspective camera on the other hand emulates the way the human eye works, by rendering objects slightly smaller as they get further away. Here is an example from my Blender tutorial series.
Perspective:
Orthographic:
Notice how the far wing is smaller in the perspective render? That’s what perspective rendering does for you. In 2D rendering however, 99 times out of 100 you want to use Orthographic.
The values passed to the constructor are the resolution of the camera, the width and height. In this particular case I chose to use pixels for my resolution, as I wanted to have the rendering at 1280×720 pixels. You however do not have to… if you are using physics and want to use real world units for example, you could have gone with meters, or whatever you want. The key thing is that your aspect ratio is correct. The rest of the code in create() is about loading our image and positioning it about the origin in the world. Finally we wire up our gesture handler so we can pan/swipe left and right on the image.
The next important call is in render():
batch.setProjectionMatrix(camera.combined);
This ties our LibGDX camera object to the OpenGL renderer. The OpenGL rendering process depends on a number of matrix to properly translate from the scene or world to screen coordinates during rendering. camera.combined returns the camera’s view and projection matrixes multiplied together. If you want more information about the math behind the scenes you can read here. Of course, the entire point of the Camera classes is so you don’t have to worry about this stuff, so if you find it confusing, don’t sweat it, LibGDX takes care of the math for you.
Finally in our pan handler ( huh? ) we have the following code:
camera.translate(deltaX,0);
camera.update();
You can use translate to move the camera around. Here we move the camera along the X axis by the amount the user swiped. This causes the view of the image to move as the user swipes the screen/pans the mouse. Once you are done modifying the camera, you need to update it. Without calling update() the camera would never move.
There are a number of neat functions in the camera that we don’t use here. There are functions to look at a point in space, to rotate or even rotate around ( orbit ) a vector. There are also functions for projecting to and from screen to world space as well as code for ray casting into the scene. In a straight 2D game though you generally won’t use a lot of this functionality. We may take a closer look at the camera class later on when we jump to 3D.