posted by owen on Tue, 12th Sep.
Despite what online video tutorials might lead you to believe procedural generation (procgen) in video games is hard, like really hard. You might as well skip height maps and go right to the hard stuff. The hard stuff will sneak up on you quickly like enemies popping into view in a n64 game. Coincidentally the hard stuff is the same point at which most tutorials reach 10 thousand lines of code and stuck in a corner to linger forever. I am not going to go down that path, all I am going to do is outline what I have learnt over the little time I spent working on my own little procgen side project.
Randomness and Chaos
People seem to think of procedural generation (pg) as generating random points for use in a rendering graphics or content but soon they will discover that it is not about the randomness at all. Randomness is just a sideeffect that often leads to chaos when you are working with human beings. What you really need is constrained "predictability". Randomness is the least of your problems. Predictability is why so many tutorials use simplex/perlin noise. Simplex noise gives predictable results in a set range between -1..to..1 which you can use to produce predictable procedural content that only "seems" random. Randomness is NOT what you want. The goal is to have controlled space that appears random - not chaos.
Avoid simulating the real world
Some will attempt to create something like what was done in No Man's Sky or Minecraft but fail to understand that the real world does not work like a computer. No matter how much code you write or fast the code is you cannot simulate everything in the real world. And even if you try, it is going to take you a really, really, really long time just to get the basic stuff in place. You are gonna have to decide what is important to simulate and what you will simply leave to the imagination. Game consoles and computers nowadays have upwards of 4 gigs of RAM and they still have to resort to trickery and shaders. It may seems like your favorite game is a true masterpiece but it is mostly smoke and mirrors once you figure out how it all works. This figuring out takes time - many dead bodies liter the highway.
Picking a noise function
A good noise function needs to be fast and is often complicated to code so it is best to stick with simplex noise or something similar. Tutorials often state that you can use any noise function you want but you want to avoid functions that are "random" as mentioned earlier - you want to know what result you are going to get. And you want to be able to repeat previous results so that you can test different outcomes in different scenarios.
Draw distance, view space, LODs, cache and culling
You will be tempted to fill your screen with tonnes of flowers and trees and such early on until you realize that your computer cannot keep up with all the information. The world is full of information, more information that you can imagine. Most pretty video games that you see being published today are using all sorts of trickery to render the information you see. It is not only down to the skill of the program but Art, RAM and disk read speed. The level of detail (LOD) of the environment has alot to do with it as well. Some games have asset pipelines that auto-generate thousands of models just for one scene and then stream them in seamlessly. Other games store entire static sections of the game world on disk or in memory during loading instead of rendering it all in real time. You will have to sacrifice something depending on your situation. If you cannot pay 10,000 artists then you might want to keep your scope down to something that you can mange.
Distractions are everywhere
Feature/Scope creep is worse in procedural generation. Everybody wants everything as the case was in No Man's Sky. You think you can program every leaf on a plant blowing in the wind on a moon of Saturn but how much time do you have in the day? Not allot. And you will see someone using a cool shader in Unity and you will be like: "I want that in my code too!". Avoid the temptation. That stuff will only lead you down a road of pain and frustration. That fancy shader is probably using up 90% of the available CPU/GPU cycles - leaving nothing left for any kind of game play. It took me almost a year to get wave animations on bodies of water. Mostly my own ignorance because it just came to me one night but the key lesson is being able to notice when a "nice-to-have" feature is wasting you productive time and being able to leave it alone and move on to something more important.
Keeping track of everything
It is good to be generating lots of stuff but you will come to a point where you need to know where something is or was and some kind of key/id to identify it. There might be objects that are longer needed such as dead enemies and trees that you have already cut down. The solution that I have is to keep track/save the xyz point at which I generated the object. In my system I try to ensure that only one thing is generated at every point in the world. So even if the object has moved to another spot I can check the object listing to see if something with an matching origin point has already been generated or if I need to generate it for the first time. This only applies to things that can be killed or have AI movement. Most things would otherwise not need to be tracked.
When the going gets tough
While writing your #procgen thing one of the first challenges you will come up against is how to place stuff in the world without them overlapping against each other, floating trees, planets colliding and caves - Oh god caves! This is what alot of online tutorials fail to tell you: if you start by using hieght maps you are going run into a wall where you cannot do caves and you end up putting too much data into cache. Loops, in loops, in loops then you hit the point when you try to solve it with threading - anytime you see some one start using threading you know that it is going to be a roller coaster down the rabbit hole. Avoid threading unless it is the last thing you implement - its a rabbit hole - it will not help. If the code is too slow to run on the main thread at such an early stage then you are doing too much. Stop - hammer time.
In the end procgen is not about replay-ability or creating lots of content or infinite worlds or pretty graphics or whatever people are hyping nowadays. Procgen is (at its root) about maintaining state of a complex system. You can generate a billion pieces of content but if you cannot put them together in a cohesive system then you are basically just generating garbage at which point you might as well hand make the level and be done with it. You can only play a game that you finish making. Expect to spend a great deal of time figuring out how to keep the state of all the stuff you are generating. Anyway good luck and happy proc-gen-ing!
How Grids and Patterns Work Together by Eric Broug
Math Encounters -- Beyond Animation Ken Perlin (Presentation)
Making maps with noise functions from Red Blob Games