Projects

# Random Skylines

I play Cities: Skylines quite a bit, albeit not much in the last few weeks. I’m very excited just for the free features of the Mass Transit expansion but personally think the game was pretty great as it was more or less at launch—if we had been stuck with that without further updates it still would have been my “Game of the Year, Every Year.”

Sometime last year I got into making my own maps to build on, a time-consuming but rewarding experience. The maps that the game comes with become limiting after a while, and although Steam has innumerable user-created maps floating around I prefer to shape my own. The problem is that I always feel my maps lack a certain something in the way of terrain features, particularly when it comes to things like the ridgelines and valleys I see so much around me where I live.

What I need, I think, is a random map generator that can create the kind of height map that I need for a given idea, and then I can tweak it as I want. The Skylines map editor already has 1081×1081 pixel greyscale heightmap import (and export) capabilities; all I need is to make an external tool to produce them.

As an aside, there already exists a tool called terrain.party which allows you to grab Skylines-compatible heightmaps from real terrain, but these have a number of flaws (particularly when it comes to the shoreline) and in my personal opinion carry too much attachment to what is really at that location in the real world.

So this comes to the issue of random terrain generation, for which not all of the tutorials on the internet have “now finish the rest of the owl” syndrome (though too many do). After a bit of playing I rejected using the midpoint displacement algorithm as it relies too greatly on powers of 2 plus 1 ($2^n + 1$)—a set which 1081 definitely is not among. Instead I turned to Perlin noise, which is arguably cheating.

To summarise, when you typically assign random values to points you wind up with the value of one point being completely independent of the value of any of its neighbours. This would produce a useless, spiky terrain. Instead the value of a noise function can be expected to be relatively similar at nearby points, though still “random” over all. This would instead produce a landscape of rolling hills, all random and yet all the same. Perlin noise works by adding a whole lot of noise functions of different sizes together, producing a much more interesting if not quite realistic map.

A slight modification can be made to this to make mountains steeper and plains flatter, by raising a number (here 6) to the power of the perlin function.

```#include <png++/png.hpp>
#include <iostream>
#include <libnoise/noise.h> // From the libnoise library
#include <ctime>
#include <utility>
#include <cmath> // Include libm for pow function

// ...

std::pair<double, double> perlinize(double ** map, int width, int height, int seed, double frequency, double persistance, double exponent) {
noise::module::Perlin pgen; // From libnoise
pgen.SetSeed(seed);
pgen.SetFrequency(frequency);
pgen.SetPersistence(persistance);
double minvalue = 100.0, maxvalue = -100.0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
double fnew = pow(exponent, pgen.GetValue(i, j, 0));
minvalue = (fnew < minvalue) ? fnew : minvalue;
maxvalue = (fnew > maxvalue) ? fnew : maxvalue;
map[i][j] = fnew;
}
}
return { minvalue, maxvalue }; // Return the maximum and minimum generated value
}
```

But it would be nice if a bit of erosion could be applied to this map, particularly if the results could be used as a guide for placing rivers—a crucial part of Skylines, which attempts to model water movement including inflows into pumping stations and sewage outflow back into the environment. But I’m rather yet to get that to work…