From 80b5a3ee896d450525ac129c3442f0ec792523d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Fri, 19 Sep 2014 09:49:38 +0200 Subject: MapImage->MapNode, PawnImage->PawnNode, add Layer --- core/src/ch/asynk/tankontank/engine/Layer.java | 119 +++++++++++++ core/src/ch/asynk/tankontank/engine/Map.java | 11 +- core/src/ch/asynk/tankontank/engine/MapImage.java | 167 ------------------ core/src/ch/asynk/tankontank/engine/MapNode.java | 193 +++++++++++++++++++++ core/src/ch/asynk/tankontank/engine/Pawn.java | 27 ++- core/src/ch/asynk/tankontank/engine/PawnImage.java | 73 -------- core/src/ch/asynk/tankontank/engine/PawnNode.java | 85 +++++++++ core/src/ch/asynk/tankontank/game/GameFactory.java | 6 +- core/src/ch/asynk/tankontank/game/Unit.java | 4 +- 9 files changed, 416 insertions(+), 269 deletions(-) create mode 100644 core/src/ch/asynk/tankontank/engine/Layer.java delete mode 100644 core/src/ch/asynk/tankontank/engine/MapImage.java create mode 100644 core/src/ch/asynk/tankontank/engine/MapNode.java delete mode 100644 core/src/ch/asynk/tankontank/engine/PawnImage.java create mode 100644 core/src/ch/asynk/tankontank/engine/PawnNode.java diff --git a/core/src/ch/asynk/tankontank/engine/Layer.java b/core/src/ch/asynk/tankontank/engine/Layer.java new file mode 100644 index 0000000..76f99c0 --- /dev/null +++ b/core/src/ch/asynk/tankontank/engine/Layer.java @@ -0,0 +1,119 @@ +package ch.asynk.tankontank.engine; + +import java.util.LinkedList; +import java.util.Vector; +import java.util.Iterator; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.utils.viewport.Viewport; + +import ch.asynk.tankontank.engine.gfx.Node; +import ch.asynk.tankontank.engine.gfx.Animation; + +public class Layer +{ + public boolean visible; + private final Viewport viewport; + private final Batch batch; + private final Vector animations = new Vector(5); + private final Vector nextAnimations = new Vector(2); + private final LinkedList nodes = new LinkedList(); + + public Layer(Viewport viewport) + { + this.visible = true; + this.viewport = viewport; + this.batch = new SpriteBatch(); + viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true); + } + + public void resize(int width, int height) + { + viewport.update(width, height); + } + + public void addNode(Node node) + { + node.setLayer(this); + nodes.add(node); + } + + public boolean removeNode(Node node) + { + node.setLayer(null); + return nodes.remove(node); + } + + public void goOnTop(Node node) + { + nodes.remove(node); + node.setLayer(this); + nodes.add(node); + } + + public void addAnimation(Animation animation) + { + nextAnimations.add(animation); + } + + public void act() + { + act(Math.min(Gdx.graphics.getDeltaTime(), (1 / 30f))); + } + + public void act(float delta) + { + Iterator iter; + + iter = animations.iterator(); + while (iter.hasNext()) { + Animation a = iter.next(); + Node n = a.getNode(); + if (n != null) + goOnTop(n); + if (a.act(delta)) iter.remove(); + } + + for (int i = 0, n = nodes.size(); i < n; i++) + nodes.get(i).act(delta); + + for (int i = 0, n = nextAnimations.size(); i < n; i++) + animations.add(nextAnimations.get(i)); + nextAnimations.clear(); + } + + public void draw() + { + Camera camera = viewport.getCamera(); + camera.update(); + if (!visible) return; + Batch batch = this.batch; + if (batch != null) { + batch.setProjectionMatrix(camera.combined); + batch.begin(); + for (int i = 0, n = nodes.size(); i < n; i++) + nodes.get(i).draw(batch, 1); + batch.end(); + } + } + + public void clear() + { + for (int i = 0, n = nodes.size(); i < n; i++) + nodes.get(i).clear(); + nodes.clear(); + + for (int i = 0, n = animations.size(); i < n; i++) + animations.get(i).free(); + animations.clear(); + + for (int i = 0, n = nextAnimations.size(); i < n; i++) + nextAnimations.get(i).free(); + nextAnimations.clear(); + + batch.dispose(); + } +} diff --git a/core/src/ch/asynk/tankontank/engine/Map.java b/core/src/ch/asynk/tankontank/engine/Map.java index 771e2c9..7364c9d 100644 --- a/core/src/ch/asynk/tankontank/engine/Map.java +++ b/core/src/ch/asynk/tankontank/engine/Map.java @@ -4,15 +4,10 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.GridPoint2; -public interface Map -{ - // libgdx - - public float getWidth(); - public float getHeight(); - - // game +import ch.asynk.tankontank.engine.gfx.Node; +public interface Map extends Node +{ public GridPoint2 getHexAt(GridPoint2 hex, float x, float y); public Pawn getTopPawnAt(GridPoint2 hex); diff --git a/core/src/ch/asynk/tankontank/engine/MapImage.java b/core/src/ch/asynk/tankontank/engine/MapImage.java deleted file mode 100644 index 2b80974..0000000 --- a/core/src/ch/asynk/tankontank/engine/MapImage.java +++ /dev/null @@ -1,167 +0,0 @@ -package ch.asynk.tankontank.engine; - -import com.badlogic.gdx.Gdx; - -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.scenes.scene2d.ui.Image; - -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.math.Vector3; -import com.badlogic.gdx.math.GridPoint2; - -public class MapImage extends Image implements Map -{ - private Map.Config cfg; - private int cols; - private int rows; - private Tile[][] board; - - @SuppressWarnings("unchecked") - public MapImage(Map.Config cfg, Tile[][] board, Texture texture) - { - super(texture); - this.cfg = cfg; - this.board = board; - this.cols = cfg.cols - 1; - this.rows = cfg.rows - 1; - } - - public Pawn getTopPawnAt(GridPoint2 cell) - { - return getTopPawnAt(cell.x, cell.y); - } - - private Pawn getTopPawnAt(int col, int row) - { - // if ((col < 0) || (row < 0)) throw new (); - return board[row][col].getTop(); - } - - private int pushPawnAt(Pawn pawn, int col, int row) - { - // if ((col < 0) || (row < 0)) throw new (); - return board[row][col].push(pawn); - } - - private void removePawnFrom(Pawn pawn, int col, int row) - { - // if ((col < 0) || (row < 0)) throw new (); - board[row][col].remove(pawn); - } - - public Vector2 getHexCenterAt(GridPoint2 cell) - { - float x = cfg.x0 + ((cell.x * cfg.w) + (cfg.w / 2)); - float y = cfg.y0 + ((cell.y * cfg.h) + (cfg.s / 2)); - if ((cell.y % 2) == 1) x += cfg.dw; - return new Vector2(x, y); - } - - public Vector2 getPawnPosAt(Pawn pawn, GridPoint2 cell) - { - return getPawnPosAt(pawn, cell.x, cell.y); - } - - private Vector2 getPawnPosAt(Pawn pawn, int col, int row) - { - float x = cfg.x0 + ((col * cfg.w) + ((cfg.w - pawn.getHeight()) / 2)); - float y = cfg.y0 + ((row * cfg.h) + ((cfg.s - pawn.getWidth()) / 2)); - if ((row % 2) == 1) x += cfg.dw; - return new Vector2(x, y); - } - - public void movePawnTo(Pawn pawn, Vector3 coords) - { - GridPoint2 p = getHexAt(null, coords.x, coords.y); - movePawnTo(pawn, p.x, p.y, Pawn.Orientation.KEEP); - } - - public void setPawnAt(final Pawn pawn, final int col, final int row, Pawn.Orientation o) - { - int z = pushPawnAt(pawn, col, row); - Vector2 pos = getPawnPosAt(pawn, col, row); - pawn.pushMove(pos.x, pos.y, z, o); - } - - public void movePawnTo(final Pawn pawn, final int col, final int row, Pawn.Orientation o) - { - GridPoint2 prev = getHexAt(pawn.getLastPosition()); - // if (prev == null) throw new (); - removePawnFrom(pawn, prev.x, prev.y); - - if ((col < 0) || (row < 0)) { - pawn.resetMoves(new Runnable() { - @Override - public void run() { - GridPoint2 hex = getHexAt(pawn.getLastPosition()); - pawn.setZIndex(pushPawnAt(pawn, hex.x, hex.y)); - } - }); - return; - } else { - int z = pushPawnAt(pawn, col, row); - Vector2 pos = getPawnPosAt(pawn, col, row); - pawn.pushMove(pos.x, pos.y, z, o); - } - } - - private GridPoint2 getHexAt(Vector3 v) - { - if (v == null) return null; - return getHexAt(null, v.x, v.y); - } - - public GridPoint2 getHexAt(GridPoint2 hex, float cx, float cy) - { - if (hex == null) hex = new GridPoint2(); - - // compute row - int row; - boolean oddRow = true; - float y = (cy - cfg.y0); - if (y < 0.f) { - row = -1; - } else { - row = (int) (y / cfg.h); - oddRow = ((row % 2) == 1); - } - - // compute col - int col; - float x = (cx - cfg.x0); - if (oddRow) x -= cfg.dw; - if (x < 0.f) { - col = -1; - } else { - col = (int) (x / cfg.w); - } - - // check upper boundaries - float dy = (y - (row * cfg.h)); - if (dy > cfg.s) { - dy -= cfg.s; - float dx = (x - (col * cfg.w)); - if (dx < cfg.dw) { - if ((dx * cfg.slope) < dy) { - row += 1; - if (!oddRow) col -= 1; - oddRow = !oddRow; - } - } else { - if (((cfg.w - dx) * cfg.slope) < dy) { - row += 1; - if (oddRow) col += 1; - oddRow = !oddRow; - } - } - } - - // validate hex - if ((col < 0) || (row < 0) || (row > rows) || (col > cols) || (oddRow && ((col +1)> cols))) - hex.set(-1, -1); - else - hex.set(col, row); - - return hex; - } -} diff --git a/core/src/ch/asynk/tankontank/engine/MapNode.java b/core/src/ch/asynk/tankontank/engine/MapNode.java new file mode 100644 index 0000000..10b5ad5 --- /dev/null +++ b/core/src/ch/asynk/tankontank/engine/MapNode.java @@ -0,0 +1,193 @@ +package ch.asynk.tankontank.engine; + +import com.badlogic.gdx.Gdx; + +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.math.GridPoint2; + +import ch.asynk.tankontank.engine.gfx.TextureDrawable; +import ch.asynk.tankontank.engine.gfx.animations.AnimationSequence; +import ch.asynk.tankontank.engine.gfx.animations.RunnableAnimation; + +public class MapNode extends TextureDrawable implements Map +{ + private Layer layer; + private Map.Config cfg; + private int cols; + private int rows; + private Tile[][] board; + + public MapNode(Map.Config cfg, Tile[][] board, Texture texture) + { + super(texture); + this.cfg = cfg; + this.board = board; + this.cols = cfg.cols - 1; + this.rows = cfg.rows - 1; + } + + @Override + public void setLayer(Layer layer) + { + this.layer = layer; + } + + @Override + public void clear() + { + dispose(); + } + + @Override + public void act(float delta) + { + } + + @Override + public Pawn getTopPawnAt(GridPoint2 cell) + { + return getTopPawnAt(cell.x, cell.y); + } + + private Pawn getTopPawnAt(int col, int row) + { + return board[row][col].getTop(); + } + + private int pushPawnAt(Pawn pawn, int col, int row) + { + return board[row][col].push(pawn); + } + + private void removePawnFrom(Pawn pawn, int col, int row) + { + board[row][col].remove(pawn); + } + + @Override + public Vector2 getHexCenterAt(GridPoint2 cell) + { + float x = cfg.x0 + ((cell.x * cfg.w) + (cfg.w / 2)); + float y = cfg.y0 + ((cell.y * cfg.h) + (cfg.s / 2)); + if ((cell.y % 2) == 1) x += cfg.dw; + return new Vector2(x, y); + } + + @Override + public Vector2 getPawnPosAt(Pawn pawn, GridPoint2 cell) + { + return getPawnPosAt(pawn, cell.x, cell.y); + } + + private Vector2 getPawnPosAt(Pawn pawn, int col, int row) + { + float x = cfg.x0 + ((col * cfg.w) + ((cfg.w - pawn.getHeight()) / 2)); + float y = cfg.y0 + ((row * cfg.h) + ((cfg.s - pawn.getWidth()) / 2)); + if ((row % 2) == 1) x += cfg.dw; + return new Vector2(x, y); + } + + @Override + public void movePawnTo(Pawn pawn, Vector3 coords) + { + GridPoint2 p = getHexAt(null, coords.x, coords.y); + movePawnTo(pawn, p.x, p.y, Pawn.Orientation.KEEP); + } + + @Override + public void setPawnAt(final Pawn pawn, final int col, final int row, Pawn.Orientation o) + { + int z = pushPawnAt(pawn, col, row); + Vector2 pos = getPawnPosAt(pawn, col, row); + pawn.pushMove(pos.x, pos.y, z, o); + } + + @Override + public void movePawnTo(final Pawn pawn, final int col, final int row, Pawn.Orientation o) + { + GridPoint2 prev = getHexAt(pawn.getLastPosition()); + removePawnFrom(pawn, prev.x, prev.y); + + if ((col < 0) || (row < 0)) { + AnimationSequence seq = pawn.getResetMovesAnimation(); + seq.addAnimation(RunnableAnimation.get(new Runnable() { + @Override + public void run() { + GridPoint2 hex = getHexAt(pawn.getLastPosition()); + pushPawnAt(pawn, hex.x, hex.y); + } + })); + layer.addAnimation(seq); + } else { + int z = pushPawnAt(pawn, col, row); + Vector2 pos = getPawnPosAt(pawn, col, row); + pawn.pushMove(pos.x, pos.y, z, o); + } + } + + private GridPoint2 getHexAt(Vector3 v) + { + if (v == null) return null; + return getHexAt(null, v.x, v.y); + } + + @Override + public GridPoint2 getHexAt(GridPoint2 hex, float cx, float cy) + { + if (hex == null) hex = new GridPoint2(); + + // compute row + int row; + boolean oddRow = true; + float y = (cy - cfg.y0); + if (y < 0.f) { + row = -1; + } else { + row = (int) (y / cfg.h); + oddRow = ((row % 2) == 1); + } + + // compute col + int col; + float x = (cx - cfg.x0); + if (oddRow) x -= cfg.dw; + if (x < 0.f) { + col = -1; + } else { + col = (int) (x / cfg.w); + } + + // check upper boundaries + float dy = (y - (row * cfg.h)); + if (dy > cfg.s) { + dy -= cfg.s; + float dx = (x - (col * cfg.w)); + if (dx < cfg.dw) { + if ((dx * cfg.slope) < dy) { + row += 1; + if (!oddRow) col -= 1; + oddRow = !oddRow; + } + } else { + if (((cfg.w - dx) * cfg.slope) < dy) { + row += 1; + if (oddRow) col += 1; + oddRow = !oddRow; + } + } + } + + // validate hex + if ((col < 0) || (row < 0) || (row > rows) || (col > cols) || (oddRow && ((col +1)> cols))) + hex.set(-1, -1); + else + hex.set(col, row); + + return hex; + } +} + diff --git a/core/src/ch/asynk/tankontank/engine/Pawn.java b/core/src/ch/asynk/tankontank/engine/Pawn.java index bcd1966..3d2c782 100644 --- a/core/src/ch/asynk/tankontank/engine/Pawn.java +++ b/core/src/ch/asynk/tankontank/engine/Pawn.java @@ -2,35 +2,30 @@ package ch.asynk.tankontank.engine; import com.badlogic.gdx.math.Vector3; -public interface Pawn -{ - // libgdx - - public float getWidth(); - public float getHeight(); - public void setZIndex(int z); - - // game +import ch.asynk.tankontank.engine.gfx.Node; +import ch.asynk.tankontank.engine.gfx.animations.AnimationSequence; +public interface Pawn extends Node +{ public Vector3 getLastPosition(); public void moveBy(float x, float y); public void pushMove(float x, float y, int z, Pawn.Orientation o); - public void resetMoves(Runnable cb); + public AnimationSequence getResetMovesAnimation(); public void moveDone(); public enum Orientation { KEEP(0), - WEST(-90), - NORTH_WEST(-30), - NORTH_EAST (30), - EAST(90), - SOUTH_EAST(150), - SOUTH_WEST(-150); + WEST(180), + NORTH_WEST(120), + NORTH_EAST (60), + EAST(0), + SOUTH_EAST(-60), + SOUTH_WEST(-120); public final int v; Orientation(int v) { this.v = v; } diff --git a/core/src/ch/asynk/tankontank/engine/PawnImage.java b/core/src/ch/asynk/tankontank/engine/PawnImage.java deleted file mode 100644 index d092028..0000000 --- a/core/src/ch/asynk/tankontank/engine/PawnImage.java +++ /dev/null @@ -1,73 +0,0 @@ -package ch.asynk.tankontank.engine; - -import java.util.ArrayDeque; - -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.scenes.scene2d.ui.Image; -import com.badlogic.gdx.scenes.scene2d.actions.Actions; -import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction; - -import com.badlogic.gdx.math.Vector3; - -public class PawnImage extends Image implements Pawn -{ - private static final float MOVE_TIME = 0.3f; - private static final float ROTATE_TIME = 0.2f; - - private ArrayDeque path = new ArrayDeque(); - - public PawnImage(TextureRegion region) - { - super(region); - setOrigin((getWidth() / 2.f), (getHeight() / 2.f)); - } - - public Vector3 getLastPosition() - { - if ((path == null) || (path.size() == 0)) return null; - return path.getFirst(); - } - - public void pushMove(float x, float y, int z, Pawn.Orientation r) - { - setPosition(x, y); - if (r != Pawn.Orientation.KEEP) setRotation(r.v); - setZIndex(z); - Vector3 v = new Vector3(x, y, r.v); - if ((path.size() == 0) || (!v.equals(path.getFirst()))) - path.push(new Vector3(x, y, r.v)); - } - - public void resetMoves(Runnable cb) - { - final Vector3 finalPos = path.getLast(); - - SequenceAction seq = new SequenceAction(); - - while(path.size() != 0) { - Vector3 v = path.pop(); - seq.addAction(Actions.moveTo(v.x, v.y, MOVE_TIME)); - if (v.z != Pawn.Orientation.KEEP.v) - seq.addAction(Actions.rotateTo(v.z, ROTATE_TIME)); - } - - seq.addAction( Actions.run(new Runnable() { - @Override - public void run() { - path.push(finalPos); - } - })); - - // the map must finalize this move - seq.addAction(Actions.run(cb)); - - addAction(seq); - } - - public void moveDone() - { - Vector3 v = path.pop(); - path.clear(); - path.push(v); - } -} diff --git a/core/src/ch/asynk/tankontank/engine/PawnNode.java b/core/src/ch/asynk/tankontank/engine/PawnNode.java new file mode 100644 index 0000000..bf3287b --- /dev/null +++ b/core/src/ch/asynk/tankontank/engine/PawnNode.java @@ -0,0 +1,85 @@ +package ch.asynk.tankontank.engine; + +import java.util.ArrayDeque; + +import com.badlogic.gdx.graphics.g2d.TextureRegion; + +import com.badlogic.gdx.math.Vector3; + +import ch.asynk.tankontank.engine.gfx.TextureRegionDrawable; +import ch.asynk.tankontank.engine.gfx.animations.MoveToAnimation; +import ch.asynk.tankontank.engine.gfx.animations.RunnableAnimation; +import ch.asynk.tankontank.engine.gfx.animations.AnimationSequence; + +public class PawnNode extends TextureRegionDrawable implements Pawn +{ + private static final float MOVE_TIME = 0.3f; + private static final float ROTATE_TIME = 0.2f; + + private Layer layer; + private ArrayDeque path = new ArrayDeque(); + + public PawnNode(TextureRegion region) + { + super(region); + } + + @Override + public void setLayer(Layer layer) + { + this.layer = layer; + } + + @Override + public void clear() + { + dispose(); + } + + @Override + public void act(float delta) + { + } + + public Vector3 getLastPosition() + { + if ((path == null) || (path.size() == 0)) return null; + return path.getFirst(); + } + + public void pushMove(float x, float y, int z, Pawn.Orientation r) + { + setCoords(x, y, z); + if (r != Pawn.Orientation.KEEP) setRotation(r.v); + Vector3 v = new Vector3(x, y, r.v); + if ((path.size() == 0) || (!v.equals(path.getFirst()))) + path.push(new Vector3(x, y, r.v)); + } + + public AnimationSequence getResetMovesAnimation() + { + final Vector3 finalPos = path.getLast(); + + AnimationSequence seq = AnimationSequence.get(path.size() + 1); + + while(path.size() != 0) { + seq.addAnimation(MoveToAnimation.get(this, path.pop(), MOVE_TIME)); + } + + seq.addAnimation(RunnableAnimation.get(new Runnable() { + @Override + public void run() { + path.push(finalPos); + } + })); + + return seq; + } + + public void moveDone() + { + Vector3 v = path.pop(); + path.clear(); + path.push(v); + } +} diff --git a/core/src/ch/asynk/tankontank/game/GameFactory.java b/core/src/ch/asynk/tankontank/game/GameFactory.java index f5c113c..8716c49 100644 --- a/core/src/ch/asynk/tankontank/game/GameFactory.java +++ b/core/src/ch/asynk/tankontank/game/GameFactory.java @@ -6,7 +6,7 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.g2d.TextureRegion; import ch.asynk.tankontank.engine.Map; -import ch.asynk.tankontank.engine.MapImage; +import ch.asynk.tankontank.engine.MapNode; import ch.asynk.tankontank.engine.Tile; public class GameFactory @@ -139,10 +139,10 @@ public class GameFactory Map m = null; switch(t) { case MAP_A: - m = new MapImage(config(), board, manager.get("images/map_a.png", Texture.class)); + m = new MapNode(config(), board, manager.get("images/map_a.png", Texture.class)); break; case MAP_B: - m = new MapImage(config(), board, manager.get("images/map_b.png", Texture.class)); + m = new MapNode(config(), board, manager.get("images/map_b.png", Texture.class)); break; } diff --git a/core/src/ch/asynk/tankontank/game/Unit.java b/core/src/ch/asynk/tankontank/game/Unit.java index 61833eb..310ead9 100644 --- a/core/src/ch/asynk/tankontank/game/Unit.java +++ b/core/src/ch/asynk/tankontank/game/Unit.java @@ -2,9 +2,9 @@ package ch.asynk.tankontank.game; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import ch.asynk.tankontank.engine.PawnImage; +import ch.asynk.tankontank.engine.PawnNode; -public class Unit extends PawnImage +public class Unit extends PawnNode { public int rng; public int def; -- cgit v1.1-2-g2b99