Procedural Terrain Generation
by Paramecium13
Introduction
This script and the accompanying executable and libraries procedurally generate terrain based off a numeric input (the seed). To increase speed, most of the actual terrain generation is done in the external executable; a more detailed explanation is provided in the How It Works section. The generator can currently generate four different types of terrain: non-branched caves ("CaveI"), branched caves ("CaveII"), islands ("IslandI"), and simple hills/mountains/swamps terrain ("Terrain"). The script also contains a method for saving the current map to a .rvdata2 file so it can be used in other projects (no scripts are required to use the generated maps). This can be used to quickly generate maps for your project for you to then edit.
![dLGMKIR.png]()
How to Use
Place all the files included in the demo in the \System sub-folder of your project and place the Terrain Gen script in your scripts thing with Paramecium Core and Tile Swap (by Hime, available here) above it. Make sure you have the .NET Framework 4.5 or higher installed. Modify the file config.json to create the type of terrain you want (more info on how that works in the How It Works section).
To generate terrain, call the method TerrainGen.generateTerrain(arr) in an event script in the map where you want the terrain. The parameter arr is an array containing the parameters for the terrain generation. The first four entries of the array are the same for all types of terrain. The first one is a string containing the name of the type of terrain you want to generate. The second one is the seed you want to use to generate the terrain; any two maps generated with the same seed (and other parameters) will be identical. The third parameter is the length and width of the map (this only generates square maps). The fourth entry is a string containing the name of the config file you want to use (e.g. "System\\cave.json") note that it starts in the directory where game.exe is located and that the backslash is used for escape sequences, so if you want to put one in your string you need to put in two backslashes. The other entries of the array depend on the type of terrain.
Non-Branched Caves
The array for non-branched caves is of the form
["CaveI", seed, size, config file, x0, y0, n, minL, maxL, buffer, θmin, θmax, min, max, amp]
The entries x0 and y0 are the starting x and y coordinates. The entry n is the number of cave segments generated. The entries minL and maxL are the minimum and maximum lengths of the segments; minL should be at least 2, the program has failed when it wasn't. The parameter buffer is the distance the (center of) the caves should stay from the border of the map. The entries θmin and θmax are the minimum and maximum angles between the cave segments, in radians; note that if θmin is 0 and θmax is greater than 0, the caves will only make left turns (I made this mistake and it took me a few days to realize what I was doing wrong), while this leads to interesting patterns, I doubt it is what you are looking for. The entries min and max are the minimum and maximum values of the feature map, which is used to generate features (e.g. rocks, holes, gold). The entry amp is the amplitude of the first octave of the vegetation map, the amplitude of the final vegetation map is the sum from i = 0 to 6 of amp/2i (for amp = 60, this is 119.0625).
Branched Caves
The array for branched caves is of the form
["CaveII", seed, size, config file, x0, y0, n, minL, maxL, buffer, θmin, θmax, b, min, max, amp]
The only differences with the array for non-branched maps is that the first entry is "CaveII" and the entry b, which is the number of branches.
![Z2QVIpr.png]()
Islands
The array for islands is of the form
["CaveII", seed, size, n, amp, maxMult, min, max]
The entry n is the number of octaves used to make the height map. I recommend that 2n < size/2. The entry amp is the amplitude of the first octave, the amplitude of the final height map is the sum from 0 to n of amp/2i (for amp = 60, this is 119.0625). The entry maxMult is the maximum amount the height map is stretched at the center of the map. The parameters min and max are the minimum and maximum values of the feature map.
![R3TjOxy.png]()
An island generated by this system, saved, and slightly modified.
Terrain
The array for normal terrain is of the form
["Terrain", seed, size, n, amp, min, max]
The only difference with the array for Island is that this array doesn't have the entry maxMult.
How It Works
A Simple Explanation
First the program generates a height map, how it does so depends on the type of terrain being generated. Next, it generates a vegetation map, which is similar to a height map for simple terrain, and a feature map, which is a two dimensional array of random numbers. The program then feeds these three maps into the parser, which creates a map of tiles based on the maps. First the parser goes through each tile and checks which base tile to put there by selecting the lowest height level that the height of the height map is less than or equal to at this tile. Then (still on the same tile) it checks if the vegetation map at this level is greater than or equal to a vegetation level and if so assigns it the corresponding tile. Finally (still on the same tile) it checks if the value of the feature map satisfies one of the listed features and if so, it adds the corresponding tile. After it has gone through all the tiles, it creates walls (e.g. for cliffs or trees) where appropriate.
A More Complicated Explanation
The first thing it does is prompt the user to enter a seed, which is used to generate the world, and stores it in game variable 1. Next, it calls the method TerrainGen.generateTerrain(array). The first thing that method does is it writes its parameters to the file System\args.arg. Next it calls the execute method of executor.dll (source code bellow), which caries out the death penalty launches generate.exe.
Header.h#pragma once#define MY_FIRST_DLL __declspec(dllexport)extern "C" MY_FIRST_DLLint execute(void);
Source.cpp
#include "Header.h"#include <iostream>MY_FIRST_DLLint execute(void){ system("System\\generate.exe"); return 1;}
The first thing generate.exe does is load the arguments from the file args.arg . Next it loads the config file (e.g config.json) (see bellow for code and explanation) and uses Newtonsoft.Json.dll to load the terrain parser (which will be used later) from it.{
"HLevels": {
"15": {
"BaseTile": {
"tileId": "A17 ",
"layer": 0
},
"VMapConfig": {
"25": {
"tileId": "A21 ",
"layer": 1
}
},
"FMapConfigV": {
"51": {
"tileId": "B89 ",
"layer": 2
},
"53": {
"tileId": "B90 ",
"layer": 2
}
},
"FMapConfigNV": {
"51": {
"tileId": "B89 ",
"layer": 2
},
"53": {
"tileId": "B90 ",
"layer": 2
}
}
},
"25": {
"BaseTile": {
"tileId": "A18 ",
"layer": 0
},
"VMapConfig": {},
"FMapConfigV": {},
"FMapConfigNV": {}
},
"45": {
"BaseTile": {
"tileId": "A81 ",
"layer": 0
},
"VMapConfig": {},
"FMapConfigV": {},
"FMapConfigNV": {}
},
"-30": {
"BaseTile": {
"tileId": "A2 ",
"layer": 1
},
"VMapConfig": {},
"FMapConfigV": {},
"FMapConfigNV": {}
},
"-10": {
"BaseTile": {
"tileId": "A1 ",
"layer": 0
},
"VMapConfig": {},
"FMapConfigV": {},
"FMapConfigNV": {
"19": {
"tileId": "A3 ",
"layer": 1
},
"37": {
"tileId": "A4 ",
"layer": 1
}
}
}
},
"Walls": [
{
"ceilTile": {
"tileId": "A81 ",
"layer": 0
},
"wallTile": {
"tileId": "A89 ",
"layer": 0
},
"wallHeight": 2
}
]
}
The HLevels entry contains a list of height levels and the terrain that is generated at them. Each height level configuration has a number (its height level) associated with it; all tiles with a height level less than or equal to that number are given the base tile of that Height level configuration. The VMapConfig (underneath each height level config) contains a list of vegetation map levels and the associated tile. All tiles at that height level whose vegetation map level is greater than or equal to that in an entry of VMapConfig is assigned that tile. The FMapConfigV is used when the tile has been given vegetation and the FMapConfigNV is used when it has not (both of these are under each height level config). The FMapConfig(N)V contains a list of numbers and their associated tiles. The higher the number, the rarer the tile will be placed.
Create new files based on the provided ones to get different types of terrain.
Next, generator.exe reads which type of terrain to generate and calls the corresponding method. That method loads its arguments then uses ptg.dll to generate a height map, a vegetation map, and a feature map (which is an array of random integers between min and max). Finally, it uses the terrain parser that was loaded from the config file and whose methods are contained in rmp.dll to parse the height map, vegetation map, and feature map into the tiles that will be placed in the game and saves them to the files layer0.map, layer1.map, and layer2.map.The method TerrainGen.generateTerrain then loads the files layer0.map, layer1.map, and layer2.map and places the tiles they contain on the map.RequirementsYou need to download these separately from the demo.- .NET Framework 4.5 or higher; there is a good chance you already have a version of the .NET Framework installed as many programs require it. You need to download and install this for the program to work.
- Tile Swap by Hime. Place it in the scripts part of the demo where it is asked for (or anywhere bellow Materials and above Terrain Gen). This script has its own terms and conditions.
Download the demo (which contains the script and the external files) here.
Upcoming Features
- An update on the RGSS3 side for creating exploration-crafting-survival type games
- Some modifications and additions to the cave generation algorithms
- Another cave making algorithm, for which I will be returning to my intellectual roots to implement.
- Multi-tile structures
- Other types of terrain(?)
- Rivers(?)
FAQ
There haven't been many questions yet so I made most of them my self.
Do players need the .NET Framework?
Yes, players need the .NET Framework 4.5 or higher installed to play games using this system for procedural terrain generation.
What do players and developers need to use maps generated and saved by this system?
Nothing, the maps saved by this system are normal RPG Maker VX Ace maps. The should not require any scripts or stuff to use (I haven't tested this but I am confident that this is the case; I will probable add some generated maps to a game I am developing)
I am trying to generate normal (branched or non-branched) caves but it produces weird spiral-like caves (I am using the angle range of (0,π/4).
The problem is the range of angles being used. All angles between 0 and π/4 represent left turns. I had this problem initially and it took me a few days to realize what I was doing wrong.
Terms of Use
This script and the libraries and executable I wrote (executor.dll, generator.exe, ptg.dll, and rmp.dll) are free to use in any non-commercial RPG Maker project, provided that I am given credit and that the licence for Newtonsoft.Json.dll (written by James Newton-King; website) is distributed alongside it. For usage of my work in commercial RPG Maker projects or in non-RPG Maker projects, please contact me.