Improved island map generator.
Added documentation as well. Untested.
This commit is contained in:
parent
6cf1f6dcc1
commit
44f183cca0
@ -4,53 +4,81 @@ import java.util.Random;
|
|||||||
|
|
||||||
import org.bukkit.util.noise.SimplexOctaveGenerator;
|
import org.bukkit.util.noise.SimplexOctaveGenerator;
|
||||||
|
|
||||||
public class IslandMapGenerator {
|
import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateValidatable;
|
||||||
|
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
|
||||||
|
|
||||||
|
public class IslandMapGenerator implements CoordinateValidatable {
|
||||||
private SimplexOctaveGenerator noiseGenerator;
|
private SimplexOctaveGenerator noiseGenerator;
|
||||||
private final int noiseOctaves = 8;
|
private final int noiseOctaves = 8;
|
||||||
private final int islandGenerationPercent = 47;
|
private final int islandGenerationPercent = 47;
|
||||||
private final float exaggerationFactor = 1.5f;
|
private final float exaggerationFactor = 1.5f;
|
||||||
private final double noiseFrequency = 0.5D;
|
private final double noiseFrequency = 0.5D;
|
||||||
private final double noiseAmplitude = 0.5D;
|
private final double noiseAmplitude = 0.5D;
|
||||||
private final int shoreSize = 4;
|
private final float shoreFactor = 0.065f;
|
||||||
private final int maxHeightAboveWater = 8;
|
private final int maxHeightAboveSea = 8;
|
||||||
|
private final int lowestSeaFloor = 16;
|
||||||
private final int seaLevel;
|
private final int seaLevel;
|
||||||
private final int shallowDepth;
|
private final int shallowDepth;
|
||||||
|
private final DepthFirstSearch dfs;
|
||||||
|
|
||||||
public IslandMapGenerator(Random random, int seaLevel, int shallowDepth) {
|
public IslandMapGenerator(Random random, int seaLevel, int shallowDepth) {
|
||||||
|
|
||||||
this.noiseGenerator = new SimplexOctaveGenerator(random, noiseOctaves);
|
this.noiseGenerator = new SimplexOctaveGenerator(random, noiseOctaves);
|
||||||
this.seaLevel = seaLevel;
|
this.seaLevel = seaLevel;
|
||||||
this.shallowDepth = shallowDepth;
|
this.shallowDepth = shallowDepth;
|
||||||
|
dfs = new DepthFirstSearch(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Considers this land if it is greater than sea level.
|
||||||
|
* @param worldX the X coordinate of location in world.
|
||||||
|
* @param worldZ the Z coordinate of location in world.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean isLand(int worldX, int worldZ) {
|
public boolean isLand(int worldX, int worldZ) {
|
||||||
if (getBaseBlockHeight(worldX, worldZ) >= seaLevel) {
|
if (getIslandValue(worldX, worldZ) >= 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates if this is the edge of the island by checking if it's surrounding blocks are part of this island.
|
||||||
|
* @param worldX The world X coordinate.
|
||||||
|
* @param worldZ The world Z coordinate.
|
||||||
|
* @return true if it is the edge of the island and false if it isn't.
|
||||||
|
*/
|
||||||
public boolean isEdgeOfIsland(int worldX, int worldZ) {
|
public boolean isEdgeOfIsland(int worldX, int worldZ) {
|
||||||
return isIsland(worldX, worldZ) &&
|
return isIsland(worldX, worldZ) &&
|
||||||
(!isSameIsland(worldX, worldZ, worldX + 1, worldZ) ||
|
!(isSameIsland(worldX, worldZ, worldX + 1, worldZ) &&
|
||||||
isSameIsland(worldX, worldZ, worldX - 1, worldZ) ||
|
isSameIsland(worldX, worldZ, worldX - 1, worldZ) &&
|
||||||
isSameIsland(worldX, worldZ, worldX , worldZ + 1) ||
|
isSameIsland(worldX, worldZ, worldX , worldZ + 1) &&
|
||||||
isSameIsland(worldX, worldZ, worldX, worldZ - 1));
|
isSameIsland(worldX, worldZ, worldX, worldZ - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These coordinates are considered to be the shore if:
|
||||||
|
* It is a part of an island,
|
||||||
|
* within a square radius of shoreSize, there is an edge of the island.
|
||||||
|
* @param worldX the X coordinate of location in world.
|
||||||
|
* @param worldZ the Z coordinate of location in world.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean isShore(int worldX, int worldZ) {
|
public boolean isShore(int worldX, int worldZ) {
|
||||||
if (!isIsland(worldX, worldZ)) return false;
|
if (!isIsland(worldX, worldZ)) return false;
|
||||||
|
if (isLand(worldX, worldZ) && getIslandValue(worldX, worldZ) <= shoreFactor) {
|
||||||
for (int xPos = 0; xPos < shoreSize; xPos++) {
|
|
||||||
for (int zPos = 0; zPos < shoreSize; zPos++) {
|
|
||||||
if (isEdgeOfIsland(worldX + xPos, worldZ + zPos) || isEdgeOfIsland(worldX - xPos, worldZ - zPos)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Considers these coordinates to be part of an island if:
|
||||||
|
* It is land, or if it is a shallow portion of land.
|
||||||
|
* @param worldX the X coordinate of location in world.
|
||||||
|
* @param worldZ the Y coordinate of location in world.
|
||||||
|
* @return true if these coordinates represent an island.
|
||||||
|
*/
|
||||||
public boolean isIsland(int worldX, int worldZ) {
|
public boolean isIsland(int worldX, int worldZ) {
|
||||||
if (isLand(worldX, worldZ) || isShallowPortion(worldX, worldZ)) {
|
if (isLand(worldX, worldZ) || isShallowPortion(worldX, worldZ)) {
|
||||||
return true;
|
return true;
|
||||||
@ -58,9 +86,16 @@ public class IslandMapGenerator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This block is considered a shallow portion of the island:
|
||||||
|
* The block height is less than the sea level,
|
||||||
|
* and that the block height is greater than the sea level - the shallow depth.
|
||||||
|
* @param worldX the X coordinate of location in world.
|
||||||
|
* @param worldZ the Z coordinate of location in world.
|
||||||
|
* @return true if it is considered the shallow portion.
|
||||||
|
*/
|
||||||
public boolean isShallowPortion(int worldX, int worldZ) {
|
public boolean isShallowPortion(int worldX, int worldZ) {
|
||||||
int blockHeight = getBaseBlockHeight(worldX, worldZ);
|
if (getIslandValue(worldX, worldZ) >= - (float) shallowDepth / (float) seaLevel) {
|
||||||
if (blockHeight < seaLevel && blockHeight >= (seaLevel - shallowDepth)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -68,34 +103,51 @@ public class IslandMapGenerator {
|
|||||||
|
|
||||||
private double getTerrainValue(int worldX, int worldZ) {
|
private double getTerrainValue(int worldX, int worldZ) {
|
||||||
double normalized = getNoiseValue(worldX, worldZ);
|
double normalized = getNoiseValue(worldX, worldZ);
|
||||||
return Math.pow(normalized, exaggerationFactor);
|
return Math.pow(normalized, exaggerationFactor) * (islandGenerationPercent + seaLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getNoiseValue(int worldX, int worldZ) {
|
public double getNoiseValue(int worldX, int worldZ) {
|
||||||
return (noiseGenerator.noise(worldX, worldZ, noiseFrequency, noiseAmplitude, true) + 1D) / 2D;
|
return (noiseGenerator.noise(worldX, worldZ, noiseFrequency, noiseAmplitude, true) + 1D) / 2D;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBaseBlockHeight(int worldX, int worldZ) {
|
/***
|
||||||
return Math.min((int) getTerrainValue(worldX, worldZ) * (islandGenerationPercent + seaLevel), maxHeightAboveWater + seaLevel);
|
* Island value will be 0 or positive if it is a part of an island.
|
||||||
|
* If less than, it is considered under the sea.
|
||||||
|
* Does not factor in a shallow depth.
|
||||||
|
* The value above zero is normalized to [0, 1].
|
||||||
|
* @param worldX the x world coordinate to obtain this value for.
|
||||||
|
* @param worldZ the z world coordinate to obtain this value for.
|
||||||
|
* @return a value representing the island at the given point.
|
||||||
|
*/
|
||||||
|
public float getIslandValue(int worldX, int worldZ) {
|
||||||
|
return (float) ((getTerrainValue(worldX, worldZ) - seaLevel) / (islandGenerationPercent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getBaseTerrainHeight(int worldX, int worldZ) {
|
||||||
|
double terrainVal = getTerrainValue(worldX, worldZ);
|
||||||
|
return (int) Math.max(Math.min(terrainVal, maxHeightAboveSea + seaLevel), lowestSeaFloor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using DFS, determines if two given blocks are from the same island.
|
||||||
|
* Works by checking if a path can be drawn between these two.
|
||||||
|
* @param firstBlockX The x coord of the first block.
|
||||||
|
* @param firstBlockZ The z coord of the first block.
|
||||||
|
* @param secondBlockX The X coord of the first block.
|
||||||
|
* @param secondBlockZ The Z coord of the first block.
|
||||||
|
* @return true if the two blocks are on the same island, and false otherwise.
|
||||||
|
*/
|
||||||
public boolean isSameIsland(int firstBlockX, int firstBlockZ, int secondBlockX, int secondBlockZ) {
|
public boolean isSameIsland(int firstBlockX, int firstBlockZ, int secondBlockX, int secondBlockZ) {
|
||||||
if (!isIsland(firstBlockX, firstBlockZ)) return false;
|
if (!isIsland(firstBlockX, firstBlockZ)) return false;
|
||||||
if (!isIsland(secondBlockX, secondBlockZ)) return false;
|
if (!isIsland(secondBlockX, secondBlockZ)) return false;
|
||||||
|
dfs.setStartNode(secondBlockX, secondBlockZ, firstBlockX, firstBlockZ);
|
||||||
int xDirection = (secondBlockX - firstBlockX) / Math.abs(secondBlockX - firstBlockX);
|
boolean res = dfs.isConnected();
|
||||||
for (int xPos = firstBlockX; xPos != secondBlockX; xPos += xDirection) {
|
dfs.deleteTree();
|
||||||
if (!isIsland(xPos, firstBlockZ)) {
|
return res;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int zDirection = (secondBlockZ - secondBlockZ) / Math.abs(secondBlockZ - secondBlockZ);
|
@Override
|
||||||
for (int zPos = firstBlockZ; zPos != secondBlockZ; zPos += zDirection) {
|
public boolean validate(int x, int y) {
|
||||||
if (!isIsland(secondBlockX, zPos)) {
|
return isIsland(x, x);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user