Random terrain
Procedurally generated terrain, often referred to as randomly generated terrain, is a method of creating terrain by following a pattern or algorithm instead of hand-picking every single point. By using randomly generated terrain large maps can be made in a fraction of the time.
Contents |
[edit] Basic algorithm
The most basic algorithm for terrain generation is to place a brick of a random size in a random position across the map. To do this we are going to use a Loops#For and create a new part for every iteration.
for i = 1, 200 do
local part = Instance.new("Part", workspace) -- Creates a Part and makes it a descendant of Workspace
part.Anchored = true -- Prevents the part from moving.
Then set the size to a random amount using math.random()
part.Size = Vector3.new(math.random(20), math.random(20), math.random(20))
The position will be done the same as the size was for the X and Z axis however, the Y axis will be treated differently. Since we want all the bricks to stay on the ground, the base of the block needs to be at 0. Because the Position of a brick in roblox uses the center of that brick, dividing the height of the brick by 2 makes it sit on 0.
part.CFrame = CFrame.new(math.random(-100, 100), part.Size.Y/2, math.random(-100, 100))
end -- for the for loop
[edit] Height-map
A height-map shows different elevations across a map. Height-maps are the most common form of terrain used. For this example, put a script in the base of the map. This way it is easy to access the size and position of the map. The first thing to do is define the variables needed.
local size = Vector3.new(10, -- Number of tiles along the width
10, -- Number of steps of heightmap
10) -- Number of tiles along the length
local base = script.Parent -- The part to replace with terrain
local tilePart = Instance.new("Part")
tilePart.Anchored = true
tilePart.formFactor = "Custom"
tilePart.Size = base.Size / size --The size of one unit or cuboid of the map
Sizing and positioning the bricks will be done similar to how it was in the first terrain generator except the only random factor will be the height of the brick.
for x = 1, size.x do
for z = 1, size.z do
local y = math.random(size.y)
local tile = tilePart:clone()
local position = Vector3.new(x-1, 0, z-1) * tile.Size
tile.Size = tile.Size * Vector3.new(1, y, 1)
tile.CFrame = CFrame.new(tile.Size/2) --Shift the part by half it's size, so we can position the corner
tile.CFrame = tile.CFrame - base.Size / 2 --Shift it into one corner of the base
tile.CFrame = tile.CFrame + position --Put it in the right place
tile.CFrame = base.CFrame * tile.CFrame --Move it so that it is level with the surface of the base
tile.Parent = workspace
end
end -- an end for each for loop
[edit] Coloring the bricks
Currently the bricks are very plain and dull. To liven things up, it is best to add some color to your terrain.
[edit] Random
So that there is some control over what colors are going into our terrain a table full of colors is going to be added. Then our function will pick a random color out of that table and designate that as the color of the brick.
local colors = {BrickColor.Red(), BrickColor.Black(), BrickColor.White()}
function color(part)
part.BrickColor = colors[math.random(#colors)]
end
Then add the line color(a) somewhere in the script and presto! Your terrain is now prettier.
[edit] Based on height
Using the height of the brick is a common method used because it allows for you to make sandy beaches and snowy mountain-tops without causing too much costly checks. To do this, check the height of the bricks against the minimum height for each color.
local colors = {BrickColor.Red(), BrickColor.Black(), BrickColor.White()}
function color(part)
if part.Size.Y > 7 then
part.BrickColor = colors[3]
elseif part.Size.Y > 3 then
part.BrickColor = colors[2]
else
part.BrickColor = colors[1]
end
end
If you know enough about generic for loops then it is easier to speed up this process and also add more colors by using the index of the color as the minimum height.
function color(part)
local colors = {
[0]=BrickColor.Blue(),
[3]=BrickColor.Yellow(),
[8]=BrickColor.Green(),
[17]=BrickColor.new("Reddish brown"),
[24]=BrickColor.DarkGray(),
[32]=BrickColor.White()
}
for minimum_height, color in ipairs(colors) do
if part.Size.Y > minimum_height then
part.BrickColor = color
end
end
[edit] Using weighted values
In scripting terminology, weighted values are values that have been tampered with to insure certain results.
[edit] Mountains
In case we wanted to make sure a mountain came out of our script, we can easily just use a variable ( rand ) to hold the highest point we reach and add that to every number. Now to maintain it being random, we will also add a random number between -2 and 2. Then after we have that number, we'll check if the random number between -2 and 2 is greater than 0 and add it to our variable "rand".
rand=0
for x=1,Xlength do
for z=1,Zlength do
local a=part:clone()
local random_factor=math.random(-2,2)
tilePart.Size=Vector3.new(part.Size.X/Xlength,rand+random_factor,par.Size.Z/Zlength)
if random_factor>0 then
rand=rand+random_factor
end
[edit] Lake
Now to make a lake, we won't need random_factor or rand. All that will be needed is a little bit of math to add in the weighted factors. Just try
tilePart.Size=Vector3.new(par.Size.X/Xlength,math.random(-2,2)+math.abs(x-Xlength/2)+math.abs(z-Zlength),par.Size.Z/Zlength)
This works because it uses the distance from the middle as the weight.