Friday, June 5, 2015

Using Noise to Generate Game Maps

There is absolutely no technical tie-in to the comic today. It's just tree puns. Sorry. But since trees are part of the landscape, I thought this might be a good time to share some of what I'm working on with noise and map generation.

Yes, noise. Noise can generate random game maps. Not noise like that new Google Chrome plugin thing that sends URLs to people nearby using your computer speakers (interesting, but odd), noise as in Perlin noise.

Perlin noise is a procedural way to generate pseudo-random textures that appear more natural than those created with alternative methods. It was invented by Ken Perlin in 1983 while working on the CGI for the movie Tron.

I learned about this just over a month ago at a local Meetup group. If you consider that the map in a computer game is like a texture, Perlin noise can be used to easily generate terrain which seems realistic. I want to use this is a side project I'm working on for Amphibian.com but I haven't had much time to experiment with it until this week. I now have a JavaScript utility that generates the noise so I can generate randomized maps both in the client browser and in my Node.js server.

I am using a noise generation library, perlin.js, by Joseph Gentle. It is based on Stefan Gustavson's public domain implementation and can be found here on GitHub: https://github.com/josephg/noisejs

Here is a simple example of it in action.

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Perlin Noise</title>
  <style>
    body {
      margin: 0px;
    }

    div {
      height: 40px;
    }

  </style>
</head>

<body>

  <div id="map"></div>

</body>

<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="perlin.js"></script>
<script>

var width = 33;
var height = 17;

noise.seed(Math.random());

for (var y = 0; y < height; y++) {

  var row = "<div>";

  for (var x = 0; x < width; x++) {

    var value = noise.simplex2( y / height, x / width );

    var e = "grass";
    if (value > 0.5) {
        e = "grass2";
    } else if (value < -0.5) {
        e = "water";
    }

    row += "<span><img src='" + e + ".png'/></span>";

  }

  row += "</div>";
  $("#map").append(row);

}

</script>

</html>

I'm building a simple map out three possible tile images: grass, rough grass, and water. They are just 40x40 squares which are either green, green with darker green lines, or blue.

grass.png
grass2.png
water.png
I am looping over the height and width values and generating a noise value for each cell of the grid. The noise value will always be between -1 and 1. The "default" cell is grass. If the noise value is over 0.5 then that cell becomes rough grass. If it is under -0.5 it becomes water. I am just throwing the images in span tags wrapped in div rows for the purposes of this example. Try it yourself and see what it looks like. Hit refresh on your browser to generate a different random landscape each time. They always look fairly natural with the way the water and rough grass group together and intermingle with the plain grass tiles.

Look at a few of the ones I generated.




Now if I could just randomly generate some comics. Fifty percent of the time, they'd be funny all of the time.

Amphibian.com comic for 5 June 2015