Random terrain generation with parts

I am attempting to create a block game, (Voxel game - Roblox) and I want to make the terrain generate randomly, like hills. Currently all it does is take a group of blocks and clone it until it fills ~the size of the baseplate.

Each block is 3x3x3, and I want the terrain to be made up of them. How would I go about this?

6 Likes

Do you need help with the terrain generation?

2 Likes

Yes, I want to know how to randomly generate hills, valleys, etc. from these blocks.

2 Likes

Where do you want me to put this script? I put it into a script in serverscriptservice and nothings happened.

1 Like

I am aware of this let me fix it. Sorry.

1 Like

@MrSprinkleToes Don’t use the other script, use this one instead:

local Players = game:GetService("Players")

------------------------------------------------------------------------------------------------------------------------------------------------
 
local BASE_HEIGHT 		= 10				-- The main height factor for the terrain.
local CHUNK_SCALE 		= 1					-- The grid scale for terrain generation. Should be kept relatively low if used in real-time.
local RENDER_DISTANCE 	= 25				    -- The length/width of chunks in voxels that should be around the player at all times
local X_SCALE 			= 90 / 4			-- How much we should strech the X scale of the generation noise
local Z_SCALE 			= 90 / 4			-- How much we should strech the Z scale of the generation noise
local GENERATION_SEED	= math.random() 	-- Seed for determining the main height map of the terrain.
 
------------------------------------------------------------------------------------------------------------------------------------------------
 
local chunks = {}

local function roundToOdd(n)
	--spawn(function()
	return math.floor(n - n % 3);
	--end)
end

local function chunkExists(chunkX, chunkZ)
	if not chunks[chunkX] then
		chunks[chunkX] = {}
	end
	return chunks[chunkX][chunkZ]
end
 
local function mountLayer(x, heightY, z, material)
	local beginY = -BASE_HEIGHT
	local endY = heightY
	local cframe = CFrame.new(x * 3 + 1, roundToOdd((beginY + endY) * 3 / 1), z * 3 + 1)
	local size = Vector3.new(3, (endY - beginY) * 3, 3)
    local p = Instance.new("Part", workspace)
	p.Anchored = true
	p.CFrame = cframe
	p.Size = Vector3.new(3, 3, 3)
	p.Material = Enum.Material.Grass
	p.BrickColor = BrickColor.new("Forest green")
end
 
function makeChunk(chunkX, chunkZ)
	local rootPosition = Vector3.new(chunkX * CHUNK_SCALE, 0, chunkZ * CHUNK_SCALE)
	chunks[chunkX][chunkZ] = true -- Acknowledge the chunk's existance.
	for x = 0, CHUNK_SCALE - 1 do
		for z = 0, CHUNK_SCALE - 1 do
			local cx = (chunkX * CHUNK_SCALE) + x
			local cz = (chunkZ * CHUNK_SCALE) + z
			local noise = math.noise(GENERATION_SEED, cx / X_SCALE, cz / Z_SCALE)
			local cy = noise * BASE_HEIGHT
			mountLayer(cx, cy, cz, Enum.Material.Grass)
		end
	end
end
 
function checkSurroundings(location)
	local chunkX, chunkZ = math.floor(location.X / 3 / CHUNK_SCALE), math.floor(location.Z / 3 / CHUNK_SCALE)
	local range = math.max(1, RENDER_DISTANCE / CHUNK_SCALE)
	for x = -range, range do
		for z = -range, range do
			local cx, cz = chunkX + x
			local cz = chunkZ + z
			if not chunkExists(cx, cz) then
				makeChunk(cx, cz)
			end
		end
	end
end
 
game:GetService("RunService").Heartbeat:Connect(function()
	for _, player in pairs(Players:GetPlayers()) do
		if player.Character then
			local humanoidRootPart = player.Character:FindFirstChild("HumanoidRootPart")
			if humanoidRootPart then
				checkSurroundings(humanoidRootPart.Position)
			end
		end
	end
end)

I did get most of this of the devhub.

6 Likes

I put it in a script inside of ServerScriptService, and nothing is happening. Am I missing something?

Could you explain how the script works? It’d be nice to teach instead of throw free code at the OP to just copy and paste.

8 Likes

Did you delete the baseplate? You have to play the game, not run it. It works perfectly fine for me…

I will explain the script when I have time

Put the script in server script service.

Alright, it works now. Thanks! It would be nice if you could explain it later on, I’d like to try at replicating it.

1 Like

No problemo! If you need more help with this later on, don’t be afraid to message me!

Now for the explanation

Just curious, I’ve been trying to figure this out for a while. I am using this in places created with the createplace api and saving these places with the saveplace api. How would I prevent the game from recreating chunks that were already created and saved in the place? Because of it recreating chunks when the person rejoins the game, it doesn’t save changes made to the terrain. (You can see it in action if you create a place in my game when you first join, then rejoin the place)

2 Likes

So, do you have any idea how I could save the chunks and not overwrite them when the player rejoins the place?

1 Like

Well, you’ll have to edit the original script. But since the chunks are all placed in a table, you could save that.

Then when a player joins the game, check if they have a chunk table saved, if not generate them a new one. If they do, use the one they have.

Just a note: Could be memory intensive.

3 Likes

The script doesn’t save the actual chunk data, it only keeps track of which chunks exist.

Thats why you have to edit the script yourself and save the chunk table yourself.

2 Likes

I know this topic is 2 years old, but how would you make it so you can detect parts out of a range. I tried doing something with my script, but it would delete all blocks out of that range if I move out of it (if that makes sense).

1 Like