diff options
author | Jérémy Zurcher <jeremy@asynk.ch> | 2018-06-28 16:24:06 +0200 |
---|---|---|
committer | Jérémy Zurcher <jeremy@asynk.ch> | 2018-06-28 16:24:06 +0200 |
commit | afa5db087cb0fc28223712cfc4ac4612504bdd69 (patch) | |
tree | 8575070b58c49ecae2f1a43fb0dae919f2df4c3d /core/src/ch/asynk/zproject | |
parent | dd3232a74ab4b5f0d353d717cf3f080a73528a6e (diff) | |
download | gdx-boardgame-afa5db087cb0fc28223712cfc4ac4612504bdd69.zip gdx-boardgame-afa5db087cb0fc28223712cfc4ac4612504bdd69.tar.gz |
implement GameScreen and GameCamera
Diffstat (limited to 'core/src/ch/asynk/zproject')
-rw-r--r-- | core/src/ch/asynk/zproject/Board.java | 36 | ||||
-rw-r--r-- | core/src/ch/asynk/zproject/Hud.java | 40 | ||||
-rw-r--r-- | core/src/ch/asynk/zproject/ZProject.java | 95 | ||||
-rw-r--r-- | core/src/ch/asynk/zproject/screens/GameCamera.java | 211 | ||||
-rw-r--r-- | core/src/ch/asynk/zproject/screens/GameScreen.java | 162 |
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; + } +} |