diff options
| author | Jérémy Zurcher <jeremy@asynk.ch> | 2018-09-14 09:13:20 +0200 | 
|---|---|---|
| committer | Jérémy Zurcher <jeremy@asynk.ch> | 2018-09-14 09:13:20 +0200 | 
| commit | 76c4a8eccdc276583c215e5ad09b5fb2f07ac53e (patch) | |
| tree | 8e026033a22f2b4d3dfe02235ab40d897309321e /core/src/ch/asynk/gdx | |
| parent | a3cc66dc1fe2f468b234083baacd82a37c51fd3f (diff) | |
| download | gdx-boardgame-76c4a8eccdc276583c215e5ad09b5fb2f07ac53e.zip gdx-boardgame-76c4a8eccdc276583c215e5ad09b5fb2f07ac53e.tar.gz  | |
ch/asynk/zproject/engine -> ch/asynk/gdx/board
Diffstat (limited to 'core/src/ch/asynk/gdx')
20 files changed, 1240 insertions, 0 deletions
diff --git a/core/src/ch/asynk/gdx/board/Assets.java b/core/src/ch/asynk/gdx/board/Assets.java new file mode 100644 index 0000000..3678129 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/Assets.java @@ -0,0 +1,30 @@ +package ch.asynk.gdx.board; + +import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; + +public class Assets extends AssetManager +{ +    public Texture getTexture(String assetName) +    { +        return get(assetName, Texture.class); +    } + +    public NinePatch getNinePatch(String assetName, int left, int right, int top, int bottom) +    { +        return new NinePatch(get(assetName, Texture.class), left, right, top, bottom); +    } + +    public TextureAtlas getAtlas(String assetName) +    { +        return get(assetName, TextureAtlas.class); +    } + +    public BitmapFont getFont(String assetName) +    { +        return get(assetName, BitmapFont.class); +    } +} diff --git a/core/src/ch/asynk/gdx/board/Board.java b/core/src/ch/asynk/gdx/board/Board.java new file mode 100644 index 0000000..0089ad7 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/Board.java @@ -0,0 +1,9 @@ +package ch.asynk.gdx.board; + +import com.badlogic.gdx.math.Vector2; + +public interface Board +{ +    public void centerOf(int x, int y, Vector2 v); +    public void toBoard(float x, float y, Vector2 v); +} diff --git a/core/src/ch/asynk/gdx/board/Camera.java b/core/src/ch/asynk/gdx/board/Camera.java new file mode 100644 index 0000000..4c1a1b6 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/Camera.java @@ -0,0 +1,218 @@ +package ch.asynk.gdx.board; + +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 Camera 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 Camera(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 setDimension(float boardWidth, float boardHeight) +    { +        setToOrtho(false, boardWidth, boardHeight); +        this.boardWidth = boardWidth; +        this.boardHeight = boardHeight; +        this.boardAspectRatio = (boardWidth / boardHeight); +    } + +    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(); +    } + +    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/gdx/board/Drawable.java b/core/src/ch/asynk/gdx/board/Drawable.java new file mode 100644 index 0000000..53559dc --- /dev/null +++ b/core/src/ch/asynk/gdx/board/Drawable.java @@ -0,0 +1,19 @@ +package ch.asynk.gdx.board; + +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; + +public interface Drawable +{ +    public float getX(); +    public float getY(); +    public float getWidth(); +    public float getHeight(); +    public float getInnerX(); +    public float getInnerY(); +    public float getInnerWidth(); +    public float getInnerHeight(); +    public void draw(Batch batch); +    default public void drawDebug(ShapeRenderer debugShapes) { } +    public void setPosition(float x, float y, float w, float h); +} diff --git a/core/src/ch/asynk/gdx/board/Touchable.java b/core/src/ch/asynk/gdx/board/Touchable.java new file mode 100644 index 0000000..533ec96 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/Touchable.java @@ -0,0 +1,6 @@ +package ch.asynk.gdx.board; + +public interface Touchable +{ +    public boolean touch(float x, float y); +} diff --git a/core/src/ch/asynk/gdx/board/board/BoardFactory.java b/core/src/ch/asynk/gdx/board/board/BoardFactory.java new file mode 100644 index 0000000..fc30e72 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/board/BoardFactory.java @@ -0,0 +1,40 @@ +package ch.asynk.gdx.board.board; + +import ch.asynk.gdx.board.Board; + +public class BoardFactory +{ +    public enum BoardType +    { +        HEX, SQUARE, +    } + +    public enum BoardOrientation +    { +        VERTICAL, +        HORIZONTAL, +    } + +    public static Board getBoard(BoardType boardType, float side) +    { +        return getBoard(boardType, side, 0f, 0f, BoardOrientation.VERTICAL); +    } + +    public static Board getBoard(BoardType boardType, float side, float x0, float y0) +    { +        return getBoard(boardType, side, x0, y0, BoardOrientation.VERTICAL); +    } + +    public static Board getBoard(BoardType boardType, float side, float x0, float y0, BoardOrientation boardOrientation) +    { +        switch(boardType) +        { +            case HEX: +                return new HexBoard(side, x0, y0, boardOrientation); +            case SQUARE: +                return new SquareBoard(side, x0, y0); +            default: +                throw new RuntimeException( String.format("%s board type is not implemented yet.", boardType) ); +        } +    } +} diff --git a/core/src/ch/asynk/gdx/board/board/HexBoard.java b/core/src/ch/asynk/gdx/board/board/HexBoard.java new file mode 100644 index 0000000..9d56a7c --- /dev/null +++ b/core/src/ch/asynk/gdx/board/board/HexBoard.java @@ -0,0 +1,144 @@ +package ch.asynk.gdx.board.board; + +import com.badlogic.gdx.math.Vector2; + +import ch.asynk.gdx.board.Board; + +public class HexBoard implements Board +{ +    private float side;     // length of the side of the hex +    private float x0;       // bottom left x offset +    private float y0;       // bottom left y offset +    private BoardFactory.BoardOrientation orientation; + +    private float w;        // side to side orthogonal distance +    private float dw;       // half hex : w/2 +    private float dh;       // hex top : s/2 +    private float h;        // square height : s + dh +    private float slope;    // dh / dw + +    //  BoardOrientation.VERTICAL : 2 vertical sides : 2 vertices pointing up and down +    //  coordinates +    //  \ +    //   \___ +    //   cols are horizontal +    //   rows are at -120° +    //   bottom left is the bottom vertice of the most bottom-left vertical hex side of the map +    // +    //  BoardOrientation.HORIZONTAL : 2 horizontal sides : 2 vertices pointing left and right +    //  coordinates +    //  | +    //  | +    //   \ +    //    \ +    //   cols are at +120° +    //   rows are vertical° +    //   bottom left is the left vertice of the most bottom-left horizontal hex side of the map + +    public HexBoard(float side, float x0, float y0, BoardFactory.BoardOrientation boardOrientation) +    { +        this.side = side; +        this.x0 = x0; +        this.y0 = y0; +        this.orientation = boardOrientation; + +        this.w  = side * 1.73205f; +        this.dw = w / 2.0f; +        this.dh = side / 2.0f; +        this.h  = side + dh; +        this.slope = dh / dw; +    } + +    @Override public void centerOf(int x, int y, Vector2 v) +    { +        float cx = this.x0; +        float cy = this.y0; + +        if (this.orientation == BoardFactory.BoardOrientation.VERTICAL) { +            cx += (this.dw + (x * this.w) - (y * this.dw)); +            cy += (this.dh + (y * this.h)); +        } else { +            cx += (this.dh + (x * this.h)); +            cy += (this.dw + (y * this.w) - (x * this.dw)); +        } + +        v.set(cx, cy); +    } + +    @Override public void toBoard(float x, float y, Vector2 v) +    { +        int col = -1; +        int row = -1; + +        if (this.orientation == BoardFactory.BoardOrientation.VERTICAL) { +            // compute row +            float dy = y - this.y0; +            row = (int) (dy / this.h); +            if (dy < 0.f) { +                row -= 1; +            } + +            // compute col +            float dx = x - this.x0 + (row * this.dw); +            col = (int) (dx / this.w); +            if (dx < 0f) { +                col -= 1; +            } + +            // upper rectangle or hex body +            if (dy > ((row * this.h) + this.side)) { +                dy -= ((row * this.h) + this.side); +                dx -= (col * this.w); +                // upper left or right rectangle +                if (dx < this.dw) { +                    if (dy > (dx * this.slope)) { +                        // upper left hex +                        row += 1; +                    } +                } else { +                    // if (dy > ((2 * this.dh) - (dx * this.slope))) { +                    if (dy > ((this.w - dx) * this.slope)) { +                        // upper right hex +                        row += 1; +                        col += 1; +                    } +                } +            } +        } else { +            // compute col +            float dx = x - this.x0; +            col = (int) (dx / this.h); +            if (dx < 0.f) { +                col -= 1; +            } + +            // compute row +            float dy = y - this.y0 + (col * this.dw); +            row = (int) (dy / this.w); +            if (dy < 0f) { +                row -= 1; +            } + +            // right rectangle or hex body +            if (dx > ((col * this.h) + this.side)) { +                dx -= ((col * this.h) + this.side); +                dy -= (row * this.w); +                // upper or lower rectangle +                if (dy > ((this.dw - dx) / this.slope)) { +                    if (dy > ((2 * this.dw) - (dx / this.slope))) { +                        // upper right hex +                        col += 1; +                        row += 1; +                    } +                } else { +                    if (dy < (dx / this.slope)) { +                        // lower right hex +                        col += 1; +                    } +                } +            } +        } + +        v.set(col, row); +    } +} diff --git a/core/src/ch/asynk/gdx/board/board/SquareBoard.java b/core/src/ch/asynk/gdx/board/board/SquareBoard.java new file mode 100644 index 0000000..f8da8d3 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/board/SquareBoard.java @@ -0,0 +1,35 @@ +package ch.asynk.gdx.board.board; + +import com.badlogic.gdx.math.Vector2; + +import ch.asynk.gdx.board.Board; + +public class SquareBoard implements Board +{ +    private float side;     // length of the side of a square +    private float x0;       // bottom left x offset +    private float y0;       // bottom left y offset + +    public SquareBoard(float side, float x0, float y0) +    { +        this.side = side; +        this.x0 = x0; +        this.y0 = y0; +    } + +    @Override public void centerOf(int x, int y, Vector2 v) +    { +        float cx = this.x0 + (this.side / 2) + (this.side * x); +        float cy = this.y0 + (this.side / 2) + (this.side * y); + +        v.set(cx, cy); +    } + +    @Override public void toBoard(float x, float y, Vector2 v) +    { +        int col = (int) ((x - this.x0) / this.side); +        int row = (int) ((y - this.y0) / this.side); + +        v.set(col, row); +    } +} diff --git a/core/src/ch/asynk/gdx/board/ui/Alignment.java b/core/src/ch/asynk/gdx/board/ui/Alignment.java new file mode 100644 index 0000000..cb8f4a2 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/ui/Alignment.java @@ -0,0 +1,168 @@ +package ch.asynk.gdx.board.ui; + +public enum Alignment +{ +    ABSOLUTE,           // Root +    RELATIVE,           // Default +    TOP_LEFT, +    TOP_RIGHT, +    TOP_CENTER, +    MIDDLE_LEFT, +    MIDDLE_RIGHT, +    MIDDLE_CENTER, +    BOTTOM_LEFT, +    BOTTOM_RIGHT, +    BOTTOM_CENTER; + +    public Alignment verticalMirror() +    { +        switch(this) { +            case TOP_LEFT: +                return TOP_RIGHT; +            case MIDDLE_LEFT: +                return MIDDLE_RIGHT; +            case BOTTOM_LEFT: +                return BOTTOM_RIGHT; +            case TOP_RIGHT: +                return TOP_LEFT; +            case MIDDLE_RIGHT: +                return MIDDLE_LEFT; +            case BOTTOM_RIGHT: +                return BOTTOM_LEFT; +        } +        return this; +    } + +    public Alignment horizontalMirror() +    { +        switch(this) { +            case TOP_LEFT: +                return BOTTOM_LEFT; +            case TOP_CENTER: +                return BOTTOM_CENTER; +            case TOP_RIGHT: +                return BOTTOM_RIGHT; +            case BOTTOM_LEFT: +                return TOP_LEFT; +            case BOTTOM_CENTER: +                return TOP_CENTER; +            case BOTTOM_RIGHT: +                return TOP_RIGHT; +        } +        return this; +    } + +    public boolean isTop() +    { +        switch(this) { +            case TOP_LEFT: +            case TOP_CENTER: +            case TOP_RIGHT: +                return true; +        } +        return false; +    } + +    public boolean isMiddle() +    { +        boolean r = false; +        switch(this) { +            case MIDDLE_LEFT: +            case MIDDLE_CENTER: +            case MIDDLE_RIGHT: +                return true; +        } +        return false; +    } + +    public boolean isBottom() +    { +        boolean r = false; +        switch(this) { +            case BOTTOM_LEFT: +            case BOTTOM_CENTER: +            case BOTTOM_RIGHT: +                return true; +        } +        return false; +    } + +    public boolean isLeft() +    { +        boolean r = false; +        switch(this) { +            case TOP_LEFT: +            case MIDDLE_LEFT: +            case BOTTOM_LEFT: +                return true; +        } +        return false; +    } + +    public boolean isRight() +    { +        boolean r = false; +        switch(this) { +            case TOP_RIGHT: +            case MIDDLE_RIGHT: +            case BOTTOM_RIGHT: +                return true; +        } +        return false; +    } + +    public boolean isCenter() +    { +        switch(this) { +            case TOP_CENTER: +            case MIDDLE_CENTER: +            case BOTTOM_CENTER: +                return true; +        } +        return false; +    } + +    public float getX(Element element, float width) +    { +        float x = element.getInnerX(); +        switch(this) { +            case TOP_LEFT: +            case MIDDLE_LEFT: +            case BOTTOM_LEFT: +                break; +            case TOP_CENTER: +            case MIDDLE_CENTER: +            case BOTTOM_CENTER: +                x += ((element.getInnerWidth() - width) / 2); +                break; +            case TOP_RIGHT: +            case MIDDLE_RIGHT: +            case BOTTOM_RIGHT: +                x += (element.getInnerWidth() - width); +                break; +        } +        return x; +    } + +    public float getY(Element element, float height) +    { +        float y = element.getInnerY(); +        switch(this) { +            case TOP_LEFT: +            case TOP_CENTER: +            case TOP_RIGHT: +                y += (element.getInnerHeight() - height); +                break; +            case MIDDLE_LEFT: +            case MIDDLE_CENTER: +            case MIDDLE_RIGHT: +                y += ((element.getInnerHeight() - height) / 2); +                break; +            case BOTTOM_LEFT: +            case BOTTOM_CENTER: +            case BOTTOM_RIGHT: +                break; +        } +        return y; +    } +} diff --git a/core/src/ch/asynk/gdx/board/ui/Assembly.java b/core/src/ch/asynk/gdx/board/ui/Assembly.java new file mode 100644 index 0000000..b7d329e --- /dev/null +++ b/core/src/ch/asynk/gdx/board/ui/Assembly.java @@ -0,0 +1,62 @@ +package ch.asynk.gdx.board.ui; + +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; + +import ch.asynk.gdx.board.util.IterableSet; + +public abstract class Assembly extends Element +{ +    private IterableSet<Element> children; +    private Element touched; + +    public Assembly(int c) +    { +        this.children = new IterableSet<Element>(c); +    } + +    public void add(Element e) +    { +        if (children.add(e)) { +            e.setParent(this); +        } +    } + +    public void remove(Element e) +    { +        if (children.remove(e)) { +            e.setParent(null); +        } +    } + +    public Element touched() +    { +        return touched; +    } + +    @Override public boolean touch(float x, float y) +    { +        for (Element e : children) +            if (e.touch(x, y)) { +                touched = e; +                return true; +            } +        touched = null; +        return false; +    } + +    @Override public void update() +    { +        children.forEach( c -> c.update() ); +    } + +    @Override public void draw(Batch batch) +    { +        children.forEach( c -> c.draw(batch) ); +    } + +    @Override public void drawDebug(ShapeRenderer debugShapes) +    { +        children.forEach( c -> c.drawDebug(debugShapes) ); +    } +} diff --git a/core/src/ch/asynk/gdx/board/ui/Button.java b/core/src/ch/asynk/gdx/board/ui/Button.java new file mode 100644 index 0000000..f5f771a --- /dev/null +++ b/core/src/ch/asynk/gdx/board/ui/Button.java @@ -0,0 +1,65 @@ +package ch.asynk.gdx.board.ui; + +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; + +public class Button extends Patch +{ +    private Label label; +    private float spacing; + +    public Button(BitmapFont font, NinePatch patch) +    { +        this(font, patch, 0, 0); +    } + +    public Button(BitmapFont font, NinePatch patch, float padding, float spacing) +    { +        super(patch); +        this.padding = padding; +        this.spacing = spacing; +        label = new Label(font); +        label.setParent(this); +        label.setAlignment(Alignment.MIDDLE_CENTER); +    } + +    public void write(String text) +    { +        write(text, getX(), getY()); +    } + +    public void write(String text, float x, float y) +    { +        label.write(text, x, y); +    } + +    public void setLabelAlignment(Alignment alignment) +    { +        label.setAlignment(alignment); +    } + +    @Override public void update() +    { +        label.preUpdate();      // compute width and height +        rect.width = label.getWidth() + 2 * (padding + spacing); +        rect.height = label.getHeight() + 2 * (padding + spacing); +        super.update(); +        label.doUpdate();       // compute x and y +        label.postUpdate();     // compute fx and fy +    } + +    @Override public void draw(Batch batch) +    { +        if (!visible) return; +        super.draw(batch); +        label.draw(batch); +    } + +    @Override public void drawDebug(ShapeRenderer debugShapes) +    { +        super.drawDebug(debugShapes); +        label.drawDebug(debugShapes); +    } +} diff --git a/core/src/ch/asynk/gdx/board/ui/Element.java b/core/src/ch/asynk/gdx/board/ui/Element.java new file mode 100644 index 0000000..09523b5 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/ui/Element.java @@ -0,0 +1,112 @@ +package ch.asynk.gdx.board.ui; + +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Rectangle; + +import ch.asynk.gdx.board.Drawable; +import ch.asynk.gdx.board.Touchable; + +public abstract class Element implements Drawable, Touchable +{ +    public boolean blocked; +    public boolean visible; +    protected float padding; +    protected Element parent; +    protected Alignment alignment; +    protected Rectangle rect;           // drawing coordinates +    protected float x, y;               // given position + +    protected Element() +    { +        this.blocked = false; +        this.visible = true; +        this.padding = 0; +        this.rect = new Rectangle(0, 0, 0, 0); +        this.parent = null; +        this.alignment = alignment.RELATIVE; +        this.x = this.y = 0; +    } + +    @Override public final float getX()        { return rect.x; } +    @Override public final float getY()        { return rect.y; } +    @Override public final float getWidth()    { return rect.width; } +    @Override public final float getHeight()   { return rect.height; } + +    @Override public final float getInnerX()              { return rect.x + padding; } +    @Override public final float getInnerY()              { return rect.y + padding; } +    @Override public final float getInnerWidth()          { return rect.width - 2 * padding; } +    @Override public final float getInnerHeight()         { return rect.height - 2 * padding; } + +    @Override public void drawDebug(ShapeRenderer debugShapes) +    { +        debugShapes.rect(getX(), getY(), getWidth(), getHeight()); +    } + +    @Override public boolean touch(float x, float y) +    { +        if (blocked || !visible) return false; +        return rect.contains(x, y); +    } + +    @Override public void setPosition(float x, float y, float w, float h) +    { +        this.x = x; +        this.y = y; +        rect.width = w; +        rect.height = h; +        // rect.set(rec.x, y, w, h); +    } + +    public void setParent(Element parent) +    { +        this.parent = parent; +    } + +    public void setPadding(float padding) +    { +        this.padding = padding; +    } + +    public void setAlignment(Alignment alignment) +    { +        this.alignment = alignment; +    } + +    public final void translate(float dx, float dy) +    { +        setPosition(x + dx, y + dy); +    } + +    public final void setPosition(Rectangle r) +    { +        setPosition(r.x, r.x, r.width, r.height); +    } + +    public final void setPosition(float x, float y) +    { +       setPosition(x, y, rect.width, rect.height); +    } + +    protected void preUpdate() { } +    protected void postUpdate() { } +    protected void doUpdate() +    { +        if (alignment == Alignment.ABSOLUTE || parent == null) { +            rect.x = x; +            rect.y = y; +        } else if (alignment == Alignment.RELATIVE) { +            rect.x  = x + parent.getInnerX(); +            rect.y = y + parent.getInnerX(); +        } else { +            rect.x = x + alignment.getX(parent, rect.width); +            rect.y = y + alignment.getY(parent, rect.height); +        } +    } + +    public void update() +    { +        preUpdate(); +        doUpdate(); +        postUpdate(); +    } +} diff --git a/core/src/ch/asynk/gdx/board/ui/Label.java b/core/src/ch/asynk/gdx/board/ui/Label.java new file mode 100644 index 0000000..05dfc8c --- /dev/null +++ b/core/src/ch/asynk/gdx/board/ui/Label.java @@ -0,0 +1,62 @@ +package ch.asynk.gdx.board.ui; + +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.GlyphLayout; + +public class Label extends Element +{ +    private BitmapFont font; +    private GlyphLayout layout; +    private float fx; +    private float fy; +    private String text; + +    public Label(BitmapFont font) +    { +        this(font, 0); +    } + +    public Label(BitmapFont font, float padding) +    { +        this(font, padding, Alignment.RELATIVE); +    } + +    public Label(BitmapFont font, float padding, Alignment alignment) +    { +        super(); +        this.font = font; +        this.padding = padding; +        this.alignment = alignment; +        this.layout = new GlyphLayout(); +    } + +    public void write(String text) +    { +        write(text, getX(), getY()); +    } + +    public void write(String text, float x, float y) +    { +        this.text = text; +        setPosition(x, y); +    } + +    @Override protected void preUpdate() +    { +        this.layout.setText(font, (text == null) ? "" : text); +        super.setPosition(x, y, (layout.width + (2 * padding)), (layout.height + (2 * padding))); +    } + +    @Override protected void postUpdate() +    { +        fx = getInnerX(); +        fy = getInnerY() + layout.height; +    } + +    @Override public void draw(Batch batch) +    { +        if (!visible) return; +        font.draw(batch, layout, fx, fy); +    } +} diff --git a/core/src/ch/asynk/gdx/board/ui/Patch.java b/core/src/ch/asynk/gdx/board/ui/Patch.java new file mode 100644 index 0000000..aa86c9f --- /dev/null +++ b/core/src/ch/asynk/gdx/board/ui/Patch.java @@ -0,0 +1,22 @@ +package ch.asynk.gdx.board.ui; + +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.NinePatch; + +public class Patch extends Element +{ +    private NinePatch patch; + +    public Patch(NinePatch patch) +    { +        super(); +        this.patch = patch; +        setPosition(0, 0, patch.getTotalWidth(), patch.getTotalHeight()); +    } + +    @Override public void draw(Batch batch) +    { +        if (!visible) return; +        patch.draw(batch, getX(), getY(), getWidth(), getHeight()); +    } +} diff --git a/core/src/ch/asynk/gdx/board/ui/Root.java b/core/src/ch/asynk/gdx/board/ui/Root.java new file mode 100644 index 0000000..95d9ed5 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/ui/Root.java @@ -0,0 +1,16 @@ +package ch.asynk.gdx.board.ui; + +public class Root extends Assembly +{ +    public Root(int c) +    { +        super(c); +        this.alignment = Alignment.ABSOLUTE; +    } + +    public void resize(float width, float height) +    { +        setPosition(0, 0, width, height); +        update(); +    } +} diff --git a/core/src/ch/asynk/gdx/board/util/Collection.java b/core/src/ch/asynk/gdx/board/util/Collection.java new file mode 100644 index 0000000..8aadadf --- /dev/null +++ b/core/src/ch/asynk/gdx/board/util/Collection.java @@ -0,0 +1,28 @@ +package ch.asynk.gdx.board.util; + +import java.util.Iterator; + +public interface Collection<E> extends Iterator, Iterable<E> +{ +    public int size(); + +    public boolean isEmpty(); + +    public void clear(); + +    public void ensureCapacity(int c); + +    public boolean contains(E e); + +    public E get(int idx); + +    public int indexOf(E e); + +    public boolean add(E e); + +    public boolean insert(E e, int idx); + +    public E remove(int idx); + +    public boolean remove(E e); +} diff --git a/core/src/ch/asynk/gdx/board/util/IterableArray.java b/core/src/ch/asynk/gdx/board/util/IterableArray.java new file mode 100644 index 0000000..2dc4481 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/util/IterableArray.java @@ -0,0 +1,143 @@ +package ch.asynk.gdx.board.util; + +import java.util.Arrays; +import java.util.Iterator; + +public class IterableArray<E> implements Collection<E> +{ +    private int idx; +    private int s; +    private int c; +    transient E[] data; + +    @SuppressWarnings("unchecked") +    public IterableArray(int capacity) +    { +        this.s = 0; +        this.c = capacity; +        this.data = (E[]) new Object[c]; +    } + +    @Override public int size() +    { +        return s; +    } + +    @Override public boolean isEmpty() +    { +        return (s == 0); +    } + +    @Override public void clear() +    { +        for (int i = 0; i < s; i++) +            data[i] = null; +        s = 0; +    } + +    @Override public void ensureCapacity(int min) +    { +        if (c > min) return; +        c += (c >> 1); +        if (c < min) +            c = min; +        data = Arrays.copyOf(data, c); +    } + +    @Override public boolean contains(E e) +    { +        if (e == null) { +            for (int i = 0; i < s; i++) { +                if (data[i] == null) +                    return true; +            } +        } else { +            for (int i = 0; i < s; i++) { +                if (e.equals(data[i])) +                    return true; +            } +        } +        return false; +    } + +    @Override public E get(int i) +    { +        return data[i]; +    } + +    @Override public int indexOf(E e) +    { +        for (int i = 0; i < data.length; i++) { +            if (data[i] != null && data[i].equals(e)) +                return i; +        } +        return -1; +    } + +    @Override public boolean add(E e) +    { +        ensureCapacity(s + 1); +        data[s] = e; +        s += 1; +        return true; +    } + +    @Override public boolean insert(E e, int idx) +    { +        ensureCapacity(s + 1); +        System.arraycopy(data, idx, data, idx+1, (s - idx)); +        data[idx] = e; +        s += 1; +        return true; +    } + +    @Override public E remove(int i) +    { +        E e = data[i]; +        int m = (s - i - 1); +        if (m > 0) +            System.arraycopy(data, i+1, data, i, m); +        data[--s] = null; + +        return e; +    } + +    @Override public boolean remove(E e) +    { +        for (int i = 0; i < s; i++) { +            if (e.equals(data[i])) { +                int m = (s - i - 1); +                if (m > 0) +                    System.arraycopy(data, i+1, data, i, m); +                data[--s] = null; +                return true; +            } +        } +        return false; +    } + +    @SuppressWarnings("unchecked") +    @Override public Iterator<E> iterator() +    { +        this.idx = 0; +        return (Iterator<E>) this; +    } + +    @Override public boolean hasNext() +    { +        return (idx < s); +    } + +    @Override public E next() +    { +        E e = get(idx); +        idx += 1; +        return e; +    } + +    @Override public void remove() +    { +        idx -= 1; +        remove(idx); +    } +} diff --git a/core/src/ch/asynk/gdx/board/util/IterableQueue.java b/core/src/ch/asynk/gdx/board/util/IterableQueue.java new file mode 100644 index 0000000..8a9a74f --- /dev/null +++ b/core/src/ch/asynk/gdx/board/util/IterableQueue.java @@ -0,0 +1,19 @@ +package ch.asynk.gdx.board.util; + +public class IterableQueue<E> extends IterableArray<E> +{ +    public IterableQueue(int n) +    { +        super(n); +    } + +    public void enqueue(E e) +    { +        add(e); +    } + +    public E dequeue() +    { +        return remove(0); +    } +} diff --git a/core/src/ch/asynk/gdx/board/util/IterableSet.java b/core/src/ch/asynk/gdx/board/util/IterableSet.java new file mode 100644 index 0000000..7e37f4e --- /dev/null +++ b/core/src/ch/asynk/gdx/board/util/IterableSet.java @@ -0,0 +1,16 @@ +package ch.asynk.gdx.board.util; + +public class IterableSet<E> extends IterableArray<E> +{ +    public IterableSet(int n) +    { +        super(n); +    } + +    @Override public boolean add(E e) +    { +        if (contains(e)) return false; +        super.add(e); +        return true; +    } +} diff --git a/core/src/ch/asynk/gdx/board/util/IterableStack.java b/core/src/ch/asynk/gdx/board/util/IterableStack.java new file mode 100644 index 0000000..1365408 --- /dev/null +++ b/core/src/ch/asynk/gdx/board/util/IterableStack.java @@ -0,0 +1,26 @@ +package ch.asynk.gdx.board.util; + +public class IterableStack<E> extends IterableArray<E> +{ +    public IterableStack(int n) +    { +        super(n); +    } + +    public void push(E e) +    { +        add(e); +    } + +    public E pop() +    { +        if (size() <= 0) return null; +        return remove(size() - 1); +    } + +    public E getTop() +    { +        if (size() <= 0) return null; +        return get(size() - 1); +    } +}  | 
