Umm, a somewhat ambiguous question, bear with me.
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 if(seed) rand_seed(seed) if(new_island_size > 30) island_size = round(new_island_size) var/island_area = island_size*island_size if(new_water_max > 0.1 && new_water_max < 0.9) water_max = round(new_water_max * island_area) water = island_area 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:
/proc/cheap_pyth_hyp(dx, dy) dx = abs(dx) dy = abs(dy) if(dx>=dy) return dx + (0.5*dy) else return dy + (0.5*dx)
/proc/polar2cartesian(r, theta) return list(r * cos(theta), r * sin(theta))
/proc/rotate_matrix(list/matrix, rotation) rotation %= 4 if(rotation < 0) rotation += 4 var/i_max = length(matrix) var/j_max = length(matrix[1]) switch(rotation) if(1) . = 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) . = 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) . = 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]
/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