Random terrain: Difference between revisions
>Sduke524 No edit summary |
>Sduke524 No edit summary |
||
Line 1: | Line 1: | ||
== Introduction == | == Introduction == | ||
Procedurally generated terrain, often refered to as randomly generated terrain, is a terrain that is created via script rather than by hand. This | Procedurally generated terrain, often refered to as randomly generated terrain, is a terrain that is created via script rather than by hand. This gives the ability to have a game that is a completely different experience every time as well as uses alot less work. | ||
== The | == The basic algorithm == | ||
The most basic | The most basic algorithm is to place bricks of random size in random positions across your baseplate. To do this we will set up a simple for loop that instances a new, anchored part every time. | ||
for i=1,200 do | for i=1,200 do | ||
Line 10: | Line 10: | ||
Next we will set the size to a random amount. For this we will use the function ''math.random()'' | Next we will set the size to a random amount. For this we will use the function ''math.random()'' | ||
a.Size=Vector3.new(math.random(1,20),math.random(1,20),math.random(1,20)) | a.Size=Vector3.new(math.random(1,20),math.random(1,20),math.random(1,20)) | ||
This will set the Size to a random amount | This will set the Size to a random amount between 1 and 20 for the X,Y and Z size. Now for the last step of our algorithm, use CFrame to place the brick in a random spot. We will easily just place the X and Z axis using ''math.random()'' yet for the Y axis, we'll have to do something special. Being that we want all the bricks to stay on the ground, we want their base to be at 0. Now since the Position of a brick in roblox uses the center of the brick, we'll have to divide the Y size in half, so that it sits just perfectly on 0. So it would be : | ||
a.CFrame=CFrame.new(math.random(-100,100),a.Size.Y/2,math.random(-100,100)) | a.CFrame=CFrame.new(math.random(-100,100),a.Size.Y/2,math.random(-100,100)) | ||
end -- for the for loop | end -- for the for loop | ||
== Heightmap == | == Heightmap == | ||
A heightmap shows different elevations across the whole map. For making a basic one, we will just have a script in the base of our map. This way we can specify the size of the map we want and where it will be positioned easily. To start, we will define three variables. | A heightmap shows different elevations across the whole map. For making a basic one, we will just have a script in the base of our map. This way we can specify the size of the map we want and where it will be positioned, easily. To start, we will define three variables. | ||
Xlength=10 | Xlength=10 | ||
Zlength=10 | Zlength=10 | ||
par=script.Parent | par=script.Parent | ||
Xlength and Zlength will be the dimensions ( in parts ) that will be used whereas par shows the base, which is what | Xlength and Zlength will be the dimensions ( in parts ) that will be used whereas par shows the base, which is what our math is based on. Now, how we will create all the bricks is similar to last time, only now it will use two for loops. | ||
for x=1,Xlength do | for x=1,Xlength do | ||
for z=1,Zlength do | for z=1,Zlength do | ||
local a=Instance.new("Part",workspace) | local a=Instance.new("Part",workspace) | ||
a.Anchored=true | a.Anchored=true | ||
By setting it up this way, it'll start from a corner and go all the way to the edge, then go back to that corner and do the same thing just one up until the map is complete. Now the sizing of the brick will be a little bit more unique than last time. Now we will only use math.random() on the Y axis, the other two we will divide the par.Size by their equivalent Xlength or Zlength. This will insure that it will sit perfectly | By setting it up this way, it'll start from a corner and go all the way to the edge, then go back to that corner and do the same thing just one up until the map is complete. Now the sizing of the brick will be a little bit more unique than last time. Now we will only use math.random() on the Y axis, the other two we will divide the par.Size by their equivalent Xlength or Zlength. This will insure that it will sit perfectly on our base, but only if the formFactor is set to ''Custom'' | ||
a.formFactor="Custom" | a.formFactor="Custom" | ||
a.Size=Vector3.new(par.Size.X/Xlength,math.random(1,20),par.Size.Z/Zlength) | a.Size=Vector3.new(par.Size.X/Xlength,math.random(1,20),par.Size.Z/Zlength) | ||
Now we will do the tricky part, positioning it with CFrame. There are 3 basic steps to getting the CFrame perfect. Step 1 will be very similar to the first example. The Y axis will be done exactly the same way, however the other 2 axis are going to have to be done by doing | Now we will do the tricky part, positioning it with CFrame. There are 3 basic steps to getting the CFrame perfect. Step 1 will be very similar to the first example. The Y axis will be done exactly the same way, however the other 2 axis are going to have to be done by doing | ||
size.X*x and size.Z*z | |||
a.CFrame=CFrame.new(x*a.Size.X,a.Size.Y/2,z*a.Size.Z) | a.CFrame=CFrame.new(x*a.Size.X,a.Size.Y/2,z*a.Size.Z) | ||
This is done because now it'll take the for loop x and z values, and multiply them by the size to get it to scale. Next we're gonna add the position of the part, and also subtract half of the size on the X and the Z. | This is done because now it'll take the for loop x and z values, and multiply them by the size to get it to scale. Next we're gonna add the position of the part, and also subtract half of the size on the X and the Z. | ||
a.CFrame=a.CFrame+Vector3.new((par.Position.X-par.Size.X/2),par.Position.Y,(par.Position.Z-par.Size.Z/2)) | a.CFrame=a.CFrame+Vector3.new((par.Position.X-par.Size.X/2),par.Position.Y,(par.Position.Z-par.Size.Z/2)) | ||
The reason we also subtract half of the X and half of the Z is because then it will make it offset from the corner, instead of the middle of the | The reason we also subtract half of the X and half of the Z is because then it will make it offset from the corner, instead of the middle of the base. Now if you run it like this, you'll notice that it still comes off the base a little bit. This is because the bricks aren't being moved by the corner as well, but by the middle of them. We will fix this in the third and final step, subtracting half of the x and z size of the brick being placed. | ||
a.CFrame=a.CFrame-Vector3.new(a.Size.X/2,0,a.Size.Z/2); | a.CFrame=a.CFrame-Vector3.new(a.Size.X/2,0,a.Size.Z/2); | ||
end end -- an end for each for loop | end end -- an end for each for loop | ||
== Coloring the bricks == | == Coloring the bricks == | ||
Now | Now in case you sadly haven't noticed, the bricks are alil dull and all completely grey. So | ||
to change this we will make a simple function named color. | |||
=== randomly picked === | === randomly picked === | ||
For this method, we'll use a table full of strings that will be the names of the colors. Then the function will pick a random color out of the table and use it. Here is the function | For this method, we'll use a table full of strings, that will be the names of the colors. Then the function will pick a random color out of the table and use it. Here is the function | ||
colors={"Bright red","Really black","White"} | colors={"Bright red","Really black","White"} | ||
Line 48: | Line 51: | ||
and it will run. | and it will run. | ||
=== Based on height === | === Based on height === | ||
Now we will base are function off of the height of the brick. It will be basically the same, | Now we will base are function off of the height of the brick. It will be basically the same thing, with one real difference. Now we will have acouple conditionals and the color(a) will have to go after the brick is sized. | ||
colors={"Bright red","Really black","White"} | colors={"Bright red","Really black","White"} | ||
function color(part) | function color(part) |
Revision as of 05:44, 9 July 2011
Introduction
Procedurally generated terrain, often refered to as randomly generated terrain, is a terrain that is created via script rather than by hand. This gives the ability to have a game that is a completely different experience every time as well as uses alot less work.
The basic algorithm
The most basic algorithm is to place bricks of random size in random positions across your baseplate. To do this we will set up a simple for loop that instances a new, anchored part every time.
for i=1,200 do local a=Instance.new("Part",workspace)--creates new part in workspace a.Anchored=true
Next we will set the size to a random amount. For this we will use the function math.random()
a.Size=Vector3.new(math.random(1,20),math.random(1,20),math.random(1,20))
This will set the Size to a random amount between 1 and 20 for the X,Y and Z size. Now for the last step of our algorithm, use CFrame to place the brick in a random spot. We will easily just place the X and Z axis using math.random() yet for the Y axis, we'll have to do something special. Being that we want all the bricks to stay on the ground, we want their base to be at 0. Now since the Position of a brick in roblox uses the center of the brick, we'll have to divide the Y size in half, so that it sits just perfectly on 0. So it would be :
a.CFrame=CFrame.new(math.random(-100,100),a.Size.Y/2,math.random(-100,100)) end -- for the for loop
Heightmap
A heightmap shows different elevations across the whole map. For making a basic one, we will just have a script in the base of our map. This way we can specify the size of the map we want and where it will be positioned, easily. To start, we will define three variables.
Xlength=10 Zlength=10 par=script.Parent
Xlength and Zlength will be the dimensions ( in parts ) that will be used whereas par shows the base, which is what our math is based on. Now, how we will create all the bricks is similar to last time, only now it will use two for loops.
for x=1,Xlength do for z=1,Zlength do local a=Instance.new("Part",workspace) a.Anchored=true
By setting it up this way, it'll start from a corner and go all the way to the edge, then go back to that corner and do the same thing just one up until the map is complete. Now the sizing of the brick will be a little bit more unique than last time. Now we will only use math.random() on the Y axis, the other two we will divide the par.Size by their equivalent Xlength or Zlength. This will insure that it will sit perfectly on our base, but only if the formFactor is set to Custom
a.formFactor="Custom" a.Size=Vector3.new(par.Size.X/Xlength,math.random(1,20),par.Size.Z/Zlength)
Now we will do the tricky part, positioning it with CFrame. There are 3 basic steps to getting the CFrame perfect. Step 1 will be very similar to the first example. The Y axis will be done exactly the same way, however the other 2 axis are going to have to be done by doing
size.X*x and size.Z*z a.CFrame=CFrame.new(x*a.Size.X,a.Size.Y/2,z*a.Size.Z)
This is done because now it'll take the for loop x and z values, and multiply them by the size to get it to scale. Next we're gonna add the position of the part, and also subtract half of the size on the X and the Z.
a.CFrame=a.CFrame+Vector3.new((par.Position.X-par.Size.X/2),par.Position.Y,(par.Position.Z-par.Size.Z/2))
The reason we also subtract half of the X and half of the Z is because then it will make it offset from the corner, instead of the middle of the base. Now if you run it like this, you'll notice that it still comes off the base a little bit. This is because the bricks aren't being moved by the corner as well, but by the middle of them. We will fix this in the third and final step, subtracting half of the x and z size of the brick being placed.
a.CFrame=a.CFrame-Vector3.new(a.Size.X/2,0,a.Size.Z/2); end end -- an end for each for loop
Coloring the bricks
Now in case you sadly haven't noticed, the bricks are alil dull and all completely grey. So
to change this we will make a simple function named color.
randomly picked
For this method, we'll use a table full of strings, that will be the names of the colors. Then the function will pick a random color out of the table and use it. Here is the function
colors={"Bright red","Really black","White"} function color(part) part.BrickColor=BrickColor.new(colors[math.random(1,#colors)]) end
Now all you have to do to use this function is somewhere in the script put
color(a)
and it will run.
Based on height
Now we will base are function off of the height of the brick. It will be basically the same thing, with one real difference. Now we will have acouple conditionals and the color(a) will have to go after the brick is sized.
colors={"Bright red","Really black","White"} function color(part) part.BrickColor=BrickColor.new(colors[1]) if part.Size.Y>3 then part.BrickColor=BrickColor.new(colors[2]) end if part.Size.Y>7 then part.BrickColor=BrickColor.new(colors[3]) end end