This time I’m on a surprising problem and after some work I’m here to ask for help. ???
My point is to develop a “simple” way to have a decent zoom and pan functionality for a turn based game. In my mind requirement is to realize a zoom camera on top of a map, something like
s9tKaoap1bI
take a look to zoom in/out an pan.
Now, after some work I have to admit I don’t have find a tutorial/documentation on how to organize my codebase to solve this problem, so the following points are my thoughts on this topic so far:
- in my init code:
- create a new OrthographicCamera: it’s a 2d game, I don’t need anything else
- create a new Stage with some actors in (for example a window or a button)
- use a InputMultiplexer and add two InputProcessor: one for stage (UI) and one for game entities: so I can separate input on ui and on game entities
- in my render code every frame:
- clear everything
- update camera
- batch.begin
- draw the baseMap
- batch.end
- stage.act: update ui
- stage.draw: render ui
- when zoom change, only camera zoom change, so ui is not scaled (this is good of course!)
package test;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
public class MapPanZoomExample extends ApplicationAdapter {
private OrthographicCamera cam;
private Image map;
public SpriteBatch batch;
private Stage stage;
private Skin skin;
@Override
public void create() {
batch = new SpriteBatch();
// create ui
stage = new Stage();
skin = new Skin(Gdx.files.internal("defaultSkin/uiskin.json"));
final Dialog dialog = new Dialog("Welcome", skin, "dialog") {
public void result(Object obj) {
System.out.println("Closed dialog!");
}
};
dialog.setPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0);
dialog.text("Hello World ! Try to move with mouse and zoom with mouse wheel");
dialog.button("Close", true); // sends "true" as the result
dialog.pack();
dialog.setVisible(true);
stage.addActor(dialog);
// init camera
cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// init map image
map = new Image(new Texture("exampleMap.jpg"));
// init input processor
InputMultiplexer multi = new InputMultiplexer();
multi.addProcessor(stage);
multi.addProcessor(new InputProcessor() {
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
System.out.println("clicked: " + screenX + "," + screenY);
return false;
}
@Override
public boolean scrolled(int amount) {
// arbitrary max zoomIn and max zoomOut values here
if (cam.zoom - amount >= -0.25f && cam.zoom - amount <= 2) {
cam.zoom -= (float) amount / 10f;
}
return true;
}
@Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
@Override
public boolean keyUp(int keycode) {
return false;
}
@Override
public boolean keyTyped(char character) {
return false;
}
@Override
public boolean keyDown(int keycode) {
System.out.println("Key down: " + keycode);
int step = 20;
int dx = 0;
int dy = 0;
if (keycode == Keys.LEFT) {
dx = -step;
}
if (keycode == Keys.RIGHT) {
dx = step;
}
if (keycode == Keys.UP) {
dy = step;
}
if (keycode == Keys.DOWN) {
dy = -step;
}
cam.translate(dx, dy);
return true;
}
});
Gdx.input.setInputProcessor(multi);
}
@Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
map.draw(batch, 1);
batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
public static void main(String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.width = 1024;
config.height = 768;
new LwjglApplication(new MapPanZoomExample(), config);
}
}
Questions:
- zoom works fine, but how to translate/scale coordinates on screen when map is scaled ?
- why If user try to move the map using keyboard, nothing moves ? see row 96 - 112
- how to implement to move the map when mouse is “near” borders ?
- order in render() method is fine ? see row 122
thanks in advance!