How do you create unique and random game worlds and maps? Unique and random game maps and worlds can be created procedurally in code using noise. The noise is good for simulating nature because it produces values that change randomly in small amounts with no abrupt changes and provides realistic curves to rivers or hills. Noise is not good for straight or square items.
What does noise look like?
We normally think of noise as something we hear. Something is noisy or loud. That’s not the type of noise I’m talking about. This noise is sometimes called Perlin Noise after Ken Perlin who created a computer algorithm to generate the noise. The noise is really a map of values that gradually change.
It’s possible to assign colors to the values and then they form an image that looks a lot like wispy clouds. This is a picture of noise that I posted on Facebook. But we don’t use the noise directly by drawing it to the screen. The values are used to control other things such as the height of the world map or the boundaries of a forest. Anything that needs to look random with no noticeable pattern is a good choice for noise.
If you’d like to improve your coding skills, then browse the recommended books and resources at the Resources page. You can find all my favorite books and resources at this page to help you create better software designs.
Listen to the full episode for more details or read the full transcript below.
This episode explains how I started creating game worlds by hand and now plan to generate them in code instead.
When I started teaching programming, I knew that I needed to make it fun and interesting in order for you to get the most benefit. So I decided to use games. I taught the first few students how to build simple text-based games that we could build in just a few hours. By text-based, I mean a game that only needs text output to display and a keyboard for a player to type.
Something like Tic-Tac-Toe is a perfect example. The board can be drawn over several lines using dashes and vertical lines to draw the borders. And letters to show the occupied squares.
These were simple and allowed students to focus on the language and what it means to program. I still use these types of games in my classes. But now, I do have something a little more exciting and that’s a racing game. It still uses simple text such as dots for the outline of the race track and the letter V for the race car. The idea is to move the car left or right to stay on the road as the dots scroll by to make it look like the car is moving.
But I know you want more than this.
So I started building a two dimensional or 2D side scroller game that uses graphics. It has a character that animates so it looks like it’s walking, running and jumping. When it jumps, it waves its arms to keep balance. A side scroller game lets you move the character left or right and the background shifts to make it seem like the character is moving. The character can also jump onto floating platforms or fall into pits where the game ends.
I decided to use a 2D game mainly to keep things simple so you could focus more on the programming instead of learning all the details of a full three dimensional or 3D game engine. It’s a bit old school but sure looks a lot better than a black text screen with some dots and a few letters.
A side scroller game like this needs to know where the ground is and where the floating platforms are and where the pits are. It needs a map. It’s a simple map because everything can be built using square tiles. There’s a tile for grass with a bit of dirt showing under the grass. Or maybe it could be a stone tile that looks like bricks. Or ice. The tiles can be anything as long as they’re square so they can be placed next to each other to build a ground for the player to walk on and jump onto.
The game usually has multiple levels that get harder. Each level is very wide and normally just as high as a single screen will show. It’s called a side-scroller because the maps is so wide that the whole level can’t be shown at once and needs to scroll left or right as the player walks or runs.
For a game like this, it’s possible to place the tiles by hand.
By that, I mean that you as the programmer can decide how big each level is and specify in the code or in some text file that the code reads that there should be a grass tile over here, another grass tile over there, a stone tile placed just above them, etc. You design each level by placing enough tiles until the level is filled up exactly the way you want it.
Building a game like this lets you craft unique experiences for each level. If there’s a special challenge you want the players to solve, then you can design the level with this in mind. It’s a lot of work and each level needs to be built one at a time. If you want a bigger game with more levels, then you need to build bigger and more levels.
What I found though was that even a 2D game introduced a lot of new concepts to new programmers. Concepts that distracted them from learning how to code. It wasn’t nearly as overwhelming as 3D but still was a bit too much for some students.
So I went back to text. But I wanted something more exciting than Tic-Tac-Toe. I decided to focus on building a top-down Rogue-style game. This is a game where you move your character around a game world and explore and fight monsters. The view is always from the top looking down. I figured that I could use the same idea of maybe dots for walls and letters for other things. The letter T could be used to show there’s a tree at some spot. Stuff like that.
Now all I needed was a way to place all the trees, walls, bushes, roads, rivers, bridges, etc. that would make up the game world. This type of game is more open.
So instead of individual levels, there’s a bigger world map.
By world, most games usually mean a small section of a world. And not a full globe.
Games like this also have an idea of zooming out to get the full view of the whole world map or zooming in to see the details of what’s currently around the player.
Anyway, I thought about how I could achieve this for quite some time. Placing individual trees and other terrain over the whole map was too much for this type of game. I mean, it could work. If you play some popular online or big game studio games that have a detailed world that never changes, then it was probably built by hand. Every house, tree, car, bridge, etc. was put in a specific spot for a reason. Somebody had to look at the map and say, “I think we need a delivery truck here. Oh, and let’s put the mailbox for this house right here.”
This was too much work for too little benefit for what I was trying to do. I needed something different.
One idea that I came up with was to start at the zoomed out level and create a map that would show forests and lakes and rivers and other large terrain features. Then I’d fill in the details as the player zoomed in. By randomly shifting from a forest to individual trees, this seemed like it might work.
But there were problems. The details started making the code harder to understand. What if the map needed to shift from a forest to a lake? I didn’t want random trees sticking up from the lake. But shifting from a forest to grassland was okay to have a few trees in the grass. And going from a forest to a marsh was okay to have dead trees in the water.
I started to look around to see how other programmers have solved this type of challenge. One of the creators that I found on Patreon has some YouTube videos on how to generate planets. This was exactly the type of thing I needed.
I started watching the videos and learned about something called noise.
The video just showed how to include some code and then use the noise to generate a planet. I took this a bit further and investigated exactly how the noise was generated. That’s probably a topic for another episode. For now, I’ll just describe how noise can help solve the problem of shifting from one terrain type to another.
The first thing is that this solution can be made entirely in code. There’s no need, unless you want to, to hand place anything. What noise gives you is a value based on coordinates you pas to it.
The value might be somewhere between 0 and 1. Or it could be between -1 and 1. It’s not hard to switch between these ranges. The important point is that you pass in coordinates based on the location in the map and get back a value. If you pass in two coordinates near each other, then you’ll get back two noise values that are also close to the same value. This means that as you slowly move through the map, then the noise value will slowly change.
There are no abrupt changes. This helps to mimic the way a landscape will have rolling hills that gradually go up and down. The noise values might shift gradually, but they do so in a random manner. So over larger distances, you can find the noise values to be very different. This mimics that way those rolling hills can turn into mountains in the distance.
Now that we have a noise value that shifts slowly, we can multiply it to make the change larger. It wouldn’t be much of a change even for mountains if the entire landscape only changed an inch or so up or down. So we need to multiply the noise to make it more noticeable.
Then we can start with a perfectly flat world and add the noise to that.
This will cause the world to shift up and down based on the amplified noise level. All we need to do is pick a certain level for sea level. This can be anything we want based on how much water we want in the world.
Anything below this water level will be cut off and replaced with a flat value again for the surface of the water. The same thing can be done for lakes.
Once we have the elevation of the land set and water levels figured out, we can use the height to determine the basic type of terrain that can exist. For example, we now have a way to set definite borders where trees can and cannot grow in and out of water. And trees don’t grow above a certain height. But this is a more gradual fading of the trees. Eventually the land gets too high in the mountains for trees to grow.
We can also setup zones on the land where we want forests or major grasslands.
The noise can help again to shift between the zones in a random and gradual manner.
This time, we’re not using noise for elevation but for changes between major terrain types. This can result in a thick forest slowly thinning to grassland in some places, or a more sudden shift to grassland in other places, or pockets of grass in the forest, or clusters of trees in the grass.
Noise is a perfect example of how you sometimes have to change your thinking about a problem and be open to radically different solutions. It’s also a good example of how you’ll get better results when you’re faced with difficult problems to stop and look around to see if maybe this is already a solved problem.
I’m not saying that you always have to write your code the same way everybody else does. Going your own way can sometimes lead to an interesting new solution that nobody has thought of yet. And using a well established solution is the reason all cars have round wheels.