summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJérémy Zurcher <jeremy@asynk.ch>2018-06-28 16:24:06 +0200
committerJérémy Zurcher <jeremy@asynk.ch>2018-06-28 16:24:06 +0200
commitafa5db087cb0fc28223712cfc4ac4612504bdd69 (patch)
tree8575070b58c49ecae2f1a43fb0dae919f2df4c3d /core
parentdd3232a74ab4b5f0d353d717cf3f080a73528a6e (diff)
downloadgdx-boardgame-afa5db087cb0fc28223712cfc4ac4612504bdd69.zip
gdx-boardgame-afa5db087cb0fc28223712cfc4ac4612504bdd69.tar.gz
implement GameScreen and GameCamera
Diffstat (limited to 'core')
-rw-r--r--core/src/ch/asynk/zproject/Board.java36
-rw-r--r--core/src/ch/asynk/zproject/Hud.java40
-rw-r--r--core/src/ch/asynk/zproject/ZProject.java95
-rw-r--r--core/src/ch/asynk/zproject/screens/GameCamera.java211
-rw-r--r--core/src/ch/asynk/zproject/screens/GameScreen.java162
5 files changed, 515 insertions, 29 deletions
diff --git a/core/src/ch/asynk/zproject/Board.java b/core/src/ch/asynk/zproject/Board.java
new file mode 100644
index 0000000..a9badbd
--- /dev/null
+++ b/core/src/ch/asynk/zproject/Board.java
@@ -0,0 +1,36 @@
+package ch.asynk.zproject;
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.math.Rectangle;
+import com.badlogic.gdx.utils.Disposable;
+
+public class Board implements Disposable
+{
+ private final Texture map;
+
+ public Board()
+ {
+ this.map = new Texture("data/map_00.png");
+ }
+
+ @Override public void dispose()
+ {
+ map.dispose();
+ }
+
+ public int getWidth()
+ {
+ return map.getWidth();
+ }
+
+ public int getHeight()
+ {
+ return map.getHeight();
+ }
+
+ public void draw(SpriteBatch batch, Rectangle viewPort)
+ {
+ batch.draw(map, 0, 0);
+ }
+}
diff --git a/core/src/ch/asynk/zproject/Hud.java b/core/src/ch/asynk/zproject/Hud.java
new file mode 100644
index 0000000..ded7981
--- /dev/null
+++ b/core/src/ch/asynk/zproject/Hud.java
@@ -0,0 +1,40 @@
+package ch.asynk.zproject;
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.graphics.g2d.Sprite;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.math.Rectangle;
+import com.badlogic.gdx.utils.Disposable;
+
+public class Hud implements Disposable
+{
+ private final Sprite hud;
+
+ public Hud()
+ {
+ this.hud = new Sprite(new Texture("data/corner.png"));
+ }
+
+ @Override public void dispose()
+ {
+ hud.getTexture().dispose();
+ }
+
+ public void draw(SpriteBatch batch, final Rectangle rect)
+ {
+ float right = rect.x + rect.width - hud.getWidth();
+ float top = rect.y + rect.height - hud.getHeight();
+ hud.setRotation(0);
+ hud.setPosition(rect.x, top);
+ hud.draw(batch);
+ hud.setRotation(90);
+ hud.setPosition(rect.x, rect.y);
+ hud.draw(batch);
+ hud.setRotation(180);
+ hud.setPosition(right, rect.y);
+ hud.draw(batch);
+ hud.setPosition(right, top);
+ hud.setRotation(270);
+ hud.draw(batch);
+ }
+}
diff --git a/core/src/ch/asynk/zproject/ZProject.java b/core/src/ch/asynk/zproject/ZProject.java
index 11764d6..cd25e65 100644
--- a/core/src/ch/asynk/zproject/ZProject.java
+++ b/core/src/ch/asynk/zproject/ZProject.java
@@ -1,33 +1,70 @@
package ch.asynk.zproject;
-import com.badlogic.gdx.ApplicationAdapter;
+import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.graphics.GL20;
-import com.badlogic.gdx.graphics.Texture;
-import com.badlogic.gdx.graphics.g2d.SpriteBatch;
-
-public class ZProject extends ApplicationAdapter {
- SpriteBatch batch;
- Texture img;
-
- @Override
- public void create () {
- batch = new SpriteBatch();
- img = new Texture("badlogic.jpg");
- }
-
- @Override
- public void render () {
- Gdx.gl.glClearColor(1, 0, 0, 1);
- Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
- batch.begin();
- batch.draw(img, 0, 0);
- batch.end();
- }
-
- @Override
- public void dispose () {
- batch.dispose();
- img.dispose();
- }
+import com.badlogic.gdx.Screen;
+
+import ch.asynk.zproject.screens.GameScreen;
+
+public class ZProject extends Game
+{
+ public static final String DOM = "ZProject";
+
+ private enum State
+ {
+ NONE,
+ GAME
+ }
+ private State state;
+
+ @Override public void create()
+ {
+ this.state = State.NONE;
+ Gdx.app.setLogLevel(Gdx.app.LOG_DEBUG);
+ debug(String.format("create() [%d;%d] %f", Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Gdx.graphics.getDensity()));
+ switchToGame();
+ }
+
+ @Override public void dispose()
+ {
+ switchToNone();
+ }
+
+ public static void error(String msg)
+ {
+ Gdx.app.error(DOM, msg);
+ }
+
+ public static void debug(String msg)
+ {
+ Gdx.app.debug(DOM, msg);
+ }
+
+ public static void debug(String from, String msg)
+ {
+ Gdx.app.debug(DOM, String.format("%s : %s", from, msg));
+ }
+
+ private void switchTo(Screen nextScreen, State nextState)
+ {
+ if (state == nextState) {
+ error("switch from and to " + state);
+ return;
+ }
+ if (state != State.NONE) {
+ getScreen().dispose();
+ }
+ setScreen(nextScreen);
+ this.state = nextState;
+ }
+
+ public void switchToNone()
+ {
+ switchTo(null, State.NONE);
+ }
+
+ public void switchToGame()
+ {
+ switchTo(new GameScreen(this), State.GAME);
+ }
}
diff --git a/core/src/ch/asynk/zproject/screens/GameCamera.java b/core/src/ch/asynk/zproject/screens/GameCamera.java
new file mode 100644
index 0000000..e735bb5
--- /dev/null
+++ b/core/src/ch/asynk/zproject/screens/GameCamera.java
@@ -0,0 +1,211 @@
+package ch.asynk.zproject.screens;
+
+import com.badlogic.gdx.graphics.glutils.HdpiUtils;
+import com.badlogic.gdx.graphics.OrthographicCamera;
+
+import com.badlogic.gdx.math.Rectangle;
+import com.badlogic.gdx.math.Vector3;
+import com.badlogic.gdx.math.MathUtils;
+import com.badlogic.gdx.math.Matrix4;
+
+public class GameCamera extends OrthographicCamera
+{
+ private static final float ZEROF = 0.01f;
+
+ private int padding;
+ private float boardWidth;
+ private float boardHeight;
+ private float boardAspectRatio;
+ private float zoomMax;
+ private float zoomMin;
+ private int screenWidth;
+ private int screenHeight;
+ private float widthFactor;
+ private float heightFactor;
+ private Rectangle viewport;
+
+ private Rectangle hud;
+ private Matrix4 hudMatrix;
+ private Matrix4 hudInvProjMatrix;
+ private int hudLeft;
+ private int hudBottom;
+ private boolean hudInBoard;
+
+ public GameCamera(int padding, float boardWidth, float boardHeight, float zoomMax, float zoomMin, boolean hudInBoard)
+ {
+ super(boardWidth, boardHeight);
+ this.boardWidth = boardWidth;
+ this.boardHeight = boardHeight;
+ this.padding = padding;
+ this.boardAspectRatio = (boardWidth / boardHeight);
+ this.zoomMax = zoomMax;
+ this.zoomMin = zoomMin;
+ this.viewport = new Rectangle();
+
+ this.hudInBoard = hudInBoard;
+ this.hud = new Rectangle();
+ this.hudMatrix = new Matrix4();
+ this.hudInvProjMatrix = new Matrix4();
+ }
+
+ public void updateViewport(int screenWidth, int screenHeight)
+ {
+ this.screenWidth = screenWidth;
+ this.screenHeight = screenHeight;
+
+ float screenAvailableWidth = screenWidth - (2 * padding);
+ float screenAvailableHeight = screenHeight - (2 * padding);
+ float screenAspectRatio = (screenWidth / (float) screenHeight);
+ float diff = (boardAspectRatio - screenAspectRatio);
+
+ if (diff <= -ZEROF) {
+ // screen wider than board : use max height, width grows up until max available on zooming
+ viewport.height = screenAvailableHeight;
+ viewport.width = java.lang.Math.min((screenAvailableHeight * boardAspectRatio / zoom), screenAvailableWidth);
+ viewport.x = padding + ((screenAvailableWidth - viewport.width) / 2f);
+ viewport.y = padding;
+ // camera aspect ratio must follow viewport aspect ration
+ viewportHeight = boardHeight;
+ viewportWidth = (viewportHeight * (viewport.width / viewport.height));
+ // hud
+ hud.y = 0;
+ hud.x = (hud.y * viewportWidth / viewportHeight);
+ } else if (diff > ZEROF) {
+ // word is wider than screen : use max width, height grows up until max available on zooming
+ viewport.width = screenAvailableWidth;
+ viewport.height = java.lang.Math.min((screenAvailableWidth / boardAspectRatio / zoom), screenAvailableHeight);
+ viewport.y = padding + ((screenAvailableHeight - viewport.height) / 2f);
+ viewport.x = padding;
+ // camera aspect ratio must follow viewport aspect ration
+ viewportWidth = boardWidth;
+ viewportHeight = (viewportWidth * (viewport.height / viewport.width));
+ // hud
+ hud.x = 0;
+ hud.y = (hud.x * viewportHeight / viewportWidth);
+ }
+
+ if (hudInBoard) {
+ hud.x = 0;
+ hud.y = 0;
+ hud.width = screenWidth;
+ hud.height = screenHeight;
+ } else {
+ hud.width = (viewport.width - (2 * hud.x));
+ hud.height = (viewport.height - (2 * hud.y));
+ }
+
+ // ratio viewport -> camera
+ widthFactor = (viewportWidth / viewport.width);
+ heightFactor = (viewportHeight / viewport.height);
+
+ clampPosition();
+ update(true);
+
+ hudMatrix.setToOrtho2D(hud.x, hud.y, hud.width, hud.height);
+ hudInvProjMatrix.set(hudMatrix);
+ Matrix4.inv(hudInvProjMatrix.val);
+ }
+
+ public void applyMapViewport()
+ {
+ HdpiUtils.glViewport((int)viewport.x, (int)viewport.y, (int)viewport.width, (int)viewport.height);
+ }
+
+ public void applyHudViewport()
+ {
+ if (hudInBoard)
+ HdpiUtils.glViewport(0, 0, screenWidth, screenHeight);
+ else
+ applyMapViewport();
+ }
+
+ public void centerOnWorld()
+ {
+ position.set((boardWidth / 2f), (boardHeight / 2f), 0f);
+ }
+
+ public void zoom(float dz)
+ {
+ zoom += dz;
+ clampZoom();
+ updateViewport(screenWidth, screenHeight); // zoom impacts viewport
+ }
+
+ public void clampZoom()
+ {
+ zoom = MathUtils.clamp(zoom, zoomMin, zoomMax);
+ }
+
+ public void translate(float dx, float dy)
+ {
+ float deltaX = (dx * zoom * widthFactor);
+ float deltaY = (dy * zoom * heightFactor);
+ translate(deltaX, -deltaY, 0);
+ clampPosition();
+ update(true);
+ }
+
+ public void clampPosition()
+ {
+ float cameraWidth = (viewportWidth * zoom);
+ float cameraHeight = (viewportHeight * zoom);
+
+ // on each axis, clamp on [ cameraDim/2 ; boardDim - cameraDim/2 ]
+
+ if ((boardWidth - cameraWidth) > ZEROF) {
+ cameraWidth /= 2f;
+ position.x = MathUtils.clamp(position.x, cameraWidth, (boardWidth - cameraWidth));
+ } else {
+ position.x = (boardWidth / 2f);
+ }
+
+ if ((boardHeight - cameraHeight) > ZEROF) {
+ cameraHeight /= 2f;
+ position.y = MathUtils.clamp(position.y, cameraHeight, (boardHeight - cameraHeight));
+ } else {
+ position.y = (boardHeight / 2f);
+ }
+ }
+
+ public void unproject(int x, int y, Vector3 v)
+ {
+ unproject(v.set(x, y, 0), viewport.x, viewport.y, viewport.width, viewport.height);
+ }
+
+ public void unprojectHud(float x, float y, Vector3 v)
+ {
+ Rectangle r = (hudInBoard ? hud : viewport);
+ x = x - r.x;
+ y = screenHeight - y - 1;
+ y = y - r.y;
+ v.x = (2 * x) / r.width - 1;
+ v.y = (2 * y) / r.height - 1;
+ v.z = 2 * v.z - 1;
+ v.prj(hudInvProjMatrix);
+ }
+
+ public int getScreenWidth()
+ {
+ return screenWidth;
+ }
+
+ public int getScreenHeight()
+ {
+ return screenHeight;
+ }
+
+ public Matrix4 getHudMatrix()
+ {
+ return hudMatrix;
+ }
+
+ public Rectangle getViewport()
+ {
+ return viewport;
+ }
+
+ public Rectangle getHud()
+ {
+ return hud;
+ }
+}
diff --git a/core/src/ch/asynk/zproject/screens/GameScreen.java b/core/src/ch/asynk/zproject/screens/GameScreen.java
new file mode 100644
index 0000000..425c737
--- /dev/null
+++ b/core/src/ch/asynk/zproject/screens/GameScreen.java
@@ -0,0 +1,162 @@
+package ch.asynk.zproject.screens;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Screen;
+import com.badlogic.gdx.graphics.GL20;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.Input;
+import com.badlogic.gdx.InputAdapter;
+import com.badlogic.gdx.InputMultiplexer;
+import com.badlogic.gdx.input.GestureDetector;
+import com.badlogic.gdx.input.GestureDetector.GestureAdapter;
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.math.Vector3;
+
+import ch.asynk.zproject.ZProject;
+import ch.asynk.zproject.Hud;
+import ch.asynk.zproject.Board;
+
+public class GameScreen implements Screen
+{
+ private static final float INPUT_DELAY = 0.1f; // filter out touches after gesture
+ private static final float ZOOM_SCROLL_FACTOR = .1f;
+ private static final float ZOOM_GESTURE_FACTOR = .01f;
+
+ private final ZProject zproject;
+ private final Hud hud;
+ private final Board board;
+ private final GameCamera camera;
+ private final SpriteBatch batch;
+
+ private final Vector2 dragPos = new Vector2();
+ private final Vector3 boardTouch = new Vector3();
+ private final Vector3 hudTouch = new Vector3();
+
+ private boolean paused;
+ private float inputDelay;
+ private boolean inputBlocked;
+
+ public GameScreen(final ZProject zproject)
+ {
+ this.zproject = zproject;
+ this.hud = new Hud();
+ this.board = new Board();
+ this.batch = new SpriteBatch();
+ this.camera = new GameCamera(10, board.getWidth(), board.getHeight(), 1.0f, 0.3f, false);
+ Gdx.input.setInputProcessor(getMultiplexer());
+ this.paused = false;
+ this.inputDelay = 0f;
+ this.inputBlocked = false;
+ }
+
+ @Override public void render(float delta)
+ {
+ if (paused) return;
+
+ if (inputBlocked) {
+ inputDelay -= delta;
+ if (inputDelay <= 0f)
+ inputBlocked = false;
+ }
+
+ Gdx.gl.glClearColor(0, 0, 0, 1);
+ Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
+
+ camera.applyMapViewport();
+ batch.setProjectionMatrix(camera.combined);
+ batch.begin();
+ board.draw(batch, camera.getViewport());
+ batch.end();
+
+ camera.applyHudViewport();
+ batch.setProjectionMatrix(camera.getHudMatrix());
+ batch.begin();
+ hud.draw(batch, camera.getHud());
+ batch.end();
+ }
+
+ @Override public void resize(int width, int height)
+ {
+ if (paused) return;
+ ZProject.debug("GameScreen", String.format("resize (%d,%d)",width, height));
+ camera.updateViewport(width, height);
+ }
+
+ @Override public void dispose()
+ {
+ ZProject.debug("GameScreen", "dispose()");
+ batch.dispose();
+ hud.dispose();
+ board.dispose();
+ }
+
+ @Override public void show()
+ {
+ ZProject.debug("GameScreen", "show()");
+ }
+
+ @Override public void hide()
+ {
+ ZProject.debug("GameScreen", "hide()");
+ }
+
+ @Override public void pause()
+ {
+ ZProject.debug("pause() ");
+ paused = true;
+ }
+
+ @Override public void resume()
+ {
+ ZProject.debug("resume() ");
+ paused = false;
+ resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
+ }
+
+ private InputMultiplexer getMultiplexer()
+ {
+ final InputMultiplexer multiplexer = new InputMultiplexer();
+ multiplexer.addProcessor(new InputAdapter() {
+ @Override public boolean scrolled(int amount)
+ {
+ camera.zoom(amount * ZOOM_SCROLL_FACTOR);
+ return true;
+ }
+ @Override public boolean touchDown(int x, int y, int pointer, int button)
+ {
+ if (inputBlocked) return true;
+ if (button == Input.Buttons.LEFT) {
+ dragPos.set(x, y);
+ camera.unproject(x, y, boardTouch);
+ camera.unprojectHud(x, y, hudTouch);
+ ZProject.debug("touchDown MAP : " + boardTouch);
+ ZProject.debug("touchDown HUD : " + hudTouch);
+ }
+ return true;
+ }
+ @Override public boolean touchDragged(int x, int y, int pointer)
+ {
+ int dx = (int) (dragPos.x - x);
+ int dy = (int) (dragPos.y - y);
+ dragPos.set(x, y);
+ camera.translate(dx, dy);
+ return true;
+ }
+ });
+ multiplexer.addProcessor(new GestureDetector(new GestureAdapter() {
+ @Override public boolean zoom(float initialDistance, float distance)
+ {
+ if (initialDistance > distance)
+ camera.zoom(ZOOM_GESTURE_FACTOR);
+ else
+ camera.zoom(-ZOOM_GESTURE_FACTOR);
+ inputBlocked = true;
+ inputDelay = INPUT_DELAY;
+ return true;
+ }
+ }));
+
+ return multiplexer;
+ }
+}