You can write your topic however you want, but you need to answer these questions:
*I am working on a game that is procedurally generated where the players are able to freely excavate and build in, and also be able to save their builds within CreatePlaceAsync().
**I cannot find a way how I can make my game have less parts for their devices to be able to play without lagging
**I have tried to union the parts, but I can’t quite figure out how I can let the players excavate trough the terrain
The game needs some sort of optimizing to allow any device run it on at least level 3 graphics
mapxsize = script.Parent.CFrame.X + 16
mapysize = script.Parent.CFrame.Y + 100
mapzsize = script.Parent.CFrame.Z + 16
seed = workspace.SEED.Value
noisescale = 30
amplitude = 20
psize = 3.054
for x=script.Parent.CFrame.X,mapxsize do
for z=script.Parent.CFrame.Z,mapzsize do
for y=script.Parent.CFrame.Y,mapysize do
xnoise = math.noise(y/mapysize, z/mapzsize, seed)*amplitude
znoise = math.noise(x/mapxsize, y/mapysize, seed)*amplitude
ynoise = math.noise(x/mapxsize, z/mapzsize, seed)*amplitude
density = xnoise + ynoise + znoise + y
if density < 20 and density > 10 then
p = Instance.new("Part", workspace.TerrainFolder)
p.Anchored = true
p.Size = Vector3.new(psize, psize, psize)
p.CFrame = CFrame.new(x*psize, y*psize, z*psize)
if p.CFrame.Y > 30 and p.CFrame.Y < 70 then
local c = game.ReplicatedStorage.Blocks.Nature.Grass:Clone()
c.Parent = workspace.TerrainFolder
c:SetPrimaryPartCFrame(p.CFrame)
p:Destroy()
elseif p.CFrame.Y > 70 and p.CFrame.Y < 100 then
local c = game.ReplicatedStorage.Blocks.Nature.Stone:Clone()
c.Parent = workspace.TerrainFolder
c:SetPrimaryPartCFrame(p.CFrame)
p:Destroy()
elseif p.CFrame.Y > 100 then
local c = game.ReplicatedStorage.Blocks.Nature.Snow:Clone()
c.Parent = workspace.TerrainFolder
c:SetPrimaryPartCFrame(p.CFrame)
p:Destroy()
elseif p.CFrame.Y < 70 then
local c = game.ReplicatedStorage.Blocks.Nature.Sand:Clone()
c.Parent = workspace.TerrainFolder
c:SetPrimaryPartCFrame(p.CFrame)
p:Destroy()
end
end
end
end
wait()
end
NOTE: This code belongs in a normal script parented to a part.
If players will only be walking on top of the terrain, there’s no point generating all the blocks below that. This also works if you’re not using straight up 2D heightmaps. The only blocks that need to be generated are the ones on the “surface” between inside and outside the terrain.
You can check if a position is on the boundary by seeing if it’s both solid and one or more of its neighbors is non-solid. That looks like so:
When a block gets “digged” or otherwise destroyed, update all the surrounding blocks and build them if they’ve become surface blocks as a result of the block being destroyed.
Here's the code I used to generate it:
mapxsize = 16
mapysize = 64
mapzsize = 64
seed = 0
noisescale = 1/64
amplitude = 10
psize = 3.054
function get_density(v3)
return math.noise(v3.X * noisescale, v3.Y * noisescale, v3.Z * noisescale + seed)*amplitude
end
function is_on_boundary(v3)
if get_density(v3) <= 0 then
return false
end
for _, dirEnum in pairs(Enum.NormalId:GetEnumItems()) do
local dir = Vector3.FromNormalId(dirEnum)
local neighbor_pos = v3 + dir * psize
local neighbor_density = get_density(neighbor_pos)
if neighbor_density <= 0 then
return true
end
end
return false
end
for x=0,mapxsize do
for z=0, mapzsize do
for y=-mapysize/2, mapysize/2 do
local pos = Vector3.new(x, y, z) * psize
density = get_density(pos)
if density > 0 and is_on_boundary(pos) then
local c
if pos.Y > 30 and pos.Y < 70 then
c = game.ReplicatedStorage.Block1:Clone()
elseif pos.Y > 70 and pos.Y < 100 then
c = game.ReplicatedStorage.Block2:Clone()
elseif pos.Y > 100 then
c = game.ReplicatedStorage.Block3:Clone()
elseif pos.Y < 70 then
c = game.ReplicatedStorage.Block4:Clone()
end
c.Parent = workspace.TerrainFolder
c:SetPrimaryPartCFrame(CFrame.new(x*psize, y*psize, z*psize))
end
end
end
wait()
end
Oh my god, It works like a charm! Thank you so much, I will try to find a way to divide the terrain into chunks, to load them individually and optimize even further!
But there is one issue, the game generates like an entire cave system
Allow me to elaborate
This is what I got from your code within a 16 x 100 x 16 block sized generation
The player is supposed to spawn in the top of the world, having the surface look like an actual minecraft world over view, but instead it looks like the minecraft far lands when generated within a 100 x 100 x 100 world
If you tune it right you won’t get floaties but there’s a limit to the mountain intensity you can have with this approach.
If you want more extreme terrain with no floaties, check out this post:
And here’s some info on Perlin worm cave generation:
… although I wouldn’t recommend the Perlin worm thing, it’s complicated and doesn’t work that great unless you spend a lot of time tuning it.
EDIT: Here’s the code
local BLOCK_SIZE = 4
local MAP_SIZE = Vector3.new(128, 64, 128)
local MOUNTAIN_INTENSITY = 8
seed = 0
noisescale = 1/64
amplitude = 10
function get_density(v3)
local noise_value = math.noise(v3.X * noisescale, v3.Y * noisescale, v3.Z * noisescale + seed)*amplitude
local height_bonus = -v3.Y / MOUNTAIN_INTENSITY + 8
return noise_value + height_bonus
end
function is_on_boundary(v3)
if get_density(v3) <= 0 then
return false
end
for _, dirEnum in pairs(Enum.NormalId:GetEnumItems()) do
local dir = Vector3.FromNormalId(dirEnum)
local neighbor_pos = v3 + dir * BLOCK_SIZE
local neighbor_density = get_density(neighbor_pos)
if neighbor_density <= 0 then
return true
end
end
return false
end
for x = 0, MAP_SIZE.X do
for y = 0, MAP_SIZE.Y do
for z = 0, MAP_SIZE.Z do
local block_pos = Vector3.new(x, y, z) * BLOCK_SIZE
local density = get_density(block_pos)
if density > 0 and is_on_boundary(block_pos) then
local block = script.Block:Clone()
block.Parent = game.Workspace
block.CFrame = CFrame.new(block_pos)
if y > 25 then
block.BrickColor = BrickColor.White()
elseif y < 23 then
block.BrickColor = BrickColor.Green()
else
block.Color = Color3.fromRGB(108, 88, 75)
end
end
end
end
wait()
end