I wrote something that will first randomly populate a square a with grass tiles, and then from there it will calculate tile types from each tile's surrounding tiles. My ultimate goal is generate a terrain that somewhat resembles an island.
My first step:
Then I use cellular automata / box filtering to smooth out the terrain (thanks Arcane Engineer):
where results are far from smooth, at least according to some examples I've seen online.
Here's the code:
private void SetupTiles()
{
//get reference positions
int centerRow = chunk.size / 2;
int centerCol = chunk.size / 2;
// Loop through the chunk and add tiles
for(int row = 0; row < chunk.size; row ++)
{
for(int col = 0; col < chunk.size; col ++)
{
//Water - 0
//Grass - 1
//Create TILE
//default tile is water
Tile tile = new Tile(col, row, chunk.tileSize, tileType.Water, GetRandomWaterTexture());
//since the island is smaller than chunk,
//check if current index is within island size.
if(row >= border && row < (chunkSize-border) && col >= border && col < (chunkSize-border))
{
//Randomly assign tiles type
//TODO: This random system is not very good...
if(MathUtils.random(100)>50)
{
tile.texture = GetRandomGrassTexture();
tile.type = tileType.Grass;
}
}
//add tile to chunk.
chunk.tiles[row][col] = tile;
}
}
//Initialize smoothedChunk with water
//At this point, chunk is randomly filled with grass, and smoothedChunk is just water.
for(int i = 0; i < chunkSize; i++)
{
for(int j = 0; j < chunkSize; j++)
{
Tile tile = new Tile(i, j, 8, tileType.Water, GetRandomWaterTexture());
smoothedChunk.tiles[i][j] = tile;
}
}
//TODO: Smoothed island is not really smooth...
//Smooth out chunk
SmoothMap();
//Set centre tile for camera positioning
centreTile = chunk.GetTile(centerRow, centerCol);
}
private void SmoothMap ()
{
//first loop, get surrounding tiles for each tile in chunk
//we are excluding the outer most edge
for(int r = 1; r < chunkSize-1; r++)
{
for(int c = 1; c < chunkSize-1; c++)
{
//if current tile is not null
if(chunk.tiles[r][c] != null)
{
//Get its surrounding tiles.
//At this point, smoothedChunk is still empty.
chunk.tiles[r][c].surroundingTiles = GetSurroundingTiles(r, c, chunk);
//Debug info
//System.out.println("Position: " + chunk.tiles[r][c].row + ", " + chunk.tiles[r][c].col);
//System.out.println("Current tile type: " + chunk.GetTileCode(r, c));
//System.out.println("Neighboring tiles: " + chunk.tiles[r][c].surroundingTiles);
//System.out.println();
}
}
}
//second loop, smooth tiles according to their surrounding tiles
for(int r = 1; r < chunkSize-1; r++)
{
for(int c = 1; c < chunkSize-1; c++)
{
//Write into smoothedChunk
//can the threshold be a variable?
if (chunk.tiles[r][c].surroundingTiles >= 4)
{
smoothedChunk.tiles[r][c].texture = GetRandomWaterTexture();
smoothedChunk.tiles[r][c].type = tileType.Water;
}
else if (chunk.tiles[r][c].surroundingTiles < 4)
{
smoothedChunk.tiles[r][c].texture = GetRandomGrassTexture();
smoothedChunk.tiles[r][c].type = tileType.Grass;
}
}
}
//copy tiles over from smoothedChunk to chunk,
//because we still want to use chunk for everything.
for(int i = 0; i < chunkSize; i++)
{
for(int j = 0; j < chunkSize; j++)
{
chunk.tiles[i][j] = smoothedChunk.tiles[i][j];
}
}
//don't know the difference between the loop above and
//chunk = smoothedChunk;
}
Does anybody have any idea why my results are so... unsatisfactory?
If I could achieve something like this I would be really happy (excluding the color variation):

