{"id":13,"date":"2011-05-16T20:26:32","date_gmt":"2011-05-17T01:26:32","guid":{"rendered":"http:\/\/www.playwithlua.com\/?p=13"},"modified":"2020-05-22T13:20:14","modified_gmt":"2020-05-22T18:20:14","slug":"generating-heightmaps-in-lua","status":"publish","type":"post","link":"http:\/\/www.playwithlua.com\/?p=13","title":{"rendered":"Generating Heightmaps in Lua"},"content":{"rendered":"<p>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.<\/p>\n<p>To start off with, here&#8217;s how I create a Lua map class: I start by making a &#8220;Map&#8221; table that contains a &#8220;methods&#8221; table. Anything class-level (what Java would call &#8220;static&#8221;) 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&#8217;m using 16 elevation levels):<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\">Map <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #66cc66;\">&#123;<\/span>methods<span style=\"color: #66cc66;\">=<\/span><span style=\"color: #66cc66;\">&#123;<\/span><span style=\"color: #66cc66;\">&#125;<\/span><span style=\"color: #66cc66;\">&#125;<\/span>\n&nbsp;\n<span style=\"color: #808080; font-style: italic;\">-- Make a grid of random values 0..15, or a fill value<\/span>\n<span style=\"color: #aa9900; font-weight: bold;\">function<\/span> Map<span style=\"color: #66cc66;\">.<\/span>new<span style=\"color: #66cc66;\">&#40;<\/span>width<span style=\"color: #66cc66;\">,<\/span> height<span style=\"color: #66cc66;\">,<\/span> fill<span style=\"color: #66cc66;\">&#41;<\/span>\n   <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> map <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #66cc66;\">&#123;<\/span>width<span style=\"color: #66cc66;\">=<\/span>width<span style=\"color: #66cc66;\">,<\/span> height<span style=\"color: #66cc66;\">=<\/span>height<span style=\"color: #66cc66;\">&#125;<\/span>\n   <span style=\"color: #0000aa;\">setmetatable<\/span><span style=\"color: #66cc66;\">&#40;<\/span>map<span style=\"color: #66cc66;\">,<\/span><span style=\"color: #66cc66;\">&#123;<\/span>__index<span style=\"color: #66cc66;\">=<\/span>Map<span style=\"color: #66cc66;\">.<\/span>methods<span style=\"color: #66cc66;\">&#125;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n&nbsp;\n   <span style=\"color: #aa9900; font-weight: bold;\">for<\/span> n <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #cc66cc;\">1<\/span><span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #66cc66;\">&#40;<\/span>width <span style=\"color: #66cc66;\">*<\/span> height<span style=\"color: #66cc66;\">&#41;<\/span> <span style=\"color: #aa9900; font-weight: bold;\">do<\/span>\n\t  map<span style=\"color: #66cc66;\">&#91;<\/span>n<span style=\"color: #66cc66;\">&#93;<\/span> <span style=\"color: #66cc66;\">=<\/span> fill <span style=\"color: #aa9900; font-weight: bold;\">or<\/span> <span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #0000aa;\">math.random<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #cc66cc;\">16<\/span><span style=\"color: #66cc66;\">&#41;<\/span> <span style=\"color: #66cc66;\">-<\/span> <span style=\"color: #cc66cc;\">1<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n   <span style=\"color: #aa9900; font-weight: bold;\">end<\/span>\n&nbsp;\n   <span style=\"color: #aa9900; font-weight: bold;\">return<\/span> map\n<span style=\"color: #aa9900; font-weight: bold;\">end<\/span><\/pre><\/div><\/div><\/div>\n\n<p>Pretty basic so far. I&#8217;ll add a few methods like <code>at<\/code> and <code>set<\/code> that change values based on x and y coordinates.<\/p>\n<p><!--more-->One tricky thing: Lua libraries expect tables to be indexed from 1 (although it doesn&#8217;t really matter). So, I (probably inadvisedly) made mine like that, and then got plagued by off-by-one errors because I&#8217;ve written this class so many times in other languages that it&#8217;s practically muscle memory.<\/p>\n<p>So anyway, I&#8217;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:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\"><span style=\"color: #aa9900; font-weight: bold;\">function<\/span> Map<span style=\"color: #66cc66;\">.<\/span>methods<span style=\"color: #66cc66;\">.<\/span>smooth<span style=\"color: #66cc66;\">&#40;<\/span>self<span style=\"color: #66cc66;\">&#41;<\/span>\n   <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> new <span style=\"color: #66cc66;\">=<\/span> Map<span style=\"color: #66cc66;\">.<\/span>copy<span style=\"color: #66cc66;\">&#40;<\/span>self<span style=\"color: #66cc66;\">&#41;<\/span>\n&nbsp;\n   <span style=\"color: #aa9900; font-weight: bold;\">for<\/span> x <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #cc66cc;\">0<\/span><span style=\"color: #66cc66;\">,<\/span> self<span style=\"color: #66cc66;\">.<\/span>width<span style=\"color: #66cc66;\">-<\/span><span style=\"color: #cc66cc;\">1<\/span> <span style=\"color: #aa9900; font-weight: bold;\">do<\/span>\n   \t  <span style=\"color: #aa9900; font-weight: bold;\">for<\/span> y <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #cc66cc;\">0<\/span><span style=\"color: #66cc66;\">,<\/span> self<span style=\"color: #66cc66;\">.<\/span>height<span style=\"color: #66cc66;\">-<\/span><span style=\"color: #cc66cc;\">1<\/span> <span style=\"color: #aa9900; font-weight: bold;\">do<\/span>\n\t\t <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> n <span style=\"color: #66cc66;\">=<\/span> self<span style=\"color: #66cc66;\">:<\/span>p2n<span style=\"color: #66cc66;\">&#123;<\/span>x<span style=\"color: #66cc66;\">=<\/span>x<span style=\"color: #66cc66;\">,<\/span>y<span style=\"color: #66cc66;\">=<\/span>y<span style=\"color: #66cc66;\">&#125;<\/span>\n\t\t <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> s<span style=\"color: #66cc66;\">,<\/span> c <span style=\"color: #66cc66;\">=<\/span> self<span style=\"color: #66cc66;\">:<\/span>neighbor_sum<span style=\"color: #66cc66;\">&#40;<\/span>x<span style=\"color: #66cc66;\">,<\/span> y<span style=\"color: #66cc66;\">&#41;<\/span>\n\t\t <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> nv <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #66cc66;\">&#40;<\/span>self<span style=\"color: #66cc66;\">:<\/span>at<span style=\"color: #66cc66;\">&#40;<\/span>x<span style=\"color: #66cc66;\">,<\/span>y<span style=\"color: #66cc66;\">&#41;<\/span> <span style=\"color: #66cc66;\">+<\/span> s<span style=\"color: #66cc66;\">&#41;<\/span> <span style=\"color: #66cc66;\">\/<\/span> <span style=\"color: #66cc66;\">&#40;<\/span>c <span style=\"color: #66cc66;\">+<\/span> <span style=\"color: #cc66cc;\">1<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n\t\t new<span style=\"color: #66cc66;\">&#91;<\/span>n<span style=\"color: #66cc66;\">&#93;<\/span> <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #0000aa;\">math<\/span><span style=\"color: #66cc66;\">.<\/span>round<span style=\"color: #66cc66;\">&#40;<\/span>nv<span style=\"color: #66cc66;\">&#41;<\/span>\n\t  <span style=\"color: #aa9900; font-weight: bold;\">end<\/span>\n   <span style=\"color: #aa9900; font-weight: bold;\">end<\/span>\n&nbsp;\n   <span style=\"color: #aa9900; font-weight: bold;\">return<\/span> new\n<span style=\"color: #aa9900; font-weight: bold;\">end<\/span><\/pre><\/div><\/div><\/div>\n\n<p>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 8&#215;8 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.<\/p>\n<p>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).<\/p>\n<p>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&#8217;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&#8217;s an example:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"c\" style=\"font-family:monospace;\"><span style=\"color: #808080; font-style: italic;\">\/* XPM *\/<\/span>\n<span style=\"color: #993333;\">static<\/span> <span style=\"color: #993333;\">char<\/span> <span style=\"color: #339933;\">*<\/span> map_xpm<span style=\"color: #009900;\">&#91;<\/span><span style=\"color: #009900;\">&#93;<\/span> <span style=\"color: #339933;\">=<\/span> <span style=\"color: #009900;\">&#123;<\/span>\n<span style=\"color: #ff0000;\">&quot;16 16 16 1&quot;<\/span><span style=\"color: #339933;\">,<\/span>\n<span style=\"color: #ff0000;\">&quot;0 c #000033&quot;<\/span><span style=\"color: #339933;\">,<\/span>\n<span style=\"color: #ff0000;\">&quot;1 c #000044&quot;<\/span><span style=\"color: #339933;\">,<\/span>\n<span style=\"color: #ff0000;\">&quot;2 c #000055&quot;<\/span><span style=\"color: #339933;\">,<\/span>\n. . . <span style=\"color: #202020;\">etc<\/span> . . .\n<span style=\"color: #ff0000;\">&quot;45575569ca787679&quot;<\/span><span style=\"color: #339933;\">,<\/span>\n<span style=\"color: #ff0000;\">&quot;3457679aa998977a&quot;<\/span><span style=\"color: #339933;\">,<\/span>\n<span style=\"color: #ff0000;\">&quot;4557799889b889ab&quot;<\/span><span style=\"color: #339933;\">,<\/span>\n. . . <span style=\"color: #202020;\">etc<\/span> . . .\n<span style=\"color: #009900;\">&#125;<\/span><\/pre><\/div><\/div><\/div>\n\n<p>Becomes this:<br \/>\n<img loading=\"lazy\" class=\"alignnone size-full wp-image-14\" title=\"tinymap\" src=\"http:\/\/www.playwithlua.com\/wp-content\/uploads\/2011\/05\/tinymap.png\" alt=\"\" width=\"64\" height=\"64\" \/><\/p>\n<p>So, since I can chain everything together, after playing with it some, I ended up with this to create a map:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\"><span style=\"color: #0000aa;\">math.randomseed<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #cc66cc;\">1<\/span><span style=\"color: #66cc66;\">&#41;<\/span> <span style=\"color: #808080; font-style: italic;\">-- Or whatever...<\/span>\nm <span style=\"color: #66cc66;\">=<\/span> Map<span style=\"color: #66cc66;\">.<\/span>new<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #cc66cc;\">17<\/span><span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #cc66cc;\">17<\/span><span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">:<\/span>smooth<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">:<\/span>scale<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #cc66cc;\">8<\/span><span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">:<\/span>fractal_tile<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #cc66cc;\">8<\/span><span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">:<\/span>smooth<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">:<\/span>slice<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #cc66cc;\">0<\/span><span style=\"color: #66cc66;\">,<\/span><span style=\"color: #cc66cc;\">0<\/span><span style=\"color: #66cc66;\">,<\/span><span style=\"color: #cc66cc;\">128<\/span><span style=\"color: #66cc66;\">,<\/span><span style=\"color: #cc66cc;\">128<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\nfile <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #0000aa;\">io.open<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #ff6666;\">&quot;map.xpm&quot;<\/span><span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #ff6666;\">&quot;w&quot;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\nfile<span style=\"color: #66cc66;\">:<\/span><span style=\"color: #0000aa;\">write<\/span><span style=\"color: #66cc66;\">&#40;<\/span>m<span style=\"color: #66cc66;\">:<\/span>xpm<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #66cc66;\">&#41;<\/span><span style=\"color: #66cc66;\">&#41;<\/span><\/pre><\/div><\/div><\/div>\n\n<p>(Since what I&#8217;m scaling are actually the spaces between cells, in order to get 16 tiles with corners I need a seed map 17&#215;17)<\/p>\n<p>So, enough chatter. Let&#8217;s look at a few random maps:<\/p>\n<p><img loading=\"lazy\" class=\"alignnone size-full wp-image-15\" title=\"map1\" src=\"http:\/\/www.playwithlua.com\/wp-content\/uploads\/2011\/05\/map1.png\" alt=\"\" width=\"128\" height=\"128\" \/> <img loading=\"lazy\" class=\"alignnone size-full wp-image-16\" title=\"map2\" src=\"http:\/\/www.playwithlua.com\/wp-content\/uploads\/2011\/05\/map2.png\" alt=\"\" width=\"128\" height=\"128\" \/> <img loading=\"lazy\" class=\"alignnone size-full wp-image-17\" title=\"map3\" src=\"http:\/\/www.playwithlua.com\/wp-content\/uploads\/2011\/05\/map3.png\" alt=\"\" width=\"128\" height=\"128\" \/><\/p>\n<p><a onclick=\"javascript:pageTracker._trackPageview('\/outgoing\/gist.github.com\/973517');\"  href=\"http:\/\/gist.github.com\/973517\">Here&#8217;s the code.<\/a> I think these came out much better than my last attempt at mapmaking. The elevations actually work; mountains slope gradually down into seas.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;s how I create a Lua map class: I start by making a &#8220;Map&#8221; table that contains a &#8220;methods&#8221; table. Anything class-level (what [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts\/13"}],"collection":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=13"}],"version-history":[{"count":0,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts\/13\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=13"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=13"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=13"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}