123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- package pathgame.tilemap;
- import java.util.ArrayList;
- import java.util.Random;
- public class TileMapGenerator {
- private static long seed = 1;
- public static TileMap getMap(int width, int height, int towns) {
- return getMap(width, height, seed++, towns);
- }
- public static TileMap getMap(int width, int height, long seed, int towns) {
- Random r = new Random(seed);
- HighMap highMap = HighMap.generate(seed, width, height);
- TileMap map = new TileMap(width, height);
- for(int x = 0; x < width; x++) {
- for(int y = 0; y < height; y++) {
- if(highMap.get(x, y) < 0.15f) {
- map.setTile(x, y, Tiles.DEEP_WATER);
- } else if(highMap.get(x, y) < 0.3f) {
- map.setTile(x, y, Tiles.SHALLOW_WATER);
- } else if(highMap.get(x, y) < 0.7f) {
- map.setTile(x, y, randomGrass(r));
- } else if(highMap.get(x, y) < 0.85f) {
- map.setTile(x, y, Tiles.HILL);
- } else {
- map.setTile(x, y, Tiles.MOUNTAIN);
- }
- }
- }
- generateHomeTown(map, r);
- int forestSize = ((width + height) / 2) / 10;
- forestSize *= forestSize;
- generateForest(map, r, forestSize, 10, 2, Tiles.FOREST);
- generateForest(map, r, forestSize, 5, 2, Tiles.SWAMP, Tiles.SWAMP, Tiles.SWAMP_DECO, Tiles.SWAMP_TREE, Tiles.SWAMP_BONES);
- generateTowns(map, r, towns);
- generatePorts(map, r);
- generatePaths(map, r);
- removeBadSwampTree(map);
- return map;
- }
- private static Tile randomGrass(Random r) {
- if(r.nextFloat() < 0.3f) {
- return randomTile(Tiles.GRASS_VARIANTS, r);
- }
- return Tiles.GRASS;
- }
- private static void generateForest(TileMap map, Random r, int depth, int placements, int jumpRadius, Tile... t) {
- for(int i = 0; i < placements; i++) {
- int x = r.nextInt(map.getWidth());
- int y = r.nextInt(map.getHeight());
- while(map.getTile(x, y).getForestReplaceChance() < 1.0f) {
- x = r.nextInt(map.getWidth());
- y = r.nextInt(map.getHeight());
- }
- for(int j = 0; j < depth; j++) {
- int oldX = x;
- int oldY = y;
- x += r.nextInt(jumpRadius * 2 + 1) - jumpRadius;
- y += r.nextInt(jumpRadius * 2 + 1) - jumpRadius;
- x = Math.min(Math.max(x, 0), map.getWidth() - 1);
- y = Math.min(Math.max(y, 0), map.getHeight() - 1);
- if(r.nextFloat() < map.getTile(x, y).getForestReplaceChance()) {
- map.setTile(x, y, randomTile(t, r));
- placeForest(map, r, x - 1, y, t);
- placeForest(map, r, x + 1, y, t);
- placeForest(map, r, x, y - 1, t);
- placeForest(map, r, x, y + 1, t);
- } else {
- x = oldX;
- y = oldY;
- }
- }
- }
- }
- private static void removeBadSwampTree(TileMap map) {
- for(int x = 0; x < map.getWidth(); x++) {
- for(int y = 0; y < map.getHeight(); y++) {
- Tile t = map.getTile(x, y);
- if((t == Tiles.SWAMP_TREE || t == Tiles.SWAMP_BONES)
- && ((x > 0 && map.getTile(x - 1, y).getRenderType() != TileRenderType.SWAMP)
- || (y > 0 && map.getTile(x, y - 1).getRenderType() != TileRenderType.SWAMP))) {
- map.setTile(x, y, Tiles.SWAMP);
- }
- }
- }
- }
- private static Tile randomTile(Tile[] tiles, Random r) {
- if(tiles.length == 1) {
- return tiles[0];
- }
- return tiles[r.nextInt(tiles.length)];
- }
- private static void placeForest(TileMap map, Random r, int x, int y, Tile... t) {
- if(x >= 0 && x < map.getWidth() && y >= 0 && y < map.getHeight()) {
- if(r.nextFloat() * 2 < map.getTile(x, y).getForestReplaceChance()) {
- map.setTile(x, y, randomTile(t, r));
- }
- }
- }
- private static void generateTowns(TileMap map, Random r, int towns) {
- int failCounter = 0;
- while(towns > 0 && failCounter < 100) {
- int x = r.nextInt(map.getWidth());
- int y = r.nextInt(map.getHeight());
- if(map.getTile(x, y).canHostTown() && checkNearbyTowns(map, x, y, 2)) {
- map.setTile(x, y, Tiles.TOWN);
- towns--;
- failCounter = 0;
- } else {
- failCounter++;
- }
- }
- }
- private static boolean checkNearbyTowns(TileMap map, int x, int y, int radius) {
- int startX = Math.max(x - radius, 0);
- int startY = Math.max(y - radius, 0);
- int endX = Math.min(x + radius, map.getWidth() - 1);
- int endY = Math.min(y + radius, map.getHeight() - 1);
- for(int mx = startX; mx <= endX; mx++) {
- for(int my = startY; my <= endY; my++) {
- if(map.getTile(mx, my) == Tiles.TOWN) {
- return false;
- }
- }
- }
- return true;
- }
- private static boolean isWater(TileMap map, int x, int y) {
- TileType type = map.getTile(x, y).getType();
- return type == TileType.DEEP_WATER || type == TileType.SHALLOW_WATER;
- }
- private static boolean isNeighbourWater(TileMap map, int x, int y) {
- return (x - 1 >= 0 && isWater(map, x - 1, y))
- || (x + 1 < map.getWidth() && isWater(map, x + 1, y))
- || (y - 1 >= 0 && isWater(map, x, y - 1))
- || (y + 1 < map.getHeight() && isWater(map, x, y + 1));
- }
- private static void generatePorts(TileMap map, Random r) {
- boolean[][] visited = new boolean[map.getWidth()][map.getHeight()];
- for(int x = 0; x < map.getWidth(); x++) {
- for(int y = 0; y < map.getHeight(); y++) {
- if(!visited[x][y] && isWater(map, x, y)) {
- getLake(map, r, x, y, visited);
- }
- visited[x][y] = true;
- }
- }
- }
- private static int waterSize;
- private static int waterMinX;
- private static int waterMinY;
- private static int waterMaxX;
- private static int waterMaxY;
- private static class Location {
- private final int x;
- private final int y;
- public Location(int x, int y) {
- this.x = x;
- this.y = y;
- }
- public double getQuaredDistance(int ox, int oy) {
- return (ox - x) * (ox - x) + (oy - y) * (oy - y);
- }
- }
- private static double minSquaredDistance(ArrayList<Location> locs, int x, int y) {
- double min = Double.MAX_VALUE;
- for(Location loc : locs) {
- double d = loc.getQuaredDistance(x, y);
- if(d < min) {
- min = d;
- }
- }
- return min;
- }
- private static void getLake(TileMap map, Random r, int x, int y, boolean[][] visited) {
- waterSize = 0;
- waterMinX = x;
- waterMinY = y;
- waterMaxX = x;
- waterMaxY = y;
- scanWaterTiles(map, x, y, visited);
- // water outlines can be a port too
- waterMinX = Math.max(0, waterMinX - 1);
- waterMinY = Math.max(0, waterMinY - 1);
- waterMaxX = Math.min(map.getWidth() - 1, waterMaxX + 1);
- waterMaxY = Math.min(map.getHeight() - 1, waterMaxY + 1);
- ArrayList<Location> locs = new ArrayList<>();
- int ports = waterSize / 30;
- int diffX = waterMaxX - waterMinX + 1;
- int diffY = waterMaxY - waterMinY + 1;
- int failCounter = 0;
- while(ports > 0 && failCounter < 100) {
- int rx = waterMinX + r.nextInt(diffX);
- int ry = waterMinY + r.nextInt(diffY);
- if(map.getTile(rx, ry).canHostTown() && isNeighbourWater(map, rx, ry) && minSquaredDistance(locs, rx, ry) > 25) {
- locs.add(new Location(rx, ry));
- map.setTile(rx, ry, Tiles.PORT);
- ports--;
- failCounter = 0;
- } else {
- failCounter++;
- }
- }
- }
- private static void scanWaterTiles(TileMap map, int x, int y, boolean[][] visited) {
- if(!visited[x][y] && isWater(map, x, y)) {
- visited[x][y] = true;
- waterSize++;
- waterMinX = Math.min(x, waterMinX);
- waterMinY = Math.min(y, waterMinY);
- waterMaxX = Math.max(x, waterMaxX);
- waterMaxY = Math.max(y, waterMaxY);
- if(x - 1 >= 0) {
- scanWaterTiles(map, x - 1, y, visited);
- }
- if(x + 1 < map.getWidth()) {
- scanWaterTiles(map, x + 1, y, visited);
- }
- if(y - 1 >= 0) {
- scanWaterTiles(map, x, y - 1, visited);
- }
- if(y + 1 < map.getHeight()) {
- scanWaterTiles(map, x, y + 1, visited);
- }
- }
- }
- private static void generateHomeTown(TileMap map, Random r) {
- int failCounter = 0;
- while(failCounter < 100) {
- int x = r.nextInt(map.getWidth());
- int y = r.nextInt(map.getHeight());
- if(map.getTile(x, y).canHostTown()) {
- map.setTile(x, y, Tiles.HOME_TOWN);
- map.setHomeTown(x, y);
- return;
- } else {
- failCounter++;
- }
- }
- map.setTile(0, 0, Tiles.HOME_TOWN);
- map.setHomeTown(0, 0);
- }
- private static boolean isPath(TileMap map, int x, int y) {
- return x >= 0 && y >= 0 && x < map.getWidth() && y < map.getHeight() && map.getTile(x, y).isPath();
- }
- private static void generatePaths(TileMap map, Random r) {
- int paths = (map.getHeight() + map.getWidth()) / 6 + 2;
- // generate paths with random direction
- for(int i = 0; i < paths; i++) {
- int x = r.nextInt(map.getWidth());
- int y = r.nextInt(map.getHeight());
- while(!map.getTile(x, y).canHostPath()) {
- x = r.nextInt(map.getWidth());
- y = r.nextInt(map.getHeight());
- }
- float dx = (r.nextFloat() * 0.75f + 0.25f) * (r.nextBoolean() ? -1 : 1);
- float dy = (r.nextFloat() * 0.75f + 0.25f) * (r.nextBoolean() ? -1 : 1);
- generatePathDiretion(map, r, x, y, dx, dy);
- }
- // destroy path 2x2 blocks
- destroyPathBlocks(map);
- destroyPathBlocks(map);
- // swap paths depending on neighbours
- for(int x = 0; x < map.getWidth(); x++) {
- for(int y = 0; y < map.getHeight(); y++) {
- if(map.getTile(x, y).isPath()) {
- map.setTile(x, y, Tiles.getPath(
- isPath(map, x, y - 1), isPath(map, x + 1, y),
- isPath(map, x, y + 1), isPath(map, x - 1, y)));
- }
- }
- }
- }
- private static void destroyPathBlocks(TileMap map) {
- for(int x = 0; x < map.getWidth() - 1; x++) {
- for(int y = 0; y < map.getHeight() - 1; y++) {
- if(map.getTile(x, y).isPath() && map.getTile(x + 1, y).isPath()
- && map.getTile(x, y + 1).isPath() && map.getTile(x + 1, y + 1).isPath()) {
- if(!isPath(map, x - 1, y) && !isPath(map, x, y - 1)) {
- map.setTile(x, y, Tiles.GRASS);
- continue;
- }
- if(!isPath(map, x + 1, y - 1) && !isPath(map, x + 2, y)) {
- map.setTile(x + 1, y, Tiles.GRASS);
- continue;
- }
- if(!isPath(map, x - 1, y + 1) && !isPath(map, x, y + 2)) {
- map.setTile(x, y + 1, Tiles.GRASS);
- continue;
- }
- if(!isPath(map, x + 2, y + 1) && !isPath(map, x + 1, y + 2)) {
- map.setTile(x + 1, y + 1, Tiles.GRASS);
- }
- }
- }
- }
- }
- private static void generatePathDiretion(TileMap map, Random r, float x, float y, float dx, float dy) {
- while(true) {
- int tileX = (int) x;
- int tileY = (int) y;
- if(tileX < 0 || tileY < 0 || tileX >= map.getWidth() || tileY >= map.getHeight() || !map.getTile(tileX, tileY).canHostPath()) {
- break;
- }
- map.setTile(tileX, tileY, Tiles.PATH_N_E_S_W);
- while(tileX == (int) x && tileY == (int) y) {
- if(r.nextBoolean()) {
- x += dx;
- } else {
- y += dy;
- }
- }
- }
- }
- }
|