# Can Someone help me with my chunk system?

I am working on a terrain generator for a game, and I need help with something, I am going to be making my terrain generator generator generate terrain downwards like in minecraft. But here is how it looks looks like right now:

I know how to make it generate terrain under the map, but due to the fact that it’s chunk system isn’t made by me (I got it from the devhub) I need help understanding how the chunk system works, so I can generate terrain under the map and add it to the chunk table.

Code
``````

local Players = game:GetService("Players")

------------------------------------------------------------------------------------------------------------------------------------------------

local BASE_HEIGHT 		= 25				-- 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 / 2			-- How much we should strech the X scale of the generation noise
local Z_SCALE 			= 90 / 2			-- 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 = {} -- I want to add terrain under the map to this table lol

local function roundToEven(n)
return math.floor(n - n % 2);
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 * 2 + 1, roundToEven((beginY + endY) * 2 / 1), z * 2 + 1)
local size = Vector3.new(2, (endY - beginY) * 2, 2)
local p = Instance.new("Part", workspace)

p.Anchored = true
p.CFrame = cframe
p.Size = Vector3.new(2, 2, 2)
if p.CFrame.Y <= -70 then
p.BrickColor = BrickColor.new("Dirt brown")

p.Material = Enum.Material.Grass
elseif p.CFrame.Y >= -70 then

--local Seed = math.randomseed(GENERATION_SEED)

local Chance = math.random(0, 1000)

if Chance > 0 then
p.BrickColor = BrickColor.new("Forest green")

p.Material = Enum.Material.Grass
else
p.BrickColor = BrickColor.new("Dirt brown")

p.Material = Enum.Material.Grass
end

end
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 / 2 / CHUNK_SCALE), math.floor(location.Z / 2 / 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

spawn(function()
while true do
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
game:GetService("RunService").Heartbeat:Wait()
end
end)
``````
4 Likes

This system doesn’t seem to actually remove chunks again once there are no players in range, so you don’t need to keep track of parts that have been created or which chunk they belong to.

1 Like

You could probably create a function that accepts different arguments to produce chunks:

``````local function CreateLayer(BASE_HEIGHT, mountLayer, createChunk)
-- all of the code up there
end
``````

Then you can mass-produce layers which can create a cave through clever use of `mountLayer` or `createChunk`.

Honestly, most of the code seems self-explanatory if you read it.

• Every frame, `checkSurroundings` is called from the character’s position.
• that function checks in a `range` around the character, calling `makeChunk` if the chunk doesn’t exist.
• `makeChunk` then calls `mountLayer` which does the actual building of the chunk. This is where you would want to make the most modifications to how chunks are created, so that will probably constitute its own argument in the function up top.

If you wanted to make a cave, you would basically have to create modifications to `makeChunk` and `mountLayer` to achieve the right behavior, and you can also use `math.noise` here to determine additional “smooth” characteristics of the cave, like how far it is below ground and the diameter of the cave at any given point, though you might need to create additional data to know when to stop building the cave, etc.
You can store that additional data using `chunks` as a medium of data storage, which you can access from later nodes. I made a very useless example here, but you can determine behavior for the current node using nodes around it.

``````-- in `makeChunk`, line 2
chunks[chunkX][chunkZ] = {
DistanceFromCenter = Vector3.new(...),
Color = Color3.new(...)
}

-- in `mountLayer` somewhere,
local nodeChunk = chunks[x][z]
if nodeChunk and nodeChunk.DistanceFromCenter == Vector3.new() then
print("next to center")
end
``````
2 Likes