Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How to make Smoother Terrain Generation (Using bricks)?

I have a basic script that allows for a given width and height of cubes, and for the baseplate size. Now what I was wondering is how to smooth the slopes, rather than using math.random to give me random heights.

local width = 2
local height = 2
local baseplate = {30, 30}

local model = Instance.new("Model")
model.Parent = game.Workspace
model.Name = "Terrain Parts"

local bricksRemove = game.Workspace:FindFirstChild("Terrain Parts"):GetChildren()
for num, obj in pairs(bricksRemove)do
	if obj:IsA("Part") then
		if obj.Name == "Terrain Blocks" then
			obj:Destroy()
		end
	end
end

for i = 0, ((baseplate[1]/width)*(baseplate[2]/width))-1 do
	local brick = Instance.new("Part")
	brick.FormFactor = 3
	brick.Size = Vector3.new(width, height, width)
	brick.Position = Vector3.new((i%(baseplate[1]/width))*width, math.random()+4, math.floor(i/(baseplate[2]/width))*2)
	brick.Anchored = true
	brick.Name = "Terrain Blocks"
	brick.Parent = game.Workspace:FindFirstChild("Terrain Parts")
end

I was debating whether getting blocks at certain intervals and using them to decide the incline/decline then smooth the blocks within a given range to that, but that didn't seem efficient. So if anyone has any information that will guide me into making smooth terrain, I would be grateful.

~ Legobuildermaster

1 comment

0

To anyone looking to answer, I believe I have found a way though it is more complicated. I'm going to use OOP and create parts using that, then using the directions, obtain a block in a certain direction, then base the height off of that part.

1 answer

✓ Accepted answer

First, you should simplify this code a little.

Clearing the children can be much simpler:

  • There's no point to :FindFirstChild if you immediately call :GetChildren
  • You shouldn't have the space in the name in the first place.
  • You should just use ["Terrain Parts"] if you insist on having the space
  • You can combine the two ifs using and to save two lines and a level of indentation
  • No need to use a name like num if you aren't going to use it
  • You should use workspace instead of game.Workspace
  • You should probably use "TerrainBlock" instead of "Terrain Blocks"
  • each is one Block; each is not several Blocks
  • it's not normal for names to have spaces in them
for _, child in pairs(workspace.TerrainParts:GetChildren()) do
	if child:IsA("BasePart") and child.Name == "Terrain Blocks" then
		child:Destroy()
	end
end

You can iterate over the grid much more easily, too. You don't need i itself, you just need the x and y. I would recommend not using baseplate or width or height because the names are very unclear. I would recommend blockWidth and blockHeight to describe sizes of individual blocks and worldX and worldZ or similar to describe the size of the world.

It's also easier to talk about x and y

for x = 0, worldX, blockWidth do
	for z = 0, worldZ, blockWidth do
		local brick = Instance.new("Part")
		brick.FormFactor = "Custom" -- Use descriptive values!!
		brick.Anchored = true
		brick.Size = Vector3.new(blockWidth, blockHeight, blockWidth)
		local y = math.random() * 4
		brick.Position = Vector3.new(x, y, z)
		brick.Name = "TerrainBlock"
		brick.Parent = workspace.TerrainParts
	end
end

Now, you need y to just be a function of x and z.

There are tons of different ways to do terrain generation. Recently ROBLOX added math.noise which gives you access to Perlin noise. You could use it something like this:

function height(x, y)
	return (math.noise(x / 20, y / 20) + math.noise(x / 35, y / 35) + math.noise(x / 77, y / 77)) * 10
end

....
	local y = height(x, z)
	brick.Position = Vector3.new(x, y, z)
....

1 comment

0

Thanks, this is much better than my OOP idea :/

This discussion is preserved as it was. New answers, comments, and votes are closed.