Projects

Worlds | More Adventures in Generated Maps

After Realms, I chose to build another app to procedurally generate maps.

My initial focus when making this app, dubbed "Worlds", was performance. A huge issue for me in Realms had been bad performance due to technical debt and amateur knowledge of how the different modules and layers worked together.

I introduced a quad-tree to contain the points (cell centers), then implemented tectonic plates to replace the system for generating the height map (previously random mountains and hardcoded mountain ranges). The quad-tree makes it really fast to identify where a user has clicked, whereas in Realms there would be lag after a mouse-click while the program desperately looped through every cell to find the one closest to the cursor.

Another issue I had in Realms had been how to display mountains. Mountains are often surrounded, at least partially, with dense forests. The way I drew forests was one big blob shape instead of individual trees, and getting something to wrap around another shape like that in 2D got pretty hard. I tried drawing mountains procedurally like Dragons Abound so cleverly does, but had limited success.

I decided to try and render the world with "3D" like shading, based off some code in Amit Patel's original article Polygonal Map Generation for Games.

A simple transparent shading layer creates an unmistakable "low poly" effect and clearly indicates mountains and valleys
public function calculateLighting(p:Cell, r:Corner, s:Corner):Number
{
var lightVector:Vector3D = new Vector3D(1, 1, 0);

var a:Vector3D = new Vector3D(p.point.x, p.point.y, p.elevation);
var b:Vector3D = new Vector3D(r.point.x, r.point.y, r.elevation);
var c:Vector3D = new Vector3D(s.point.x, s.point.y, s.elevation);

var normal:Vector3D = b.subtract(a).crossProduct(c.subtract(a));
if (normal.z < 0)
normal.scaleBy(-1);
normal.normalize();

var light:Number = 0.5 + 35 * normal.dotProduct(lightVector);
if (light < 0) light = 0;
else if (light > 1) light = 1;

return light;
}

Additionally, I built the code from the ground up around the idea that each visual layer is modular and able to be toggled individually.

I put the usability of the app first this time around

A settings popup allows multiple properties to be adjusted during runtime - however, the world has to be regenerated every time a setting is changed.

The settings popup gives me a lot more power over the generated world
The performance popup shows where I low hanging fruit can be tackled to fix performance issues