Thankyou very much for this! I like the randomness and I love the code but do you know if there is any way to make it less "holey". There are specks of water all over the terrain and what I am going for is more of a solid island surrounded by water
You're probably better off writing your own noise function if you want that amount of control. The problem is both with the perlin noise and the island mask. Some fixes that make it a bit better:
//Little program to generate test map with only 0 and 1 tile
#include <iostream>
#include <noise/noise.h>
#include "noiseutils.h"
#include <stdlib.h>
#include <string>
#include <sstream>
#define MAP_SIZE 512
using namespace std;
using namespace noise;
template <typename T> string tostring (T v) {
ostringstream ss;
ss << v;
return ss.str();
}
void generate_island(int iseed) {
module::Perlin myModule;
myModule.SetSeed (iseed);
utils::NoiseMap heightMap;
utils::NoiseMapBuilderPlane heightMapBuilder;
heightMapBuilder.SetSourceModule(myModule);
heightMapBuilder.SetDestNoiseMap(heightMap);
heightMapBuilder.SetDestSize(MAP_SIZE, MAP_SIZE);
heightMapBuilder.SetBounds(2.0, 6.0, 1.0, 5.0);
heightMapBuilder.Build();
float islandMap[MAP_SIZE][MAP_SIZE];
srand(iseed);
for (int count = 0; count < 1; count++ ){
//Initialize values for a new map
for (int i = 0; i < MAP_SIZE; i++) {
for (int j = 0; j < MAP_SIZE; j++) {
islandMap[j][i] = 0;
}
}
//Choose a random location, travel in random directions
int x = 0, y = 0;
int sx = 0, sy = 0;
int size = MAP_SIZE / 2;
int distance = 0;
for (int i = 0; i < 1000000; i++) {
int dx = x - sx;
int dy = y - sy;
distance = dx * dx + dy * dy;
if((y > MAP_SIZE - 1) || y < 0 || (x > MAP_SIZE - 1) || x < 0 || distance > 5000) {
x = rand() % size / 2 + rand() % size / 2 + MAP_SIZE / 2 - size / 2;
y = rand() % size / 2 + rand() % size / 2 + MAP_SIZE / 2 - size / 2;
sx = x;
sy = y;
}
++islandMap[x][y];
switch(rand() % 4) {
case 0:
++x;
break;
case 1:
--y;
break;
case 2:
--x;
break;
case 3:
++y;
break;
default:
break;
}
}
//find max value for normalizing
for (int i = 0; i < MAP_SIZE; i++) {
for (int j = 0; j < MAP_SIZE; j++) {
islandMap[i][j] = islandMap[i][j] * 2 - 1;
}
}
int max = 0;
int min = 0;
for (int i = 0; i < MAP_SIZE; i++) {
for (int j = 0; j < MAP_SIZE; j++) {
if(max < islandMap[i][j]) {
max = islandMap[i][j];
}
if(min > islandMap[i][j]) {
min = islandMap[i][j];
}
}
}
//Multiply values of original by new maps generated
for (int i = 0; i < MAP_SIZE; i++) {
for (int j = 0; j < MAP_SIZE; j++) {
float islandValue = (islandMap[i][j] - min) / (max - min);
float mapValue = (heightMap.GetValue(i, j) + 1) / 2;
float newValue = 2 * islandValue * mapValue - 1;
heightMap.SetValue(i, j, newValue);
}
}
}
utils::RendererImage renderer;
utils::Image image;
renderer.SetSourceNoiseMap (heightMap);
renderer.SetDestImage (image);
renderer.ClearGradient ();
renderer.AddGradientPoint (-1.0000, utils::Color ( 0, 0, 255, 255)); // shallow
renderer.AddGradientPoint (-0.9701, utils::Color ( 0, 0, 255, 255)); // shallow
renderer.AddGradientPoint (-0.9700, utils::Color ( 0, 128, 255, 255)); // shore
renderer.AddGradientPoint (-0.9690, utils::Color ( 0, 128, 255, 255)); // shore
renderer.AddGradientPoint (-0.9689, utils::Color (240, 240, 64, 255)); // sand
renderer.AddGradientPoint (-0.9601, utils::Color (240, 240, 64, 255)); // sand
renderer.AddGradientPoint (-0.9600, utils::Color ( 32, 160, 0, 255)); // grass
renderer.AddGradientPoint (-0.4991, utils::Color ( 32, 160, 0, 255)); // grass
renderer.AddGradientPoint (-0.4990, utils::Color ( 0, 0, 0, 255)); // pines
renderer.AddGradientPoint (-0.4987, utils::Color ( 0, 0, 0, 255)); // pines
renderer.AddGradientPoint (-0.3986, utils::Color (96, 63, 0, 255)); // dirt
renderer.AddGradientPoint ( 0.0000, utils::Color (96, 63, 0, 255)); // dirt
renderer.AddGradientPoint ( 0.0001, utils::Color (128, 128, 128, 255)); // rock
renderer.AddGradientPoint ( 1.0000, utils::Color (128, 128, 128, 255)); // rock
renderer.EnableLight ();
renderer.SetLightContrast (3.0);
renderer.SetLightBrightness (2.0);
renderer.Render ();
utils::WriterBMP writer;
writer.SetSourceImage (image);
writer.SetDestFilename ("tutorial" + tostring(iseed) + ".bmp");
writer.WriteDestFile ();
}
int main() {
for(int i=0; i<10; ++i){
generate_island(i);
}
return 0;
}
The island mask consists of many random walks added together. The random walks scale poorly with size of the map (change the MAP_SIZE to see for yourself) because they tend to diverge very quickly. With the above code I've applied two methods two remedy this a bit:
- Terminate any random walk if they get beyond a certain distance away from their origin.
- Make the starting point of any random walk more likely to be in the middle with a triangular distribution and within a smaller region (controlled with the 'size' variable).
Play a bit with the numbers to see if you can improve the results.
If you want to try something else try this instead: http://en.wikipedia.org/wiki/Diamond-square_algorithm If you set the first N levels yourself instead of randomly generating them you get much more control over the final output.