Generated maps make caves and its breaking my game

Hello ive been trying to make a game that has a map based on random generation but if i use the game management script there are chances it makes caves inside the map making the filling function completely break for the next maps even if i restart the code with a automatic game fixer
but if i use my test generation script which generates and deletes almost instantly there are no caves but sometimes they have similarities.
Both the scripts use the module for the generation i have made and they have diffrent effects
My questions are :

  • How would i fix this
  • Why is this happening
  • How would i stop the generation from making caves
  • How would i stop it from making generated maps that look alike

if you could answer to me how i would fix it atleast i would be happy enough


Cave screenshots

image

Tell me if you want me to make a video of the caves that break my game

5 Likes

Bumping because its been 2 hours

2 Likes

I might take a look at this a bit later.

3 Likes

have you tried looking at it yet? its been 6 hours now

2 Likes

Bumping again since i haven’t gotten a response for a lot of time and its a big issue for my game that i cant find on why its happening

2 Likes

Alright, I just took a deep dive into Perlin noise and how it is influencing your terrain generation. Things got mathy REAL quick :rofl:

Your density range may be your problem here. Your density function is as follows:

xnoise = math.noise (x/23, z/23, seed) * 15
znoise = math.noise (z/noisescale, x/noisescale, seed) * amplitude
local	density = xnoise - znoise + y`

Lower noisescale values create a more varied change from block to block (local), while a higher frequency create greater sustained changes in elevation on a more larger and grand scale on your map (global).

Then, this is the range you accept:

 if density < 5 and density > 2 then

First things first, I do not see the point of setting a lower bound to Density. I personally believe this is the main culprit as to why you are having these lower level caves. Change the line to:

 if density < 10 then

Next, I would reccommend changing your amplitude and noisescale values. If you want some real dynamic changes, what I implemented is variation of the amplitude and frequency per map spawn, where the minimum and maximum follow a normal distribution. Here is the code for this:

function module:LoadMap(DelayTime:number,CustomSeed,SpawnCharacter:boolean,RandomGeneration,Coins)

local function boxMuller()
	-- box-muller method for normal distribution
	local u1 = math.random()
	local u2 = math.random()
	local r = math.sqrt(-2.0 * math.log(u1))
	local theta = 2.0 * math.pi * u2
	return r * math.cos(theta)
end

local function scaleToDesiredRangeNorm(x, desiredMin, desiredMax)
	local normalized = (x + 3.09) / (7.18)
	return normalized * (desiredMax - desiredMin) + desiredMin
end

function NormalDistribution(desiredMin, desiredMax)
	local x = boxMuller()
	if x >= -3.09 and x <= 3.09 then
		local normvar = scaleToDesiredRangeNorm(x, desiredMin, desiredMax)
		return normvar
	else if x < -3.09 then
			local normvar = desiredMin
			return normvar
		else
			local normvar = desiredMax
			return normvar
		end
	end
end

local	GeneralSize = 50
	local	mapxsize = 25
	local	mapysize = 26
	local	mapzsize = 25
	local seed
	local	ExtraPosition = Vector3.new(0,15,0)
	if CustomSeed == nil then
		local Randomer = Random.new()
		seed = Randomer:NextInteger(1,100000)
	else
		seed = CustomSeed
	end
	workspace.GenerationData.Seed.Value = seed
	print(tostring(seed))
        local minAmplitude = 6
        local maxAmplitude = 17
        local minNoiseScale = 8
        local maxNoiseScale = 26
	local	noisescale = NormalDistribution(minNoiseScale, maxNoiseScale)
	local	amplitude = NormalDistribution(minAmplitude, maxAmplitude)
	local	blocksize = 5
	local	xnoise = 0
	local	ynoise = 0
	local	znoise = 0
	local	AllParts = 0
	local AllPartsFolder = workspace.AllParts
        -- rest of code

Let me know if this fixes your problems!

2 Likes

Also, you might want to take a look into FBM (Fractal Brownian Motion), where you create multiple “octaves” of math.noise each with different scaled amplitude and frequency (and then adding them all together with a for loop). You will need to implement the numbers for the changes in amplitude and frequency between the octaves.

The changes between the frequency of octaves is known as lacunarity. A higher lacunarity means that the changes in frequency between the octaves increases, which makes the pattern of the generation more complex and jagged.

The changes between the amplitude of octaves is known as persistence. A lower persistence makes the differences between the amplitude of octaves less, thus making the pattern of the generation more smoother.

Im going to try this when i come back home ( in about 1-2 days but i want to ask something for some reason the generation works perfectly if i use the test generation do you know why?

1 Like

What do you mean by test generation?

I have 2 codes i used
•Game management
•Test generation
They are 2 completely different scripts i generate maps with though it executes on the module still
But they have kind of different results

Im back home now first thing is that i put destiny like that to have less parts rendered and so it loads the map faster

Secondly this sadly did not work
as shown here this is the result after exactly 3 maps that were generated
its always the third one that has caves
image
also this could be a little related to the issue but sometimes the maps are the same
even though they are generated by perlin noise do you know why this is happening?

Edit: found out there are random holes sometimes in the generation when i test it
image

1 Like

Are you still facing the problem, if so, just let me know.

Bumping again since i have no replies for a long time and i cant find the solution
also i didnt see this but

Yes i am still facing this issue

bumping again since i cant really continue my project without this and its been a week now
also @armenia1997 if you could help it would be good

bumping 1 more time if i dont get any replies i will just make another post

Your test code has fewer than 100 possible seeds, so you’re going to see the same maps a lot. Perlin noise is not random, the function math.noise(x,y,z) always returns the same result for the same x, y, and z values, so your only source of randomization is the seed z value, which is some integer from 5 to 100 in your code.

Your main Perlin Noise generation loop is code that is trying to make a voxel surface that is 3 voxels thick. For each voxel column, the value (xnoise - znoise) determines the height of the surface (the range of y values between which blocks will be placed). If you’re just doing multiple calls, or just one pass on top of some random flat-ish foundation, then you’re going to get caves most of the time. Was a 3-block-thick surface not what you intended to code?

When you voxelize a surface like this, it’s always possible to get holes if the gradient of the noise surface you’re sampling is too steep. In your case, anywhere your offset (xnoise - znoise) differs by more than 3 from its neighbor columns, you can get a hole in the surface. You have to set your amplitude lower or noisescales higher to reduce the maximum possible gradient the surface to below 3.

Also, the way you wrote your LoadMap function, if you have the misfortune of passing in a CustomSeed that results in 1250 blocks or fewer being placed, that function will call itself repeatedly with that same custom seed until the call stack overflows (will break your game)

1 Like

i did that to save performance


How would i make it random then?


it only does this when the result doesn’t have many blocks which just makes it run it again till it finds one with enough blocks
it never breaks it
image
as seen here it only does it like 1 time every generation mostly


Also no one has answered me this yet if i use the simple code to make a generated map it always has a good result but if i use the game management code it makes caves and breaks after 3 attempts

Right, because your test code is all calling the LoadMap function with CustomSeed = nil. I was saying that your code will break if you call this function with an explicit CustomSeed that makes a small map, because the function with then call itself endlessly with that same CustomSeed value. The tail call should probably pass nil for CustomSeed, or just exit with a warning.

This is because you posted a lot of code, but no sample file. People won’t take the time to try to bring all your scripts into a place file one at a time with copy-paste to see what’s wrong. If you want help diagnosing this much code, your best bet is to post a minimal-repro place file (rbxl) that you can just click Play on and see the problem. It’s not clear to me from your screenshots how you’re getting caves from code that makes a 3-block surface. It looks like multiple passes are generating on top of each other, like you’re not waiting for the previous map to despawn before spawning a new one or something like that. Hard to say, it’s too much code to just read and try to figure out what’s going on vs. what you intended.

Maybe try to reload your code? if it’s problem with generating new map via perlin or something, you have to reload entire code, soo it will start from nothing. Despawning can be more simple, use clear all children for this, or loop.

the use of reports of bugs that the seed will be sent for me to look at the generated map its not going to be used in game normally


okay but most of the stuff is deteled but the code should work just as it should for the generation
Here is the file :
GenerationMapDevforumFile.rbxl


also that is just how many coins will spawn on the map which i made it to be random