squidpony.squidgrid.mapping.MetsaMapFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squidlib-util Show documentation
Show all versions of squidlib-util Show documentation
SquidLib platform-independent logic and utility code. Please refer to
https://github.com/SquidPony/SquidLib .
package squidpony.squidgrid.mapping;
import squidpony.annotation.Beta;
import squidpony.squidmath.Coord;
import squidpony.squidmath.PerlinNoise;
import squidpony.squidmath.StatefulRNG;
import java.util.ArrayList;
import java.util.List;
/**
* A map generation factory using Perlin noise to make island chain style maps.
*
* Based largely on work done by Metsa from #rgrd
*
* @author Eben Howard - http://squidpony.com - [email protected]
*/
@Beta
public class MetsaMapFactory {
//HEIGHT LIMITS
public static final double SEA_LEVEL = 0,
BEACH_LEVEL = 0.15,
PLAINS_LEVEL = 0.5,
MOUNTAIN_LEVEL = 0.73,
SNOW_LEVEL = 0.95,
DEEP_SEA_LEVEL = -0.1;
//BIOMESTUFF
private final double POLAR_LIMIT = 0.65, DESERT_LIMIT = 0.15;
//SHADOW
private final double SHADOW_LIMIT = 0.01;
//COLORORDER
/*
0 = deepsea
1 = beach
2 = low
3 = high
4 = mountain
5 = snowcap
6 = lowsea
*/
// new SColor[]{SColor.DARK_SLATE_GRAY, SColor.SCHOOL_BUS_YELLOW, SColor.YELLOW_GREEN,
// SColor.GREEN_BAMBOO, SColorFactory.lighter(SColor.LIGHT_BLUE_SILK), SColor.ALICE_BLUE, SColor.AZUL};
// new SColor[]{SColor.DARK_SLATE_GRAY, SColor.SCHOOL_BUS_YELLOW, SColor.YELLOW_GREEN,
// SColor.GREEN_BAMBOO, SColorFactory.lighter(SColor.LIGHT_BLUE_SILK), SColor.ALICE_BLUE, SColor.AZUL};
private int width;
private int height;
private int CITYAMOUNT = 14;
private List cities = new ArrayList<>();
private StatefulRNG rng;
private double maxPeak = 0;
private double[][] map;
public MetsaMapFactory()
{
this(240, 120, new StatefulRNG());
}
public MetsaMapFactory(int width, int height)
{
this(width, height, new StatefulRNG());
}
public MetsaMapFactory(int width, int height, long rngSeed)
{
this(width, height, new StatefulRNG(rngSeed));
}
public MetsaMapFactory(int width, int height, StatefulRNG rng)
{
this.rng = rng;
this.width = width;
this.height = height;
map = makeHeightMap();
}
public int getShadow(int x, int y, double[][] map) {
if (x >= width - 1 || y <= 0) {
return 0;
}
double upRight = map[x + 1][y - 1];
double right = map[x + 1][y];
double up = map[x][y - 1];
double cur = map[x][y];
if (cur <= 0) {
return 0;
}
double slope = cur - (upRight + up + right) / 3;
if (slope < SHADOW_LIMIT && slope > -SHADOW_LIMIT) {
return 0;
}
if (slope >= SHADOW_LIMIT) {
return -1; //"alpha"
}
if (slope <= -SHADOW_LIMIT) {
return 1;
} else {
return 0;
}
}
/**
* Finds and returns the closest point containing a city to the given point.
* Does not include provided point as a possible city location.
*
* If there are no cities, null is returned.
*
* @param point
* @return
*/
public Coord closestCity(Coord point) {
double dist = 999999999, newdist;
Coord closest = null;
for (Coord c : cities) {
if (c.equals(point)) {
continue;//skip the one being tested for
}
newdist = Math.pow(point.x - c.x, 2) + Math.pow(point.y - c.y, 2);
if (newdist < dist) {
dist = newdist;
closest = c;
}
}
return closest;
}
public double[][] makeHeightMap() {
double[][] map = HeightMapFactory.heightMap(width, height, rng.nextInt() * 0x1p-16f);
for (int x = 0; x < width / 8; x++) {
for (int y = 0; y < height; y++) {
map[x][y] = map[x][y] - 1.0 + x / ((width - 1) * 0.125);
if (map[x][y] > maxPeak) {
maxPeak = map[x][y];
}
}
}
for (int x = width / 8; x < 7 * width / 8; x++) {
for (int y = 0; y < height; y++) {
map[x][y] = map[x][y];
if (map[x][y] > maxPeak) {
maxPeak = map[x][y];
}
}
}
for (int x = 7 * width / 8; x < width; x++) {
for (int y = 0; y < height; y++) {
map[x][y] = map[x][y] - 1.0 + (width - 1 - x) / ((width - 1) * 0.125);
if (map[x][y] > maxPeak) {
maxPeak = map[x][y];
}
}
}
return map;
}
public void regenerateHeightMap()
{
map = makeHeightMap();
}
public void regenerateHeightMap(int width, int height)
{
this.width = width;
this.height = height;
map = makeHeightMap();
cities.clear();
}
public int[][] makeBiomeMap() {
//biomes 0 normal 1 snow
int[][] biomeMap = new int[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
biomeMap[x][y] = 0;
double distanceFromEquator = Math.abs(y - height * 0.5) / (height * 0.5);
distanceFromEquator += PerlinNoise.noise(x * 0.0625, y * 0.0625) / 8 + map[x][y] / 32;
if (distanceFromEquator > POLAR_LIMIT) {
biomeMap[x][y] = 1;
}
if (distanceFromEquator < DESERT_LIMIT) {
biomeMap[x][y] = 2;
}
if (distanceFromEquator > POLAR_LIMIT + 0.25) {
biomeMap[x][y] = 3;
}
}
}
return biomeMap;
}
public int[][] makeNationMap() {
// nationmap, 4 times less accurate map used for nations -1 no nation
int[][] nationMap = new int[width][height];
for (int i = 0; i < width / 4; i++) {
for (int j = 0; j < height / 4; j++) {
if (map[i * 4][j * 4] < 0) {
nationMap[i][j] = -1;
} else {
nationMap[i][j] = 0;
}
}
}
return nationMap;
}
public double[][] makeWeightedMap() {
//Weighted map for road
double[][] weightedMap = new double[width][height];
double SEALEVEL = 0;
double BEACHLEVEL = 0.05;
double PLAINSLEVEL = 0.3;
for (int i = 0; i < width / 4; i++) {
for (int j = 0; j < height / 4; j++) {
weightedMap[i][j] = 0;
if (map[i * 4][j * 4] > BEACHLEVEL) {
weightedMap[i][j] = 2 + (map[i * 4][j * 4] - PLAINSLEVEL) * 8;
}
if (map[i][j] <= BEACHLEVEL && map[i * 4][j * 4] >= SEALEVEL) {
weightedMap[i][j] = 2 - map[i * 4][j * 4] * 2;
}
}
}
CITIES:
for (int i = 0; i < CITYAMOUNT; i++) {
int px = rng.between(0, width), py = rng.between(0, height), frustration = 0;
while (map[px][py] < SEALEVEL || map[px][py] > BEACHLEVEL) {
px = rng.between(0, width);
py = rng.between(0, height);
if(frustration++ > 20)
continue CITIES;
}
cities.add(Coord.get(4 * (px >> 2), 4 * (py >> 2)));
}
return weightedMap;
}
public List getCities() {
return cities;
}
public double getMaxPeak() {
return maxPeak;
}
public double[][] getHeightMap() {
return map;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
}