Need help with creating randomly generated caves

Hello! So here is my issue: I can get Perlin worms to generate just fine but I’m currently stuck trying to figure out how to create tunnels with them. I do not want to spawn in a bunch of parts and delete them one by one to create the tunnel. That causes lag and also leaves parts outside of the caves that the player won’t even see.

What I want is blocky tunnel like caves where all the blocks are 3x3x3. sizes vary from small tunnels to big caverns. I only want one layer of blocks, no blocks outside of the caves.

Here is the picture of what I have so far

And here is the code for that:

local Seed = tick()
local Resolution = 4
local NumWorm = 0

local worms = {
	{},
	{},
	{},
	{},
	{},
	{},
}

while wait() do
	NumWorm = NumWorm+1
	local sX = math.noise(NumWorm/Resolution+.1,Seed)
	local sY = math.noise(NumWorm/Resolution+sX+.1,Seed)
	local sZ = math.noise(NumWorm/Resolution+sY+.1,Seed)
	local WormCF = CFrame.new(sX*500,sY*500,sZ*500)
	print("Worm "..NumWorm.." spawning at "..WormCF.X..", "..WormCF.Y..", "..WormCF.Z)
	local Dist = (math.noise(NumWorm/Resolution+WormCF.p.magnitude,Seed)+.5)*500

	for i = 1,Dist do
		wait()
		local X,Y,Z = math.noise(WormCF.X/Resolution+.1,Seed),math.noise(WormCF.Y/Resolution+.1,Seed),math.noise(WormCF.Z/Resolution+.1,Seed)
		WormCF = WormCF*CFrame.Angles(X*2,Y*2,Z*2)*CFrame.new(0,0,-Resolution)
		local Part = Instance.new("Part")
		Part.Anchored = true
		Part.CFrame = CFrame.new(math.clamp(WormCF.p.X,-250,250),math.clamp(WormCF.p.Y,-250,250),math.clamp(WormCF.p.Z,-250,250))
		Part.Parent = workspace
		table.insert(worms[NumWorm],Part)
	end
	if NumWorm >= 6 then
		break
	end
end

To create blocky tunnels with Perlin worms, you can use a similar approach to the one used to generate the worms themselves. Instead of spawning parts, you can modify the values in a 3D array to create the tunnel shape, and then convert that array into a mesh.

Here are the basic steps you can follow:

  1. Define the size of your tunnel. Decide how big you want your tunnel to be and create a three-dimensional array to hold the data for the tunnel.
  2. Use Perlin worms to create a path through the tunnel. You can use the same Perlin worm generation technique you used before, but this time you’ll need to adjust it to only generate a single layer of blocks.
  3. Set the values in the array to create the tunnel shape. Once you have the path of the tunnel, you can set the values in the array to create the tunnel shape. You can set the values to 1 for the blocks that should be part of the tunnel and 0 for the blocks that should be outside of the tunnel.
  4. Convert the array into a mesh. You can use a library like Roact or make your own mesh generator to convert the 3D array into a 3D mesh that can be placed in the game world.

Here’s an example code snippet that demonstrates how to create a blocky tunnel using Perlin worms:

-- Define the size of the tunnel
local width = 50
local height = 50
local depth = 50

-- Create a 3D array to hold the tunnel data
local tunnel = {}
for x = 1, width do
    tunnel[x] = {}
    for y = 1, height do
        tunnel[x][y] = {}
        for z = 1, depth do
            tunnel[x][y][z] = 0
        end
    end
end

-- Use Perlin worms to create a path through the tunnel
local perlinWorms = require(game:GetService("ReplicatedStorage").PerlinWorms)
local seed = os.time()
local path = perlinWorms.generate(width, height, depth, seed)

-- Set the values in the array to create the tunnel shape
local radius = 1.5
for i, point in ipairs(path) do
    for x = -radius, radius do
        for y = -radius, radius do
            for z = -radius, radius do
                local xi = point.x + x
                local yi = point.y + y
                local zi = point.z + z
                if xi >= 1 and xi <= width and yi >= 1 and yi <= height and zi >= 1 and zi <= depth then
                    tunnel[xi][yi][zi] = 1
                end
            end
        end
    end
end

-- Convert the tunnel data into a mesh
local mesh = game:GetService("Workspace").Terrain:ImportHeightMap(tunnel, Vector3.new(width, depth, height), Vector3.new(3, 3, 3))
mesh.Parent = game:GetService("Workspace")

Note that this code generates a very basic blocky tunnel using Perlin worms. You may want to adjust the parameters and add additional features to make the tunnel more interesting and realistic.

Sorry to bother but I don’t understand some parts,
first, I do not understand this part of the code

local perlinWorms = require(game:GetService("ReplicatedStorage").PerlinWorms)
local path = perlinWorms.generate(width, height, depth, seed)

What is require? I don’t know what require does, if it is not too much trouble could you explain to me what require is?

local mesh = game:GetService("Workspace").Terrain:ImportHeightMap(tunnel, Vector3.new(width, depth, height), Vector3.new(3, 3, 3))

The main issue here is the “ImportHeightMap” function. I can’t seem to find much on this function.

And last of all, in step 4 you mention using a “Mesh generator”. What is a mesh generator?

Sorry for my inexperience.

require is a function that loads and executes a module. A module is a script that defines functions, tables, and other data that can be shared between multiple scripts. The name of the module is usually the file name of the script without the .lua extension. The require function looks for the module in a set of predefined directories, and returns the value returned by the module’s return statement.

In the code you provided, require(game:GetService("ReplicatedStorage").PerlinWorms) loads a module named PerlinWorms from the ReplicatedStorage service. The PerlinWorms module defines a function called generate that generates a path of points using Perlin worms. The path variable is assigned the result of calling the generate function with the specified width , height , depth , and seed arguments.

A height map image can be used to create terrain using the ImportHeightMap method of the Terrain object. The tunnel variable in the code you provided is a 2D array of height values that represents the contours of the cave. This height map is used to create the terrain, which is then represented by a Mesh object by the ImportHeightMap function. A Mesh is a collection of polygons that determines a 3D object’s shape. Complex 3D shapes like buildings, terrain, and props can be made using meshes. A mesh generator is a device or function that uses a set of parameters or rules to programmatically generate meshes.

The ImportHeightMap function, which creates a mesh from a height map image, serves as the mesh generator in the context of the code you provided. With each block measuring 3x3x3 studs, the resulting mesh is a blocky representation of the cave.

Since when did a ImportHeightMap() function exist for Terrain?

Also you answered none of his questions, you only explained what those parts of the code do.

They’re using ChatGPT. Ignore them.

Also, I’ll help out later to the best of my ability. I’m not the most familiar with Perlin noise, so I’d rather wait until I get home to help out!

4 Likes

It doesn’t. ChatGPT doesn’t work well at all for anything relating to roblox.

Ok, thanks for warning me. I was starting to get confused with some of the stuff they were telling me.

A lot of the code is nonsense anyway. A lot of it based on stuff you never even said existed, because it is probably stuff that doesn’t exist in your game.