Hey there! So, I want to make a terrain generation with the falloff filter. and yes, i have seen this post before and it sadly couldn’t help me,
also a border. Ever seen Muck?
It generates a random terrain and sure, it doesn’t have a border but im pretty sure it has a inf amount of water which acts like a “border” because you drown in the water.
Muck also uses falloff map:
(Screenshot from dani’s video about the making of Muck)
How would i achieve both this?
Thanks!!
Almost forgot to send code
Module script named “Chunk”
local TERRAIN_HEIGHT_COLORS = {
[-50] = Enum.Material.Sand;
[-10] = Enum.Material.Grass;
[0] = Enum.Material.Grass; -- grassy green
[75] = Enum.Material.Rock; -- stone grey mountain
}
local X, Z = 4, 4
local WIDTH_SCALE = 15
local HEIGHT_SCALE = 100
local TERRAIN_SMOOTHNESS = 20
local MIN_TREE_SPAWN_HEIGHT = -15
local MAX_TREE_SPAWN_HEIGHT = 30
local TREE_DENSITY = 0.85
local SEED = workspace.SEED.Value
local wedge = Instance.new("WedgePart");
wedge.Anchored = true;
wedge.TopSurface = Enum.SurfaceType.Smooth;
wedge.BottomSurface = Enum.SurfaceType.Smooth;
local function draw3dTriangle(a, b, c)
local ab, ac, bc = b - a, c - a, c - b;
local abd, acd, bcd = ab:Dot(ab), ac:Dot(ac), bc:Dot(bc);
if (abd > acd and abd > bcd) then
c, a = a, c;
elseif (acd > bcd and acd > abd) then
a, b = b, a;
end
ab, ac, bc = b - a, c - a, c - b;
local right = ac:Cross(ab).unit;
local up = bc:Cross(right).unit;
local back = bc.unit;
local height = math.abs(ab:Dot(up));
local w1 = wedge:Clone();
w1.Size = Vector3.new(0, height, math.abs(ab:Dot(back)));
w1.CFrame = CFrame.fromMatrix((a + b)/2, right, up, back);
w1.Parent = workspace;
local w2 = wedge:Clone();
w2.Size = Vector3.new(0, height, math.abs(ac:Dot(back)));
w2.CFrame = CFrame.fromMatrix((a + c)/2, -right, up, -back);
w2.Parent = workspace;
return w1, w2;
end
local function getHeight(chunkPosX, chunkPosZ, x, z)
local height = math.noise(
(X/TERRAIN_SMOOTHNESS * chunkPosX) + x/TERRAIN_SMOOTHNESS,
(Z/TERRAIN_SMOOTHNESS * chunkPosZ) + z/TERRAIN_SMOOTHNESS,
SEED
) * HEIGHT_SCALE
if height > 20 then
local difference = height - 20
height += (difference * 1.2)
end
if height < -20 then
local difference = height - -20
height += (difference * 1.2)
end
return height
end
local function getPosition(chunkPosX, chunkPosZ, x, z)
return Vector3.new(
chunkPosX*X*WIDTH_SCALE + x*WIDTH_SCALE,
getHeight(chunkPosX, chunkPosZ, x, z),
chunkPosZ*Z*WIDTH_SCALE + z*WIDTH_SCALE
)
end
local function getMaterial(wedge)
local wedgeHeight = wedge.Position.Y
local color
local lowerColorHeight
local higherColorHeight
for height, heightColor in pairs(TERRAIN_HEIGHT_COLORS) do
if wedgeHeight == height then
color = heightColor
break
end
if (wedgeHeight < height) and (not higherColorHeight or height < higherColorHeight) then
higherColorHeight = height
end
if (wedgeHeight > height) and (not lowerColorHeight or height > lowerColorHeight) then
lowerColorHeight = height
end
end
if not color then
if higherColorHeight == nil then
color = TERRAIN_HEIGHT_COLORS[lowerColorHeight]
elseif lowerColorHeight == nil then
color = TERRAIN_HEIGHT_COLORS[higherColorHeight]
else
color = Enum.Material.Grass
end
end
return color
end
local function addWater(chunk)
local cframe = CFrame.new(
(chunk.x + .5) * chunk.WIDTH_SIZE_X,
-70,
(chunk.z + .5) * chunk.WIDTH_SIZE_Z
)
local size = Vector3.new(
chunk.WIDTH_SIZE_X,
90,
chunk.WIDTH_SIZE_Z
)
workspace.Terrain:FillBlock(cframe, size, Enum.Material.Water)
chunk.waterCFrame = cframe
chunk.waterSize = size
end
local function addTrees(chunk)
local posGrid = chunk.positionGrid
local instances = chunk.instances
local chunkPosX = chunk.x
local chunkPosZ = chunk.z
for x = 0, X-1 do
for z = 0, Z-1 do
local pos = posGrid[x][z]
if pos.Y >= MIN_TREE_SPAWN_HEIGHT and pos.Y <= MAX_TREE_SPAWN_HEIGHT then
math.randomseed(x * (chunkPosX+SEED) + z * (chunkPosZ+SEED))
if math.random() < TREE_DENSITY then
local tree = game.ReplicatedStorage.Tree:Clone()
for index, child in pairs(tree:GetChildren()) do
if child.Name == "Leaf" then
child.Color = Color3.fromRGB(
75 + math.random(-25, 25),
151 + math.random(-25, 25),
75 + math.random(-25, 25)
)
end
end
local cframe = CFrame.new(pos)
* CFrame.new(
math.random() * math.random(-10, 10),
10,
math.random() * math.random(-10, 10)
)
* CFrame.Angles(0, 2 * math.pi * math.random(), 0)
tree:SetPrimaryPartCFrame(cframe)
tree.Parent = workspace
table.insert(instances, tree)
end
end
end
end
end
local function convert(chunk)
local instances = chunk.instances
for i,v in pairs(instances) do
if v.Name == "Wedge" then
local Material = getMaterial(v)
workspace.Terrain:FillWedge(v.CFrame,v.Size+Vector3.new(20,20,20),Material)
v:Destroy()
end
end
end
local Chunk = {}
Chunk.__index = Chunk
Chunk.WIDTH_SIZE_X = X * WIDTH_SCALE
Chunk.WIDTH_SIZE_Z = Z * WIDTH_SCALE
function Chunk.new(chunkPosX, chunkPosZ)
local chunk = {
instances = {};
positionGrid = {};
x = chunkPosX;
z = chunkPosZ;
}
setmetatable(chunk, Chunk)
local positionGrid = chunk.positionGrid
for x = 0, X do
positionGrid[x] = {}
for z = 0, Z do
positionGrid[x][z] = getPosition(chunkPosX, chunkPosZ, x, z)
end
end
for x = 0, X-1 do
for z = 0, Z-1 do
local a = positionGrid[x][z]
local b = positionGrid[x+1][z]
local c = positionGrid[x][z+1]
local d = positionGrid[x+1][z+1]
local wedgeA, wedgeB = draw3dTriangle(a, b, c)
local wedgeC, wedgeD = draw3dTriangle(b, c, d)
table.insert(chunk.instances, wedgeA)
table.insert(chunk.instances, wedgeB)
table.insert(chunk.instances, wedgeC)
table.insert(chunk.instances, wedgeD)
end
end
addWater(chunk)
addTrees(chunk)
convert(chunk)
return chunk
end
function Chunk:Destroy()
for index, instance in ipairs(self.instances) do
instance:Destroy()
end
workspace.Terrain:FillBlock(self.waterCFrame, self.waterSize, Enum.Material.Air)
end
return Chunk