Build-Your-Own-World / byow / lab12 / HexWorld.java
HexWorld.java
Raw
package byow.lab12;

import byow.TileEngine.TERenderer;
import byow.TileEngine.TETile;
import byow.TileEngine.Tileset;

import java.util.Random;

/**
 * Draws a world consisting of hexagonal regions.
 *
 * @source HexWorld live coding video
 */
public class HexWorld {

    private static final int WIDTH = 50;
    private static final int HEIGHT = 50;

    private static final long SEED = 3333333;
    private static final Random RANDOM = new Random(SEED);

    /**
     * draw row of tiles to board, anchored at given position
     */
    public static void drawRow(TETile[][] tiles, Position p, TETile tile, int length) {
        for (int dx = 0; dx < length; dx++) {
            tiles[p.x + dx][p.y] = tile;
        }
    }

    /**
     * Fills the given 2D array of tiles with RANDOM tiles.
     * @param tiles
     */
    public static void fillBoardWithNothing(TETile[][] tiles) {
        int height = tiles[0].length;
        int width = tiles.length;
        for (int x = 0; x < width; x += 1) {
            for (int y = 0; y < height; y += 1) {
                tiles[x][y] = Tileset.NOTHING;
            }
        }
    }

    /**
     * Gets the position of top/bottom right neighbor of hexagon at Position p.
     * N is size of hexagon we are tessellating.
     */
    public static Position getTopRightNeighbor(Position p, int n) {
        return p.shift(2*n - 1, n);
    }

    public static Position getBottomRightNeighbor(Position p, int n) {
        return p.shift(2*n - 1, -n);
    }

    /**
     * Gets position of bottom neighbor of a hexagon at position p.
     * @param p base hexagon
     * @param n size of hexagons we are tessellating.
     * @return position of the bottom neighbor by shifting p.
     */

    public static Position getBottomNeighbor(Position p, int n) {
        return p.shift(0, -2 * n);
    }

    //private helper class for positions
    private static class Position {
        int x;
        int y;

        Position(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public Position shift(int dx, int dy) {
            return new Position(this.x + dx, this.y + dy);
        }
    }

    /** Picks a RANDOM tile with a 33% change of being
     *  a wall, 33% chance of being a flower, and 33%
     *  chance of being empty space.
     */
    private static TETile randomTile() {
        int tileNum = RANDOM.nextInt(5);
        switch (tileNum) {
            case 0: return Tileset.TREE;
            case 1: return Tileset.FLOWER;
            case 2: return Tileset.GRASS;
            case 3: return Tileset.MOUNTAIN;
            case 4: return Tileset.SAND;
            default: return Tileset.NOTHING;
        }
    }

    public static void addHexagonHelper(TETile[][] tiles, Position p, TETile tile,int b, int t) {
        // draw first row
        Position startOfRow = p.shift(b, 0);
        drawRow(tiles, startOfRow, tile, t);

        // draw remaining recursively until last row
        if (b > 0) {
            Position nextP = p.shift(0, -1);
            addHexagonHelper(tiles, nextP, tile, b - 1, t + 2);
        }

        // draw last row
        Position startOfReflectedRow = startOfRow.shift(0, -(2 * b + 1));
        drawRow(tiles, startOfReflectedRow, tile, t);
    }

    public static void addHexagon(TETile[][] tiles, Position p, TETile t, int s) {
        if (s <= 2) return;
        addHexagonHelper(tiles, p, t, s - 1, s);
    }

    /**
     * Adds a column of n hexagons, each of whose biomes are chosen randomly
     * to the world at position p. Each of the hexagons are size s.
     */
    public static void addHexColumn(TETile[][] tiles, Position p, int s, int n) {
        if (n < 1) return;

        // draw this hexagon
        addHexagon(tiles, p, randomTile(), s);

        // draw n - 1 hexagons below it
        if (n > 1) {
            Position bottomNeighbor = getBottomNeighbor(p, s);
            addHexColumn(tiles, bottomNeighbor, s, n - 1);
        }
    }

    /**
     * draws hexagonal world
     * @param tiles
     */
    public static void drawWorld(TETile[][] tiles, Position p, int hexSize, int tessSize) {

        // draw first hexagon
        addHexColumn(tiles, p, hexSize, tessSize);

        // expand up and right
        for (int i = 1; i < tessSize; i++) {
            p = getTopRightNeighbor(p, hexSize);
            addHexColumn(tiles, p, hexSize, tessSize + i);
        }

        // expand down and right
        for (int i = tessSize - 2; i >= 0; i--) {
            p = getBottomRightNeighbor(p, hexSize);
            addHexColumn(tiles, p, hexSize, tessSize + i);
        }
    }

    public static void main(String[] args) {
        TERenderer ter = new TERenderer();
        ter.initialize(WIDTH, HEIGHT);

        TETile[][] world = new TETile[WIDTH][HEIGHT];
        fillBoardWithNothing(world);
        Position anchor = new Position(15, 30);
        drawWorld(world, anchor, 2, 3);

        ter.renderFrame(world);
    }
}