package electrosphere.game.terrain; import com.google.gson.Gson; import electrosphere.main.Globals; import electrosphere.terraingen.TerrainGen; import electrosphere.terraingen.models.TerrainModel; import electrosphere.util.Utilities; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; /** * * @author satellite */ public class TerrainManager { //The size of the world in discrete units * must be multiple of 200 int worldSizeDiscrete = 2000; //The vertical multiplier applied to the statically generated terrain int verticalInterpolationRatio = 20; int dynamicInterpolationRatio = 1000; TerrainModel model; //Basic idea is we associate string that contains chunk x&y with elevation //While we incur a penalty with converting ints -> string, think this will //offset regenerating the array every time we want a new one int cacheSize = 50; HashMap elevationMapCache; ArrayList elevationMapCacheContents; public TerrainManager(int worldSizeDiscrete, int verticalInterpolationRatio, int dynamicInterpolationRatio){ this.worldSizeDiscrete = worldSizeDiscrete; this.verticalInterpolationRatio = verticalInterpolationRatio; this.dynamicInterpolationRatio = dynamicInterpolationRatio; this.elevationMapCache = new HashMap(); this.elevationMapCacheContents = new ArrayList(); } public void generate(){ TerrainGen terrainGen = new TerrainGen(); terrainGen.setInterpolationRatio(worldSizeDiscrete/200); terrainGen.setVerticalInterpolationRatio(verticalInterpolationRatio); terrainGen.setDynamicInterpolationRatio(dynamicInterpolationRatio); terrainGen.setRandomSeed(0); model = terrainGen.generateModel(); } public void save(){ Gson gson = new Gson(); String terrainOutRaw = gson.toJson(model); try { Files.write(new File(Globals.mainConfig.loadTerrainLocation).toPath(), terrainOutRaw.getBytes()); } catch (IOException ex) { ex.printStackTrace(); } } public void load(){ Gson gson = new Gson(); model = gson.fromJson(Utilities.readFileToString(new File(Globals.mainConfig.loadTerrainLocation)), TerrainModel.class); } public float[][] getTerrainAtChunk(int x, int y){ return model.getElevationForChunk(x, y); } public float[][] getAugmentedTerrainAtChunk(int x, int y){ String targetChunkName = x + "-" + y; if(elevationMapCache.containsKey(targetChunkName)){ elevationMapCacheContents.remove(targetChunkName); elevationMapCacheContents.add(0, targetChunkName); return elevationMapCache.get(targetChunkName); } else { float[][] targetChunk = model.getAugmentedElevationForChunk(x, y); if(elevationMapCacheContents.size() > cacheSize){ String oldChunk = elevationMapCacheContents.remove(elevationMapCacheContents.size() - 1); elevationMapCache.remove(oldChunk); } elevationMapCache.put(targetChunkName, targetChunk); elevationMapCacheContents.add(targetChunkName); return targetChunk; } } public float getHeightAtPosition(float x, float y){ //get chunk coordinate space of input x,y int chunkX = (int)Math.floor(x / dynamicInterpolationRatio); int chunkY = (int)Math.floor(y / dynamicInterpolationRatio); //get local coordinate space of input x,y float localX = x - chunkX * dynamicInterpolationRatio; float localY = y - chunkY * dynamicInterpolationRatio; //get chunk elevation map float[][] chunkElevationMap = getAugmentedTerrainAtChunk(chunkX,chunkY); //floored variants of local values int localXf = (int)Math.floor(localX); int localYf = (int)Math.floor(localY); /* Average some inner value. 01 11 0.3 0.4 0.5 0.1 0.2 0.3 00 10 */ //interp elevation from map float elevation00 = chunkElevationMap[(int)localX+0][(int)localY+0]; float elevation10 = chunkElevationMap[(int)localX+1][(int)localY+0]; float elevation01 = chunkElevationMap[(int)localX+0][(int)localY+1]; float elevation11 = chunkElevationMap[(int)localX+1][(int)localY+1]; float rVal = (1-(localX-localXf))*(1-(localY-localYf)) * elevation00 + ( (localX-localXf))*(1-(localY-localYf)) * elevation10 + (1-(localX-localXf))*( (localY-localYf)) * elevation01 + ( (localX-localXf))*( (localY-localYf)) * elevation11 ; return rVal; } public int getChunkWidth(){ return dynamicInterpolationRatio; } public int getAugmentedChunkWidth(){ return dynamicInterpolationRatio + 1; } public int getWorldDiscreteSize(){ return worldSizeDiscrete; } public float getDiscreteValue(int x, int y){ return model.getElevation()[x][y]; } }