Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Diamond-Square Terrain Generator
- This terrain generator uses a 3d midpoint displacement algorithm to produce realistic-looking terrain using wedges.
- The function Build takes 7 arguments, which are provided at the top of the script as variables for ease of editing:
- Scale (Number): This is the size of the piece of terrain that will be generated. Terrain is always generated in squares. The value provided,
- 100, will produce a 100x100 area of terrain.
- Pos (Vector3): This is the position that the terrain is roughly centered at. The terrain won't always be exactly vertically centered over this position,
- however, depending on the values that you provide for the table "Table", which will be described below.
- Iterations (Number): The midpoint displacement algorithm essentially works by dividing a large square into four smaller squares, down the middle.
- For each iteration, the new squares will themselves be divided. Basically, this value determines how complex the terrain will be.
- A value of 1, for example, will produce terrain with four "tiles", composed of four wedges each. Increasing this number by one will quadruple the number of squares (doubled on both axes).
- Error (Number): This is the degree of "randomness" that the terrain will have. If you set it to 0, for example, the terrain will be completely smooth.
- Wait (Number): The terrain generator will wait at times by this amount while generating terrain, unless this number is 0. The smallest amont you can wait is generally around
- 0.03s. For small pieces of terrain with a low number of iterations, you may be able to safely set Wait to 0. However, with larger pieces of terrain, your game may crash. Generally,
- the minimum amount of waiting time (any number above 0) is enough to prevent this.
- Table (Table): This argument may be the hardest to understand, especially if you don't already know how the midpoint-displacement algorithm works. For starters, you should
- look up "diamond square algorithm" on wikipedia. Essentially, this table allows you to the verticle value of nodes within the algorithm. It is a 2-dimensional table (a set of tables within a table)
- where indices of the main table are vertical coordinates, and indices of the sub-tables are horizontal coordinates. Values of the sub-tables are the vertical height of the node represented by the
- coordinates. Coordinates must be multiples of 1/(2^iterations).
- Colors (Table): This is a set of tables within a table that tells the script how to color the terrain, based on height.
- Each table inside Table provides a single "layer". The first number in each table is the upper boundary of that layer.
- terrain whose position along the y-axis in between this value and the first number of the table before it will be given a
- specific color: the second value in each table. A coloring table is provided as an example.
- ]]
- local Scale = 1000
- local Pos = Vector3.new(0,0,0)
- local Iterations = 4
- local Error = 40
- local Wait = 0.01
- local Table = {
- [0]={[0] =math.random(-Error,Error), [1] = math.random(-Error,Error)},
- [.5]={[.5] = 50},
- [1]={[0] = math.random(-Error,Error), [1] = math.random(-Error,Error)}
- }
- local Colors = {
- {0,BrickColor.new("Toothpaste")},
- {6,BrickColor.new("Bright red")},
- {10,BrickColor.new("Bright Yellow")},
- {14,BrickColor.new("Bright red")},
- {30,BrickColor.new("Black")},
- {math.huge, BrickColor.new("Bright red")}
- }
- function Triangle(A,B,C,Color)
- local M = Instance.new("Model")
- M.archivable = false
- local Base1 = (C-A)*((B-A):Dot(C-A)/((C-A).magnitude)^2)
- local Base2 = ((C-A) - Base1)
- local Height = (B-A) - Base1
- local Pos1 = (A + (B-A)/2)
- local Pos2 = (C + (B-C)/2)
- local Normal1 = Base1:Cross(Height).unit
- local Normal2 = Base2:Cross(Height).unit
- local Cf1 = CFrame.new(0,0,0,Normal1.x,-Base1.unit.x,-Height.unit.x, Normal1.y,-Base1.unit.y,-Height.unit.y,Normal1.z, -Base1.unit.z,-Height.unit.z) + Pos1
- local Cf2 = CFrame.new(0,0,0,Normal2.x,-Base2.unit.x,-Height.unit.x, Normal2.y,-Base2.unit.y,-Height.unit.y,Normal2.z, -Base2.unit.z,-Height.unit.z) * CFrame.Angles(0,0,math.pi)+ Pos2
- local P1 = Instance.new("WedgePart")
- P1.FormFactor = 0
- P1.Size = Vector3.new(1,math.floor(Base1.magnitude),math.floor(Height.magnitude))
- local M1 = Instance.new("SpecialMesh")
- M1.archivable = false
- M1.MeshType = "Wedge"
- M1.Scale = Vector3.new(1, Base1.magnitude, Height.magnitude)/P1.Size
- M1.Parent = P1
- P1.Anchored = true
- P1.CFrame = Cf1 + (Cf1 - Cf1.p) * Vector3.new(.5,0,0)
- P1.TopSurface = 0
- P1.BottomSurface = 0
- for i = 1, #Color do
- if P1.Position.y >= (((i == 1) and -math.huge) or Color[i-1][1]) and P1.Position.y < Color[i][1] then
- P1.BrickColor = Color[i][2]
- break
- end
- end
- P1.Parent = M
- P1.archivable = false
- local P2 = Instance.new("WedgePart")
- P2.FormFactor = 0
- P2.Size = Vector3.new(1,math.floor(Base2.magnitude),math.floor(Height.magnitude))
- local M2 = Instance.new("SpecialMesh")
- M2.archivable = false
- M2.MeshType = "Wedge"
- M2.Scale = Vector3.new(1, Base2.magnitude, Height.magnitude)/P2.Size
- M2.Parent = P2
- P2.Anchored = true
- P2.CFrame = Cf2 +(Cf2 - Cf2.p) * Vector3.new(-.5,0,0)
- P2.TopSurface = 0
- P2.BottomSurface = 0
- for i = 1, #Color do
- if P2.Position.y >= (((i == 1) and -math.huge) or Color[i-1][1]) and P2.Position.y < Color[i][1] then
- P2.BrickColor = Color[i][2]
- break
- end
- end
- P2.Parent = M
- P2.archivable = false
- return M
- end
- function Generate(MainTable, Reps, Error)
- function DiamondSquare(Vs, Ve, Hs, He, I, E)
- local Va = (Vs + Ve)/2
- local Ha = (Hs + He)/2
- if MainTable[Vs][Ha] == nil then
- MainTable[Vs][Ha] = (MainTable[Vs][Hs] + MainTable[Vs][He])/2
- end
- if MainTable[Va] == nil then
- MainTable[Va] = {}
- end
- if MainTable[Va][Hs] == nil then
- MainTable[Va][Hs] = (MainTable[Vs][Hs] + MainTable[Ve][Hs])/2 + (math.random() - .5) * E
- end
- if MainTable[Va][Ha] == nil then
- MainTable[Va][Ha] = (MainTable[Vs][Hs] + MainTable[Vs][He] + MainTable[Ve][Hs] + MainTable[Ve][He])/4+ (math.random() - .5) * E
- end
- if MainTable[Va][He] == nil then
- MainTable[Va][He] = (MainTable[Vs][He] + MainTable[Ve][He])/2+ (math.random() - .5) * E
- end
- if MainTable[Ve][Ha] == nil then
- MainTable[Ve][Ha] = (MainTable[Ve][Hs] + MainTable[Ve][He])/2+ (math.random() - .5) * E
- end
- E = E/2
- I = I - 1
- if I > 0 then
- DiamondSquare(Vs, (Vs + Ve)/2, Hs, (Hs + He)/2, I, E)
- DiamondSquare((Vs + Ve)/2, Ve, Hs, (Hs + He)/2, I, E)
- DiamondSquare(Vs, (Vs + Ve)/2, (Hs + He)/2, He, I, E)
- DiamondSquare((Vs + Ve)/2, Ve, (Hs + He)/2, He, I, E)
- end
- end
- DiamondSquare(0,1,0,1,Reps, Error)
- return MainTable, (2^Reps + 1)
- end
- function Build(Scale, Pos, Iterations, Error, Wait, Table,Colors)
- local G, Length = Generate(Table,Iterations, Error)
- local M = Instance.new("Model")
- M.archivable = false
- M.Parent = workspace
- for a, b in pairs(G) do
- for c, d in pairs(b) do
- if Wait > 0 then
- wait(Wait)
- end
- local Pos1 = Pos + Vector3.new((a-.5) * Scale, d , (c-.5) * Scale)
- local Int = 1/(2^Iterations)
- local Other = G[(a - Int)]
- local Other2 = G[a][c + Int]
- if Other ~= nil and Other2 ~= nil then
- local Other3 = Other[c]
- local Pos2 = Pos + Vector3.new((a - .5) * Scale, Other2, (c + Int - .5) * Scale)
- local Pos3 = Pos + Vector3.new((a - Int - .5) * Scale, Other3, (c - .5) * Scale)
- local T1 = Triangle(Pos2,Pos1, Pos3,Colors)
- T1.Parent = M
- end
- local Other4 = G[a + Int]
- local Other5 = G[a][c - Int]
- if Other4 ~= nil and Other5 ~= nil then
- local Other6 = Other4[c]
- local Pos5 = Pos + Vector3.new((a - .5) * Scale, Other5, (c - Int - .5) * Scale)
- local Pos6 = Pos + Vector3.new((a +Int - .5) * Scale, Other6, (c - .5) * Scale)
- local T1 = Triangle(Pos5, Pos1, Pos6,Colors)
- T1.Parent = M
- end
- end
- end
- return G
- end
- Build(Scale, Pos, Iterations, Error, Wait, Table,Colors)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement