The idea
Procedural terrain generation that generates a flat world (kind of like the Minecraft super-flat world) that uses a block system (again similar to Minecraft)
The world will be made up of several block types, and it will be around 20 or more blocks in height.
A pipe structure that runs from the surface layer to the bottom layer. (the pipe structure is made up of several blocks of pipes)
A hollow block, which can create cave systems
A solid block which makes up the rest of the world.
The execution
I am not sure where to start, as I don’t see a way of using Perlin noise for this. I would appreciate any feedback, or references to other posts.
Also, the terrain should be generated as the server loads up, if anyone has any ideas on how to improve performance please leave them below.
I would recommend watching this series of tutorials on procedural terrain generation, in which he goes over several different types of generations. I hope this helps.
You’re correct that Perlin noise is a poor choice for your application. It’s great for rolling terrain and hills, but it fails pretty hard at cave generation.
Your best bet is to look at maze generation algorithms. The standard recursive backtracker algorithm that is the most common approach for making 2D rectilinear mazes also generalizes to a 3D voxel grid and is very easy to modify the probabilities to get different characters of caves, and to add support for varying the tunnel cross sections or adding chambers and rooms. You can bias the search direction to force caves to be more horizontal, more vertical, have straighter passages, etc.
You could also use a modular approach, where you have pre-defined sections (tunnels, bends, rooms, etc.) and connect them up procedurally, like a random dungeon generator.
There are lots of other approaches too; cave generation is a bit of an art form, without one go-to solution.
I would make sure to optimise the terrain generation tool that you are using. The way that Minecraft’s generation works isn’t just blocks places next to each other. Each chunk is made into a mesh, where all of the blocks are turned into one model, in order for the game not to have all of the blocks individually.
I’m not sure of a way to go ahead with optimisation for this, as ROBLOX doesn’t let you easily generate meshes, but It is definitely something for you to take into consideration at later stages if you plan on using it in a final product or game.
You generally have to do greedy run-length merging, where if you have say, 6 blocks in a row that are all the same material, you convert this ‘run’ to a 6x1x1 single Part, and rely on texture tiling to make it look the same as when it was individual cubes. You can do this in all 3 directions, until you run out of things to combine.
Oh okay, that’s actually really smart to be honest. I think it probably isn’t as good as using mesh manipulation like Minecraft uses, but for Roblox this would be quite a good way to reduce lag on the player and server side. The main problem is if they plan on letting the player create and remove blocks from the terrain, then re-evaluating the sizes of the shapes might cause a bit of a problem.
That’s a problem you have to solve to do this kind of optimization, no matter what. If a player removes a block that is part of a multi-block part, that whole chunk of voxels has to be re-evaluated and re-optimized by the same algorithm, there’s no way around it.
Even with block add or removal, you generally want to split the affected (invalidated) clusters back into individual blocks, and defer the re-optimization until they’re done working in the area, so that you don’t have constant re-meshing killing the server framerate.The optimization can usually run like a background task, with a fixed time slice to ensure it doesn’t affect performance.
I don’t think I’ve seen a good 3D reference for this, most of the good demos are 2D. But the recursive backtracking algorithm trivially extends to 3D; if you have a demo for a 2D grid, you just add UP and DOWN to the list of possible directions you can go from any voxel, and make whatever data structures they’re using (e.g. arrays) from 2D to 3D.