package com.galvarez.ttw.model.map; import static java.lang.Math.min; import java.util.Properties; import com.badlogic.gdx.math.MathUtils; /** * Generates a map with more chances of an island on map center. * * @author Guillaume Alvarez */ public class HexMapIslandGenerator implements MapGenerator { public static float coldThreshold = 0.1f; public static float hotThreshold = 0.65f; private static boolean isCold(float heat) { return heat < coldThreshold; } private static boolean isHot(float heat) { return heat > hotThreshold; } public static float dryThreshold = 0.3f; public static float wetThreshold = 0.7f; private static boolean isDry(float wet) { return wet < dryThreshold; } private static boolean isWet(float wet) { return wet > wetThreshold; } public static float deepWaterThreshold = 0.2f; public static float shallowWaterThreshold = 0.25f; public static float lowGroundsTreshold = 0.45f; public static float mediumGroundsThreshold = 0.65f; public static float highGroundThreshold = 0.88f; public static float veryHighGroundThreshold = 0.95f; @Override public Terrain[][] getMapData(Properties props) { int noise = Integer.parseInt(props.getProperty("noise")); int width = Integer.parseInt(props.getProperty("width")); int height = Integer.parseInt(props.getProperty("height")); MidpointDisplacement md = new MidpointDisplacement(); float[][] heightMap = applyIslandForm(md.getMap2(noise, width, height)); float[][] heatMap = southIsWarmer(md.getMap2(noise, width, height)); float[][] wetMap = md.getMap2(noise, width, height); Terrain[][] returnMap = new Terrain[heightMap.length][heightMap[0].length]; float mapHeight; boolean cold, hot, wet, dry; // Use the thresholds to fill in the return map for (int row = 0; row < heightMap.length; row++) { for (int col = 0; col < heightMap[row].length; col++) { mapHeight = heightMap[row][col]; hot = isHot(heatMap[row][col]); cold = isCold(heatMap[row][col]); wet = isWet(wetMap[row][col]); dry = isDry(wetMap[row][col]); if (cold) { returnMap[row][col] = Terrain.ARCTIC; } else if (mapHeight < deepWaterThreshold) { returnMap[row][col] = Terrain.DEEP_WATER; } else if (mapHeight < shallowWaterThreshold) { returnMap[row][col] = Terrain.SHALLOW_WATER; } else if (mapHeight < lowGroundsTreshold) { // low level biomes if (hot && dry) returnMap[row][col] = Terrain.DESERT; else if (!cold && wet) returnMap[row][col] = Terrain.GRASSLAND; else if (wet) // TODO add JUNGLE when heat > hotThreshold returnMap[row][col] = Terrain.FOREST; else returnMap[row][col] = Terrain.PLAIN; } else if (mapHeight < mediumGroundsThreshold) { // slightly higher if (wet) returnMap[row][col] = Terrain.FOREST; else if (hot && dry) returnMap[row][col] = Terrain.DESERT; else returnMap[row][col] = Terrain.GRASSLAND; } else if (mapHeight < highGroundThreshold) { // hills if (wet && !hot) returnMap[row][col] = Terrain.FOREST; else returnMap[row][col] = Terrain.HILLS; } else if (mapHeight < veryHighGroundThreshold) { // mountains returnMap[row][col] = Terrain.MOUNTAIN; } else { // eternal snow returnMap[row][col] = Terrain.ARCTIC; } } } return returnMap; } private float[][] southIsWarmer(float[][] map) { int rows = map.length; int cols = map[0].length; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { float ratio = (float) (cols - col) / cols; map[row][col] += ratio * 2 * MathUtils.randomTriangular(1f, 1.5f); } } MidpointDisplacement.normalize(map); return map; } /** * Decrease height on borders and increase it on map center. */ private float[][] applyIslandForm(float[][] heightMap) { int rows = heightMap.length; int cols = heightMap[0].length; int radius = min(rows / 2, cols / 2); for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { int distanceFromBorder = min(min(row, col), min(rows - row, cols - col)); float ratio = (float) distanceFromBorder / radius; heightMap[row][col] *= ratio * 2 * MathUtils.randomTriangular(0.8f, 1.2f); } } MidpointDisplacement.normalize(heightMap); return heightMap; } @Override public Properties getDefaultValues() { Properties props = new Properties(); props.setProperty("noise", "4"); props.setProperty("width", "3"); props.setProperty("height", "3"); return props; } }