Help with coroutine

Hello,

I’m trying to make a blocky terrain like in Minecraft and I’m using coroutines to speed up the generation because I need to generate a lot of blocks. But when I run my script it gives me an error and I don’t know how to solve it.

Script:

-- @ Terrain

--// Variables

local replicatedStorage = game:GetService("ReplicatedStorage")
local assets = replicatedStorage:WaitForChild("Assets")
local blockTemplate = assets:WaitForChild("Block")
local treeTemplate = assets:WaitForChild("Tree")

--// Functions

function newRow(width, length, chunkHeight, margin, rowThreadCount, rowCount)
	coroutine.wrap(function()
		local treeOffset = math.random(50, 100)
		local treeIndex = 0
		
		for x = 1, width / rowThreadCount do
			for z = 1, length do
				local terrainBlock = blockTemplate:Clone()
				local threadCount = chunkHeight / margin

				terrainBlock.Parent = game.Workspace
				terrainBlock.Position = Vector3.new((width * margin) / 2 - ((x + ((rowCount - 1) * (width / rowThreadCount))) * margin), math.floor(grid[x + ((rowCount - 1) * (width / rowThreadCount))][z] / margin) * margin + chunkHeight / 2, (length * margin) / 2 - z * margin)
				terrainBlock.Size = Vector3.new(margin, margin, margin)

				for count = 1, threadCount do
					newColoumn(terrainBlock.Position, threadCount, margin, count, 0)
				end

				treeIndex += 1

				if treeIndex == treeOffset then
					local tree = treeTemplate:Clone()

					tree.Parent = game.Workspace
					tree:SetPrimaryPartCFrame(CFrame.new(Vector3.new((width * margin) / 2 - ((x + ((rowCount - 1) * (width / rowThreadCount))) * margin), math.floor(grid[x + ((rowCount - 1) * (width / rowThreadCount))][z] / margin) * margin + chunkHeight / 2 + blockTemplate.Size.Y, (length * margin) / 2 - z * margin)))

					treeIndex = 0
					treeOffset = math.random(50, 100)
				end
			end
		end
	end)()
end

function newColoumn(position, threadCount, margin, startPosition, maxHeight)
	coroutine.wrap(function()
		local blocks = {}
		local blockIndex = startPosition
		local lastChildBlock

		repeat wait()
			local childBlock = blockTemplate:Clone()

			childBlock.Parent = game.Workspace
			childBlock.Position = Vector3.new(position.X, position.Y - margin * blockIndex, position.Z)
			childBlock.Size = Vector3.new(margin, margin, margin)
			
			blockIndex += threadCount

			lastChildBlock = childBlock
			
			table.insert(blocks, childBlock)
		until lastChildBlock.Position.Y <= maxHeight
		
		coroutine.wrap(function()
			for _, block in pairs(blocks) do
				if block.Position.Y < maxHeight then
					block:Destroy()
				end
			end
		end)()
	end)()
end

function getPerlinNoise(width, length, margin, amplitude, seed)
	local grid = {}

	for x = 1, width do
		grid[x] = {}

		for z = 1, length do
			grid[x][z] = math.noise(x / width, z / length, seed) * amplitude
		end
	end
	
	return grid
end

function newTerrain(width, length, margin, amplitude, seed, chunkHeight)
	local grid = getPerlinNoise(width, length, margin, amplitude, seed)
	local rowThreadCount = 2
	
	for rowCount = 1, rowThreadCount do
		newRow(width, length, chunkHeight, margin, rowThreadCount, rowCount)
	end
end

newTerrain(100, 100, 4, 150, 0, 256) -- | Make sure to keep the chunk height divisible by the margin for best performance

Error:

Screenshot 2023-04-04 175137

“Attempt to Index nil with number” would be doing something along the lines of a[0] where ‘a’ is an unknown variable, looking at your code you try to index “grid” but do not pass “grid” into your function “newRow”, so you would have to edit your functions to take in grid like this:

-- @ Terrain

--// Variables

local replicatedStorage = game:GetService("ReplicatedStorage")
local assets = replicatedStorage:WaitForChild("Assets")
local blockTemplate = assets:WaitForChild("Block")
local treeTemplate = assets:WaitForChild("Tree")

--// Functions

function newRow(width, length, chunkHeight, margin, rowThreadCount, rowCount, grid)
	coroutine.wrap(function()
		local treeOffset = math.random(50, 100)
		local treeIndex = 0
		
		for x = 1, width / rowThreadCount do
			for z = 1, length do
				local terrainBlock = blockTemplate:Clone()
				local threadCount = chunkHeight / margin

				terrainBlock.Parent = game.Workspace
				terrainBlock.Position = Vector3.new((width * margin) / 2 - ((x + ((rowCount - 1) * (width / rowThreadCount))) * margin), math.floor(grid[x + ((rowCount - 1) * (width / rowThreadCount))][z] / margin) * margin + chunkHeight / 2, (length * margin) / 2 - z * margin)
				terrainBlock.Size = Vector3.new(margin, margin, margin)

				for count = 1, threadCount do
					newColoumn(terrainBlock.Position, threadCount, margin, count, 0)
				end

				treeIndex += 1

				if treeIndex == treeOffset then
					local tree = treeTemplate:Clone()

					tree.Parent = game.Workspace
					tree:SetPrimaryPartCFrame(CFrame.new(Vector3.new((width * margin) / 2 - ((x + ((rowCount - 1) * (width / rowThreadCount))) * margin), math.floor(grid[x + ((rowCount - 1) * (width / rowThreadCount))][z] / margin) * margin + chunkHeight / 2 + blockTemplate.Size.Y, (length * margin) / 2 - z * margin)))

					treeIndex = 0
					treeOffset = math.random(50, 100)
				end
			end
		end
	end)()
end

function newColoumn(position, threadCount, margin, startPosition, maxHeight)
	coroutine.wrap(function()
		local blocks = {}
		local blockIndex = startPosition
		local lastChildBlock

		repeat wait()
			local childBlock = blockTemplate:Clone()

			childBlock.Parent = game.Workspace
			childBlock.Position = Vector3.new(position.X, position.Y - margin * blockIndex, position.Z)
			childBlock.Size = Vector3.new(margin, margin, margin)
			
			blockIndex += threadCount

			lastChildBlock = childBlock
			
			table.insert(blocks, childBlock)
		until lastChildBlock.Position.Y <= maxHeight
		
		coroutine.wrap(function()
			for _, block in pairs(blocks) do
				if block.Position.Y < maxHeight then
					block:Destroy()
				end
			end
		end)()
	end)()
end

function getPerlinNoise(width, length, margin, amplitude, seed)
	local grid = {}

	for x = 1, width do
		grid[x] = {}

		for z = 1, length do
			grid[x][z] = math.noise(x / width, z / length, seed) * amplitude
		end
	end
	
	return grid
end

function newTerrain(width, length, margin, amplitude, seed, chunkHeight)
	local grid = getPerlinNoise(width, length, margin, amplitude, seed)
	local rowThreadCount = 2
	
	for rowCount = 1, rowThreadCount do
		newRow(width, length, chunkHeight, margin, rowThreadCount, rowCount, grid)
	end
end

newTerrain(100, 100, 4, 150, 0, 256) -- | Make sure to keep the chunk height divisible by the margin for best performance```

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.