rbandrews: (Default)
[personal profile] rbandrews
Lua is a pretty much ideal language for playing around with map generating functions. I made a cute one today, combining linear noise with a couple other things.

To start off with, here's how I create a Lua map class: I start by making a "Map" table that contains a "methods" table. Anything class-level (what Java would call "static") goes in Map; anything instance-level goes is Map.methods. I make a Map.new function that creates a new Map of a certain size, filling it with either a constant value or linear noise (I'm using 16 elevation levels):
Map = {methods={}}

-- Make a grid of random values 0..15, or a fill value
function Map.new(width, height, fill)
   local map = {width=width, height=height}
   setmetatable(map,{__index=Map.methods})

   for n = 1, (width * height) do
	  map[n] = fill or (math.random(16) - 1)
   end

   return map
end
Pretty basic so far. I'll add a few methods like at and set that change values based on x and y coordinates.

One tricky thing: Lua libraries expect tables to be indexed from 1 (although it doesn't really matter). So, I (probably inadvisedly) made mine like that, and then got plagued by off-by-one errors because I've written this class so many times in other languages that it's practically muscle memory.

So anyway, I'm going to skip a lot of these functions and just describe what they do. I start off with a small map that I fill with noise, then run a simple smoothing function over. The smoothing function just takes, for each cell, the average of its value and the values of all its neighbors:
function Map.methods.smooth(self)
   local new = Map.copy(self)

   for x = 0, self.width-1 do
   	  for y = 0, self.height-1 do
		 local n = self:p2n{x=x,y=y}
		 local s, c = self:neighbor_sum(x, y)
		 local nv = (self:at(x,y) + s) / (c + 1)
		 new[n] = math.round(nv)
	  end
   end

   return new
end
I keep this pattern of having every method return self so I can chain methods together. Then, I scale the map up 8x, by making an 8x8 tile for each pixel, with the corners being the adjacent pixels. So, the pixel at (0,0) becomes the upper-left corner of a tile that also has (1,0) at the upper right, (0,1) at the lower left, and so on.

Now I can fractalize it. For each tile I pick new pixels to go in the middle of each edge and in the center, so the middle of the left side will be either the top-left or bottom-left pixels, and so on. Now I can divide it into four new tiles and recurse (because the new tiles have values in each of their corners).

Once I recurse all the way to the bottom, I run the smoothing function one more time on the new map and then print it out. Making an image out of it is another little trick: rather than deal with finding an image-writing library and figuring out its API, since I'm just playing around, I write the image data by hand in XPM format. X Pixmap is a really simple image format, readable by the Gimp and Emacs, that was invented for storing X Windows icons, and is human-readable and trivial to write. Here's an example:
/* XPM */
static char * map_xpm[] = {
"16 16 16 1",
"0 c #000033",
"1 c #000044",
"2 c #000055",
. . . etc . . .
"45575569ca787679",
"3457679aa998977a",
"4557799889b889ab",
. . . etc . . .
}
Becomes this:


So, since I can chain everything together, after playing with it some, I ended up with this to create a map:
math.randomseed(1) -- Or whatever...
m = Map.new(17, 17):smooth():scale(8):fractal_tile(8):smooth():slice(0,0,128,128)
file = io.open("map.xpm", "w")
file:write(m:xpm())
(Since what I'm scaling are actually the spaces between cells, in order to get 16 tiles with corners I need a seed map 17x17)

So, enough chatter. Let's look at a few random maps:



I think these came out much better than my last attempt at mapmaking. The elevations actually work; mountains slope gradually down into seas.
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

Profile

rbandrews: (Default)
rbandrews

July 2024

S M T W T F S
 123456
78910111213
14151617181920
212223242526 27
28293031   

Style Credit

Page generated Jun. 20th, 2025 06:45 am
Powered by Dreamwidth Studios

Expand Cut Tags

No cut tags