I'm working on a framework for city-builders (similar in appearance to SimCity2000, Tropico, Populous). I'm not actually making a game, it's more just to learn some techniques. I'll probably release it as a library if I get anywhere with it.

Has anyone here ever worked on anything similar who could give any nifty tricks for generating landscapes?

At the moment I'm using a matrix of 'elevation values' to dictate the heights of the vertices where turfs corners meet. I'm essentially just placing circles of elevation=1 at random within a bounding box of that matrix. Which seems like a pretty brain-dead way of doing it. What better alternatives are there?

Then I'm transferring that matrix to turfs to render them in pseudo-3D using isometric sprites and pixel-offsets). Here's how it looks so far: http://filesmelt.com/dl/island6.png

Then there's the issue of mountains. I was thinking of placing a few random 'peaks' and then using a blur algorithm on my matrix to smooth it out into mountains and hills and stuff. I'd then pass back over and add a few random lumps and bumps. What alternatives are there? Drawing concentric circles adding 1 to the elevation value each time?

The grand plan is to have a semi-realistic weather system. Wind will change direction over time creating a vector-field over the map. Clouds will pass overhead, pick up moisture from the sea and release it according to the elevation of turfs below it. This would all influence fertility of farmland, soil-erosion, flooding etc.

So, lots of questions. :S

Any links to examples/other-games/guides that could help would be very much appreciated. Even if it's games that look similar that I could go to for inspiration.

Thanks for your time.

Here's what the bulk of the code looks like so far, it's yet to be optimised or anything.

**MapGen Code:**

var/datum/map_generator/mapgen = new /datum/map_generator()

/datum/map_generator

var/list/matrix

var/max_elevation = 10

var/water

var/water_max = 10

var/island_size = 30

var/min_radius = 2

var/max_radius = 5

var/min_edge

var/max_edge

proc/make_new_island(placement, seed, new_island_size, new_water_max)

set background = 1

//Using a pre-defined PRNG seed

if(seed) rand_seed(seed)

//Initializing variables:

//Island

if(new_island_size > 30)

island_size = round(new_island_size)

var/island_area = island_size*island_size //Number of elements in the matrix

//Water

if(new_water_max > 0.1 && new_water_max < 0.9)

water_max = round(new_water_max * island_area)

water = island_area //Island starts as a sea

//Initializing the island's Matrix

matrix = new /list(island_size,island_size)

min_edge = max_radius + 1

max_edge = island_size - min_edge

switch(placement)

if(1)

place_lumps_on_square()

else

place_lumps_randomly()

proc/place_lumps_randomly()

var/iter = 1

while(1)

if(iter++ > 999) break

if(water_max > water) break

var/x = rand(min_edge,max_edge)

var/y = rand(min_edge,max_edge)

var/radius = rand(min_radius,max_radius)

place_lump(x,y,radius)

proc/place_lumps_on_square()

var/iter = 1

while(1)

if(iter++ > 999) break

if(water_max > water) break

var/center = round(island_size/2)

var/ring_radius = round(center/2)

var/hits = 0

for(var/i=-ring_radius,i<=ring_radius,i++)

for(var/j=-ring_radius,j<=ring_radius,j++)

matrix[center+i][center+j] = 1

if(abs(i) == ring_radius && abs(j) == ring_radius)

if((hits++)%8 == 0)

place_lump(center+j,center+i,max_radius)

proc/place_lump(x,y,radius)

if(matrix[y][x]!=null) return

matrix[y][x] = 0

for(var/dx=1,dx<=radius,dx++)

for(var/dy=1,dy<=radius,dy++)

var/dist = cheap_pyth_hyp(dx, dy)

if(dist <= radius)

matrix[y+dy][x+dx] = 1

matrix[y-dy][x+dx] = 1

matrix[y+dy][x-dx] = 1

matrix[y-dy][x-dx] = 1

matrix[y+dx][x] = 1

matrix[y-dx][x] = 1

matrix[y][x+dx] = 1

matrix[y][x-dx] = 1

proc/commit_map()

elevationmatrix = matrix

matrix2map()

Matrix2Map

proc/matrix2map()

var/i_max = length(elevationmatrix)

var/j_max = length(elevationmatrix[1])

world.maxx = j_max - 1

world.maxy = i_max - 1

world.maxz = 1

var/list/icon_states = icon_states('wireframe2.dmi',1)

for(var/x=1,x<=world.maxx,x++)

for(var/y=1,y<=world.maxy,y++)

var/turf/T = locate(x,y,1)

if(!T) continue

T.gradient[1] = elevationmatrix[x][y+1]

T.gradient[2] = elevationmatrix[x+1][y+1]

T.gradient[3] = elevationmatrix[x+1][y]

T.gradient[4] = elevationmatrix[x][y]

var/lowest = 50

for(var/grad in T.gradient)

if(grad <= lowest)

if(grad == null)

grad = 0

lowest = grad

T.elevation = lowest

var/new_icon_state = ""

for(var/val in T.gradient)

if(val > T.elevation)

new_icon_state += "1"

else

new_icon_state += "0"

if(!(new_icon_state in icon_states))

world.log << "x=[x], y=[y]"

new_icon_state = "0000"

if(T.elevation == 0 && new_icon_state == "0000")

T.icon_state = "water"

else

T.icon_state = new_icon_state

T.pixel_y = 32*T.elevation

T.pixel_x = -T.pixel_y

Math:

//A very crude linear approximatiaon of pythagoras theorem.

/proc/cheap_pyth_hyp(dx, dy)

dx = abs(dx)

dy = abs(dy)

if(dx>=dy) return dx + (0.5*dy) //The longest side add half the shortest side approximates the hypotenuse

else return dy + (0.5*dx)

//we take EAST as theta = 0 and rotate anti-clockwise

/proc/polar2cartesian(r, theta)

return list(r * cos(theta), r * sin(theta))

//rotate a matrix counter-clockwise by rotation lots of 90degrees

/proc/rotate_matrix(list/matrix, rotation)

rotation %= 4

if(rotation < 0) rotation += 4 //ugh! BYOND! returning a value outside of the ring of positive integers.

var/i_max = length(matrix)

var/j_max = length(matrix[1])

switch(rotation)

if(1) //anticlockwise

. = new /list(j_max++,i_max++)

for(var/i=1,i<i_max,i++)

for(var/j=1,j<j_max,j++)

.[j_max-j][i] = matrix[i][j]

if(3) //clockwise

. = new /list(j_max++,i_max++)

for(var/i=1,i<i_max,i++)

for(var/j=1,j<j_max,j++)

.[j][i_max-i] = matrix[i][j]

if(2) //180 degrees

. = new /list(i_max++,j_max++)

for(var/i=1,i<i_max,i++)

for(var/j=1,j<j_max,j++)

.[i_max-i][j_max-j] = matrix[i][j]

else

. = new /list(i_max++,j_max++)

for(var/i=1,i<i_max,i++)

for(var/j=1,j<j_max,j++)

.[i][j] = matrix[i][j]

//Transpose a matrix

/proc/transpose_matrix(list/matrix)

var/i_max = matrix.len

var/j_max = length(matrix[1])

. = new /list(j_max++,i_max++)

for(var/i=1,i<i_max,i++)

for(var/j=1,j<j_max,j++)

.[j][i] = matrix[i][j]

Perlin Noise is quite a good algorithm to generate random terrain with random elevation, while keeping it smooth at the same time. Here's article and Python source: http://breinygames.blogspot.com/2012/06/ generating-terrain-using-perlin-noise.html