Provide an overview of:
- What does the code do and what are you not satisfied with?
- What potential improvements have you considered?
- How (specifically) do you want to improve the code?
This code generates a Minecraft type world for my game. Works perfectly, except that it lags. On mid range devices its playable, but on low range devices it will be extremely laggy and aunplayable. Also, my grid system will only update after a yield. I don’t want to add more yields as everything will spawn in slowly. The main problem is how many parts I am generating. Is there any way to make this more efficient?
Image for the scale of parts i am generating:
wait()
local rs = game:GetService("RunService") -- Using Heartbeat as a yield function
local seed = math.random(-1000000000, 1000000000) --Get the seed
local Generated = 0 -- Name chunks
local pCache = require(game.ReplicatedStorage.PartCache)
local function fractalNoise(x, y, octaves, lacunarity, persistence, scale, seed) -- Create the noise map
local value = 0
local x1 = x
local y1 = y
local amplitude = 1
for i = 1, octaves, 1 do
value += math.abs(math.noise(x1 / scale, y1 / scale, seed)) * amplitude
y1 *= lacunarity
x1 *= lacunarity
amplitude *= persistence
end
value = value ^ 2
return value
end
local colorTable = { -- Database for colors and materials
{
Color = Color3.fromRGB(0, 0, 0), -- Black
NoiseScale = nil,
StartHeight = -600,
EndHeight = -159,
UseNoise = false,
Threshold = nil,
Material = Enum.Material.Slate,
},
{
Color = Color3.fromRGB(95, 97, 95), -- Gray
NoiseScale = 1,
StartHeight = -159,
EndHeight = -12,
UseNoise = true,
Threshold = 0.1,
Material = Enum.Material.Slate,
},
{
Color = Color3.fromRGB(42, 86, 62), -- Green
NoiseScale = 3,
StartHeight = -8,
EndHeight = 25,
UseNoise = true,
Threshold = 0.4,
Material = Enum.Material.Grass,
},
{
Color = Color3.fromRGB(95, 97, 95), -- Gray
NoiseScale = 4,
StartHeight = 20,
EndHeight = 40,
UseNoise = true,
Threshold = 0.5,
Material = Enum.Material.Slate,
},
{
Color = Color3.fromRGB(255, 255, 255), -- White
NoiseScale = 30,
StartHeight = 45,
EndHeight = 300,
UseNoise = true,
Threshold = 0.75,
Material = Enum.Material.Sand,
},
}
local function linearStep(a, b, c) -- Equation
return math.clamp( (c - a) / (b - a), 0, 1)
end
function generate(x, y, z, height, color, material, folder) --Create the parts
y = math.floor(y)
if y%4 ~= 0 then -- Lock parts to a grid
y+=1
if y%4 ~= 0 then
y+=1
if y%4 ~= 0 then
y+=1
if y%4 ~= 0 then
y+=1
end
end
end
end
if not game.ReplicatedStorage.ChunkHolder:FindFirstChild(folder) then -- Create the folder, hold parts in replicated storage before putting them in the game
local newfolder = Instance.new("Folder", game.ReplicatedStorage.ChunkHolder)
newfolder.Name = folder
end
local part = game.ReplicatedStorage.Part:Clone()
part.Parent = game.ReplicatedStorage.ChunkHolder:FindFirstChild(folder)
part.Position = Vector3.new(x, math.floor(y), z)
part.Color = color
part.Material = material
y-=4
for i = math.floor(y), -160, -4 do -- Make underground parts
for _, colorData in ipairs(colorTable) do
if i >= colorData.StartHeight then
if colorData.UseNoise then
local colorValue = math.noise(x / colorData.NoiseScale, y/ colorData.NoiseScale, seed * 123)
colorValue = (colorValue + 1) / 2
local stepResult = linearStep(colorData.StartHeight, colorData.EndHeight, y)
colorValue = (1 - stepResult) * colorValue + stepResult
if colorValue > colorData.Threshold then
color = colorData.Color
material = colorData.Material
end
else
color = colorData.Color
material = colorData.Material
end
end
end
if color == Color3.fromRGB(42, 86, 62) then -- Create dirt if there should be grass
color = Color3.fromRGB(144, 84, 54)
material = Enum.Material.Sand
end
local part = game.ReplicatedStorage.Part:Clone()
part.Parent = game.ReplicatedStorage.ChunkHolder:FindFirstChild(folder)
part.Position = Vector3.new(x, i, z)
part.Color = color
part.Material = material
end
local chunkPart = Instance.new("Part") -- Create an unbreakable part so the game knows to not generate anything here
chunkPart.Name = "ChunkPart"
chunkPart.Transparency = 1
chunkPart.Anchored = true
chunkPart.Size = Vector3.new(4, 100000000, 4)
chunkPart.Position = Vector3.new(x, 0, z)
chunkPart.Parent = game.ReplicatedStorage.ChunkHolder:FindFirstChild(folder)
chunkPart.CanCollide = false
game.ReplicatedStorage.ChunkHolder:FindFirstChild(folder).Parent = workspace.World
Generated+=1
end
local function generateChunk(xmin, xmax, zmin, zmax, name) -- Calculations for every part
local xcount = 4
local zcount = 4
if xmax < xmin then xcount = -4 end
if zmax < zmin then zcount = -4 end
for x=xmin, xmax,xcount do
rs.Heartbeat:Wait()
for z=zmin, zmax, zcount do
rs.Heartbeat:Wait()
local y1 = math.noise(x*0.35/100, z*0.35/100, seed)
local y2 = math.noise(x*0.35/100, z*0.35/100, seed)
local y3 = math.noise(x*0.35/100, z*0.35/100, seed)
local y= (y1*y2*15*15)
local height = fractalNoise(x, z, 10, 1, 0.35, 100, seed) * 5 -- Multiplying changes how high up it will be, useful for mountain biomes
local color = nil
local material = nil
for _, colorData in ipairs(colorTable) do -- Get the color
if height >= colorData.StartHeight then
if colorData.UseNoise then
local colorValue = math.noise(x / colorData.NoiseScale, z/ colorData.NoiseScale, seed)
colorValue = (colorValue + 1) / 2
local stepResult = linearStep(colorData.StartHeight, colorData.EndHeight, height)
colorValue = (1 - stepResult) * colorValue + stepResult
if colorValue > colorData.Threshold then
color = colorData.Color
material = colorData.Material
end
else
color = colorData.Color
material = colorData.Material
end
end
end
generate(x, height, z, y, color, material, name)
end
end
end
local function generateGrid(c) -- Create grid around players for world generation
for i, part in pairs(workspace.GridParts:GetChildren()) do
c:ReturnPart(part)
end
rs.Heartbeat:Wait()
for i, plr in pairs(game.Players:GetPlayers()) do
rs.Heartbeat:Wait()
local char = plr.Character or plr.CharacterAdded:Wait()
local xpos = char:GetBoundingBox().p.X
local zpos = char:GetBoundingBox().p.Z
xpos = math.round(xpos)
zpos = math.round(zpos)
if xpos%4 ~= 0 then
xpos +=1
if xpos%4 ~= 0 then
xpos +=1
if xpos%4 ~= 0 then
xpos +=1
if xpos%4 ~= 0 then
xpos +=1
end
end
end
end
if zpos%4 ~= 0 then
zpos +=1
if zpos%4 ~= 0 then
zpos +=1
if zpos%4 ~= 0 then
zpos +=1
if zpos%4 ~= 0 then
zpos +=1
end
end
end
end
for x = xpos - 32, xpos + 32, 4 do
for z = zpos - 32, zpos + 32, 4 do
local gridPart = c:GetPart()
gridPart.Parent = workspace.GridParts
gridPart.Position = Vector3.new(x, 15, z)
end
end
end
end
local function findChunk(origin, direction) -- Check if there is already a chunk
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Blacklist
local Result = workspace:Raycast(origin, direction, params)
if Result then
return(true)
else
return(false)
end
end
local function generateChunksfromGrid(gen) -- Create the chunks from the grid
for i, gridPart in pairs(workspace.GridParts:GetChildren()) do
local hasChunk = findChunk(gridPart.Position, Vector3.new(0, -10000, 0))
if not hasChunk then
generateChunk(gridPart.Position.X,gridPart.Position.X,gridPart.Position.Z,gridPart.Position.Z, "Chunk"..tostring(gen))
end
end
end
local newCache = pCache.new(game.ReplicatedStorage.GridPart, 300, script.Cache) -- PartCache, less lag
while wait() do
generateGrid(newCache)
generateChunksfromGrid(Generated)
end
If you want to know how it works, this person made a great tutorial.