I have been working on a Voxel-Based game, using a tutorial slightly. However, I have tried turning on many things to no avail. There are no meshes, no unions, no ui (not much that is, only the loading screen), and the sheer amount of blocks with textures. I need to keep the textures, or the blocks will look like solid slime. I also added fog, which bearly interferes with anything, whilst keeping everything intact. The worst part is… If I am to use anything other than these blocks, it will ruin everything, and I must restart. I am trying to go for a specific style, whilst keeping the 90,601 blocks.
Game link:
since your game is a voxel game if every voxel is the same size you can implement greedy meshing but it is complicated
another thing is that you can implement Occlusion Culling i think that the Documentation have smt abt it
there are alot of yt tutorials on these and they need alot of math
but why there are alot of voxels with the loading screen when i joined? i saw less than 5k blocks and the loading screen showed me a very large number of voxels loading
That is because I have StreamingEnabled checked.
It looks like a small number, but really, It is big.
The game is utilizing some good features for a game like this
Good feature: Preloading system
Good feature: Streaming enabled
However, one VERY important feature that you have missed for games like this is called parallel luau
It’s heavily used in chunk-loading like your game does, roblox documentation specifically talks about a system like yours to ensure frame rates remain stable.
TL’DR: You are not using parallel luau
ig a good way to reduce that amount of voxels is to rander voxels when a player is near the end of a chunk like what mc does
From what i’ve seen in the game the lag spike occurs as soon as the chunk-loading system starts and ends. Everything else seems to be fine.
I do not know how to do any of these suggestions. Any easier ones perhaps?
Greedy Meshing Algorithm - Roblox Scripting Tutorial (youtube.com) – a great vid on greedy meshing
idk any easier solution but the terrain gen method that you used is not efficient a good way of generating generating a random seed when the server starts and generate terrain based of that seed on every client that reduce the part count and remove lag spikes since they are rendered on the client and every client will generate the same terrain i know a vid on doing this i will search it up rn – i didnot find it but there are alot of tutorials on yt
This will definitely break the loading screen. I will not try this.
yeah your right i didnot notice that
just a question does your game have a limit of 90,601 generated blocks?
No, however, for some reason it always stops there. It might just be an error however.
Edit: It has to be an error. I calculated 5,192 from selecting children. This may however be client sided.
ok your game lag spikes are because of streaming enabled they arnot really lag spikes
when u get near the end of a chunk streaming enabled will load it so your game will pausesimulations until you get that info back from the server
you can click ctrl f7 / f5
you will see that your fps willnot decrease when new chuncs are being loaded
and you will see that your NetWork Recive will increase alot
Nonnonoo, I mean the lag inbetween those. Not spikes.
yeah itsnot lag its your game paused waiting for the info to be transferred to the client
i think you can change that withen the streaming setting
You could try loading all of the blocks into a 3D array ( {{},{},{}} ). When rendering the parts, you can greedy-mesh the parts in range and load them in. You will need to mark the parts that got “greedy-meshed” in another array. When unloading, you should unload the entire meshed part, so make sure you’re out of distance. You will need to start spawning the parts as soon as you are in a corner of the part
You could try implementing it with the chunk system, where you greedy-mesh every chunk by itself and load / unload it all at once. That would be more inefficient tho, because you could render bigger parts if the chunk borders weren’t there (or the chunks were way bigger, what would kinda defeat the whole purpose of chunks)
Red: Assumed Chunks Blue: Optimal meshed part
Sorry for bumping this, but I still need help. I don’t want my modeling to look ugly, so no greedy meshing.
Script:
--Variables
local seed = math.random(1,10000)
local MapSize = 300
local MapScale = MapSize/2
local BlockSize = 3
local GeneratedTreePositions = {}
local World = workspace.World
local Biome = math.random(1, 4)
local Foliage1
local BiomeLength = 0
--Terrain (Foliage)
workspace.BlocksMaxGenerated.Value = ((MapSize-MapScale-MapSize + MapScale) * (MapScale-MapScale-MapScale + MapScale))
for xAxis = MapSize-MapScale-MapSize,MapScale do
for zAxis = MapScale-MapScale-MapScale,MapScale do
local noise = math.noise(seed, xAxis/12, zAxis/12)*4.7
if Biome == 1 then
noise = math.noise(seed, xAxis/12, zAxis/12)*5.7
Foliage1 = game.ReplicatedStorage.Objects.Grass:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,math.floor(noise)*BlockSize,zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
for I = 1, 10 do
Foliage1 = game.ReplicatedStorage.Objects.Grass:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,(math.floor(noise)*BlockSize) - (BlockSize*I),zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
end
workspace.BlocksGenerated.Value += 1
elseif Biome == 2 then
noise = math.noise(seed, xAxis/12, zAxis/12)*3.7
Foliage1 = game.ReplicatedStorage.Objects.Sand:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,math.floor(noise)*BlockSize,zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
for I = 1, 10 do
Foliage1 = game.ReplicatedStorage.Objects.Sand:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,(math.floor(noise)*BlockSize) - (BlockSize*I),zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
end
workspace.BlocksGenerated.Value += 1
elseif Biome == 3 then
noise = math.noise(seed, xAxis/12, zAxis/12)*3.7
Foliage1 = game.ReplicatedStorage.Objects.Water:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,math.floor(noise)*BlockSize,zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
for I = 1, 10 do
Foliage1 = game.ReplicatedStorage.Objects.Grass:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,(math.floor(noise)*BlockSize) - (BlockSize*I),zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
end
workspace.BlocksGenerated.Value += 1
else
noise = math.noise(seed, xAxis/12, zAxis/12)*5.7
Foliage1 = game.ReplicatedStorage.Objects.Snow:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,math.floor(noise)*BlockSize,zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
for I = 1, 10 do
Foliage1 = game.ReplicatedStorage.Objects.Grass:Clone()
Foliage1:SetPrimaryPartCFrame(CFrame.new(Vector3.new(xAxis*BlockSize,(math.floor(noise)*BlockSize) - (BlockSize*I),zAxis*BlockSize)))
Foliage1.Parent = workspace["Foliage(Grass)"]
end
workspace.BlocksGenerated.Value += 1
end
--Terrain (Logs)
if Biome == 1 then
if math.random(1, 800) < 2 then
--[[local Rig = game.ReplicatedStorage.Objects.Rig:Clone()
Rig.Humanoid.Script.Enabled = true
Rig.Parent = workspace
Rig:PivotTo(CFrame.new(Foliage1.PrimaryPart.Position + Vector3.new(0, 1 * BlockSize, 0)))]]
end
if math.random(1, 800) < 2 and not GeneratedTreePositions[xAxis.." "..zAxis] then
GeneratedTreePositions[xAxis.." "..zAxis] = true
local Foliage2 = game.ReplicatedStorage.Objects.Log:Clone()
Foliage2:SetPrimaryPartCFrame(Foliage1.PrimaryPart.CFrame + Vector3.new(0, BlockSize, 0))
Foliage2.Parent = workspace["Foliage(Logs)"]
for i = 1, math.random(5, 10) do
Foliage2 = game.ReplicatedStorage.Objects.Log:Clone()
Foliage2:SetPrimaryPartCFrame(Foliage1.PrimaryPart.CFrame + Vector3.new(0, BlockSize * (i + 1), 0))
Foliage2.Parent = workspace["Foliage(Logs)"]
end
local function GenerateLeaf(i, Offset)
Foliage1 = game.ReplicatedStorage.Objects.Grass:Clone()
Foliage1:SetPrimaryPartCFrame(Foliage2.PrimaryPart.CFrame + Offset * Vector3.new(BlockSize, BlockSize, BlockSize) - Vector3.new(0, 0 - (i * (BlockSize * -2))))
Foliage1.Parent = workspace["Foliage(Leaves)"]
Foliage1.PrimaryPart.CanCollide = false
end
GenerateLeaf(0, Vector3.new(0, 1, 0))
for i = 1, math.random(2, 4) do
GenerateLeaf(i - 1, Vector3.new(0, 0, 1))
GenerateLeaf(i - 1, Vector3.new(-0, 0, -1))
GenerateLeaf(i - 1, Vector3.new(1, 0, 0))
GenerateLeaf(i - 1, Vector3.new(-1, 0, -0))
GenerateLeaf(i - 1, Vector3.new(0, 0, 2))
GenerateLeaf(i - 1, Vector3.new(-0, 0, -2))
GenerateLeaf(i - 1, Vector3.new(2, 0, 0))
GenerateLeaf(i - 1, Vector3.new(-2, 0, -0))
GenerateLeaf(i - 1, Vector3.new(1, 0, 1))
GenerateLeaf(i - 1, Vector3.new(-1, 0, -1))
GenerateLeaf(i - 1, Vector3.new(1, 0, -1))
GenerateLeaf(i - 1, Vector3.new(-1, 0, 1))
end
end
if math.random(1, 1800) < 2 and not GeneratedTreePositions[xAxis.." "..zAxis] then
GeneratedTreePositions[xAxis.." "..zAxis] = true
local Foliage2 = game.ReplicatedStorage.Objects.Rock:Clone()
Foliage2:SetPrimaryPartCFrame(Foliage1.PrimaryPart.CFrame + Vector3.new(0, BlockSize, 0))
local function GenerateLeaf(i, Offset)
Foliage1 = game.ReplicatedStorage.Objects.Rock:Clone()
Foliage1:SetPrimaryPartCFrame(Foliage2.PrimaryPart.CFrame + Offset * Vector3.new(BlockSize, BlockSize, BlockSize) - Vector3.new(0, 0 - (i * (BlockSize * -2))))
Foliage1.Parent = workspace["Foliage(Rocks)"]
Foliage1.Parent = workspace
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(0, 1, 0))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(0, 0, 1))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(-0, 0, -1))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(1, 0, 0))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(-1, 0, -0))
end
end
elseif Biome == 3 then
if math.random(1, 400) < 2 and not GeneratedTreePositions[xAxis.." "..zAxis] then
GeneratedTreePositions[xAxis.." "..zAxis] = true
local Foliage2 = game.ReplicatedStorage.Objects.Log:Clone()
Foliage2:SetPrimaryPartCFrame(Foliage1.PrimaryPart.CFrame + Vector3.new(0, BlockSize, 0))
Foliage2.Parent = workspace["Foliage(Logs)"]
for i = 1, math.random(5, 10) do
Foliage2 = game.ReplicatedStorage.Objects.Log:Clone()
Foliage2:SetPrimaryPartCFrame(Foliage1.PrimaryPart.CFrame + Vector3.new(0, BlockSize * (i + 1), 0))
Foliage2.Parent = workspace["Foliage(Logs)"]
end
local function GenerateLeaf(i, Offset)
Foliage1 = game.ReplicatedStorage.Objects.Snow:Clone()
Foliage1:SetPrimaryPartCFrame(Foliage2.PrimaryPart.CFrame + Offset * Vector3.new(BlockSize, BlockSize, BlockSize) - Vector3.new(0, 0 - (i * (BlockSize * -2))))
Foliage1.Parent = workspace["Foliage(Leaves)"]
Foliage1.PrimaryPart.CanCollide = false
end
GenerateLeaf(0, Vector3.new(0, 1, 0))
for i = 1, math.random(2, 4) do
GenerateLeaf(i - 1, Vector3.new(0, 0, 1))
GenerateLeaf(i - 1, Vector3.new(-0, 0, -1))
GenerateLeaf(i - 1, Vector3.new(1, 0, 0))
GenerateLeaf(i - 1, Vector3.new(-1, 0, -0))
GenerateLeaf(i - 1, Vector3.new(0, 0, 2))
GenerateLeaf(i - 1, Vector3.new(-0, 0, -2))
GenerateLeaf(i - 1, Vector3.new(2, 0, 0))
GenerateLeaf(i - 1, Vector3.new(-2, 0, -0))
GenerateLeaf(i - 1, Vector3.new(1, 0, 1))
GenerateLeaf(i - 1, Vector3.new(-1, 0, -1))
GenerateLeaf(i - 1, Vector3.new(1, 0, -1))
GenerateLeaf(i - 1, Vector3.new(-1, 0, 1))
end
end
if math.random(1, 100) < 2 and not GeneratedTreePositions[xAxis.." "..zAxis] then
GeneratedTreePositions[xAxis.." "..zAxis] = true
local Foliage2 = game.ReplicatedStorage.Objects.Snow:Clone()
Foliage2:SetPrimaryPartCFrame(Foliage1.PrimaryPart.CFrame + Vector3.new(0, BlockSize, 0))
Foliage2.Parent = workspace
local function GenerateLeaf(i, Offset)
Foliage1 = game.ReplicatedStorage.Objects.Snow:Clone()
Foliage1:SetPrimaryPartCFrame(Foliage2.PrimaryPart.CFrame + Offset * Vector3.new(BlockSize, BlockSize, BlockSize) - Vector3.new(0, 0 - (i * (BlockSize * -2))))
Foliage1.Parent = workspace["Foliage(Rocks)"]
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(0, 1, 0))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(0, 0, 1))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(-0, 0, -1))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(1, 0, 0))
end
if math.random(1, 2) == 1 then
GenerateLeaf(0, Vector3.new(-1, 0, -0))
end
end
end
end
if math.random(1, 10) == 1 and BiomeLength > MapSize / 20 then
Biome = math.random(1, 3)
BiomeLength = 0
end
BiomeLength += 1
wait()
end
Did you atleast fix the lag spike?
^ Don’t think so
Have you not started using parallel luau?
Also nice code, I don’t think I could ever make a terrain generation system thing.