Herbert Wolverson - Procedural Map Generation Techniques

Roguelike Celebration
15 Oct 202027:28

Summary

TLDRHerbert Wolverson's talk, 'Procedural Map Generation Techniques,' explores the art of creating dynamic game maps using algorithms. He discusses various methods, from simple room placement to advanced techniques like Cellular Automata and Voronoi Diagrams, emphasizing the importance of guiding randomness for unique, usable maps. Wolverson also highlights the utility of combining algorithms and refining maps with tools like Dijkstra maps to ensure accessibility and narrative coherence, offering a comprehensive guide for game developers interested in procedural generation.

Takeaways

  • ๐ŸŽฎ Herbert Wolverson is a hobby game developer since the 1990s, known for Nox Futura and One Night in the Dungeon.
  • ๐Ÿ“š Herbert wrote a book on Rust roguelike game development and is writing another on learning Rust through making games.
  • ๐Ÿ—บ๏ธ The talk is about Procedural Map Generation Techniques, focusing on using algorithms to create and refine maps.
  • ๐ŸŽฒ Procedural generation ensures each playthrough is unique, as seen in games like Rogue and Dwarf Fortress.
  • ๐Ÿงฉ Simple room placement involves generating random rectangles and connecting them with corridors.
  • ๐Ÿ”€ Binary Space Partition (BSP) divides the map into halves repeatedly to create well-spaced rooms.
  • ๐ŸŒฟ Cellular Automata transforms a random initial state into natural-looking structures through iteration.
  • ๐Ÿšถโ€โ™‚๏ธ Drunkard's Walk simulates a character carving out paths randomly to create contiguous maps.
  • ๐Ÿ’ง Diffusion Limited Aggregation (DLA) uses particles to create winding, contiguous maps.
  • ๐Ÿ“ Voronoi Diagrams create regions based on proximity to seed points, useful for structured map generation.
  • ๐ŸŒ Perlin/Simplex Noise generates smooth, continuous gradients for realistic overworld maps.
  • ๐Ÿ”„ Combining multiple techniques and prefabs can produce more interesting and varied maps.
  • ๐Ÿ“Š Dijkstra maps help in identifying unreachable areas and ensuring logical placement of start and end points.
  • ๐Ÿ”ฅ The 'Hot Path' technique refines maps by focusing on the main path from start to end points.
  • ๐Ÿ› ๏ธ Prefabs add human-designed elements to procedurally generated maps, enhancing gameplay.

Q & A

  • Who is Herbert Wolverson?

    -Herbert Wolverson is a hobby game developer since the 1990s, the developer of Nox Futura, One Night in the Dungeon, and several 7DRLs. He has written a book on Rust roguelike game development and is working on another book about learning Rust through making games.

  • What is the topic of Herbert Wolverson's talk?

    -The topic of Herbert Wolverson's talk is 'Procedural Map Generation Techniques.'

  • What is the importance of procedural map generation in games like Rogue and Dwarf Fortress?

    -Procedural map generation in games like Rogue and Dwarf Fortress is important because it creates a different map every time a new game starts, ensuring that players have a unique experience in each playthrough, enhancing replayability.

  • What is the basic principle of Binary Space Partition (BSP) rooms?

    -Binary Space Partition (BSP) involves dividing the map into halves, then further dividing those halves, continuing until spaces of the desired room size are achieved. This technique ensures better spaced-out rooms and is used in games like Nethack.

  • How does the Cellular Automata algorithm work in map generation?

    -The Cellular Automata algorithm starts with a completely random map of walls and floors. It iterates over each tile, counting neighbors to determine whether a tile becomes a wall or a floor, creating natural-looking structures from chaos.

  • What is the Drunkard's Walk algorithm?

    -The Drunkard's Walk algorithm involves a randomly moving 'drunk' character that carves out a map by smashing through walls as it staggers around, creating a contiguous map that often looks like it was carved out by water.

  • What is a Voronoi Diagram and how is it used in map generation?

    -A Voronoi Diagram is created by placing seeds on the map and assigning each point to the nearest seed, forming regions. This technique can be used to create alien cell structures, spawn monsters in groups, or generate city layouts.

  • How can Perlin/Simplex Noise be used in procedural map generation?

    -Perlin/Simplex Noise can generate smooth gradients for terrain, such as mountains and valleys. By combining multiple noise layers, it can create detailed and natural-looking landscapes.

  • What is a Dijkstra map and how is it useful in procedural generation?

    -A Dijkstra map starts from one or more points and assigns a distance value to each tile based on how many steps it is from the starting point. It helps identify reachable areas, place starting points and exits, and refine map paths.

  • What is the 'Hot Path' technique in map refinement?

    -The 'Hot Path' technique involves generating a path between the start and end points of a map, creating a Dijkstra map from this path, and using the values to highlight important areas. This helps in organizing the map's progression and storytelling.

Outlines

00:00

๐ŸŽค Introduction of Herbert Wolverson

Noah introduces Herbert Wolverson, a seasoned hobby game developer since the 1990s, known for his works like Nox Futura and One Night in the Dungeon. Herbert authored a book on Rust roguelike game development and is working on another about learning Rust through making games. The talk titled 'Procedural Map Generation Techniques' excites Noah, as it is a topic he has long been interested in.

05:04

๐ŸŒ Overview of Procedural Map Generation

Herbert introduces himself and the topic of procedural map generation, highlighting his background and involvement in the roguelike community. He mentions his activity on social media, his upcoming book, and the source code for his talk available on GitHub. The importance of procedural generation in games is underscored by referencing Rogue (1980) and Dwarf Fortress, which utilize procedural generation to create unique, replayable experiences.

10:06

๐Ÿ— Basic Procedural Map Generation Techniques

Herbert describes simple room placement, an introductory algorithm for roguelike development. He explains the binary space partition (BSP) technique, which ensures better spacing and is used in games like Nethack. He also introduces Cellular Automata, which transforms random maps into ordered structures, and Drunkard's Walk, where randomly moving entities create contiguous maps resembling natural formations.

15:09

๐Ÿ”„ Advanced Procedural Techniques: DLA and Voronoi

The discussion moves to Diffusion Limited Aggregation (DLA), which generates winding, contiguous maps. Herbert describes using Central Attractor to focus map generation towards a central point. Voronoi Diagrams, another technique, are explained for generating diverse structures by dividing maps into cells based on proximity to random or deliberate seeds. Customizing Voronoi diagrams can yield various practical applications, such as city generation or monster spawning.

20:10

๐Ÿ“‰ Perlin/Simplex Noise and Combined Techniques

Herbert explains Perlin and Simplex noise, commonly used for creating overworld maps by generating smooth gradients. He suggests combining noise layers to add detail and randomness. Combining multiple map generation techniques, like BSP and Cellular Automata, can create more interesting and story-driven maps. The use of prefabs (pre-designed elements) can introduce human-designed features into random maps.

25:10

๐Ÿ—บ Dijkstra Maps and Final Tips

Herbert introduces Dijkstra maps, essential for refining generated maps by identifying accessible areas. These maps can help place starting points, determine optimal routes, and identify unreachable areas. Techniques like the 'Hot Path' refine map progression, and Dijkstra maps ensure logical placements for game elements. Herbert wraps up with a nod to his resources and availability for questions, hinting at more advanced topics like Wave Form Collapse.

Mindmap

Keywords

๐Ÿ’กProcedural Map Generation

Procedural map generation is the use of algorithms to create maps automatically rather than manually. It relates to the video's theme as the entire talk by Herbert Wolverson focuses on different techniques to achieve this in game development. For example, Wolverson discusses using algorithms like BSP and Cellular Automata to generate game maps that are varied and replayable.

๐Ÿ’กBinary Space Partitioning (BSP)

BSP is an algorithm that divides a space into two halves repeatedly to create a map. This technique ensures rooms are well-spaced and does not overlap. In the video, Herbert explains how BSP can be used in games like Nethack to create dungeon layouts by dividing the map vertically or horizontally and then further subdividing those sections.

๐Ÿ’กCellular Automata

Cellular Automata is a technique that uses a grid of cells that evolve based on a set of rules, leading to natural-looking structures. Herbert describes this method as starting with a random map that is iteratively refined to form a usable game map, giving the example of how random soup can turn into coherent cavern systems.

๐Ÿ’กDijkstra Maps

Dijkstra maps are used to calculate the shortest path from a starting point to various destinations on a map. Herbert emphasizes their utility in ensuring that generated maps are fully navigable and highlights their role in refining maps, such as removing unreachable areas or optimizing player routes.

๐Ÿ’กPerlin Noise

Perlin Noise is a gradient noise function used to generate natural-looking textures and terrains. Herbert explains that Perlin Noise is deterministic and smooth, making it useful for creating realistic overworld maps by translating noise values into terrain features like water, land, and mountains.

๐Ÿ’กDiffusion Limited Aggregation (DLA)

DLA is a process where particles move randomly until they stick to a cluster, forming natural, branching patterns. In the video, this technique is illustrated as a way to generate winding, interconnected maps, which can be ideal for creating intricate cave systems in games.

๐Ÿ’กPrefabs

Prefabs are pre-designed sections of a game map that can be inserted into procedurally generated environments. Herbert highlights the use of prefabs to add human-designed elements, like traps or treasure rooms, into a largely random map to enhance gameplay and narrative coherence.

๐Ÿ’กDrunkardโ€™s Walk

Drunkardโ€™s Walk is a simple algorithm where a point moves randomly, carving out paths in a solid map. Herbert describes how this method ensures the generated map is contiguous and can be used to simulate natural cave formation, as it guarantees all areas are accessible.

๐Ÿ’กVoronoi Diagrams

Voronoi Diagrams partition a space based on distance to a set of points, creating a tessellation of regions. Herbert explains how these diagrams can be used in game development for city generation or to ensure that related game elements, like groups of enemies, are placed within the same regions.

๐Ÿ’กWave Function Collapse

Wave Function Collapse is a complex algorithm used to generate patterns based on constraints, often seen in voxel-based city generation. Although Herbert does not delve deeply into it, he acknowledges its effectiveness in creating detailed and structured vertical and horizontal maps.

Highlights

Herbert Wolverson's talk on 'Procedural Map Generation Techniques' offers insights into creating and refining game maps algorithmically.

Wolverson is a veteran hobby game developer since the 1990s, known for games like Nox Futura and One Night in the Dungeon.

He authored a book on Rust roguelike game development and is currently writing another on learning Rust through game creation.

The talk introduces various algorithms for map generation, emphasizing their use in creating usable and varied game environments.

Rogue, the 1980 game, is credited with pioneering procedural generation, influencing the genre's replayability and uniqueness.

Dwarf Fortress is highlighted for its extensive use of procedural generation, creating detailed and immersive worlds.

Simple room placement and Binary Space Partition (BSP) are introduced as foundational algorithms for map generation.

Cellular Automata is praised for generating natural-looking maps from complete randomness, useful for creating organic environments.

The Drunkard's Walk algorithm is described for creating contiguous, cave-like maps through random path carving.

Diffusion Limited Aggregation is recommended for generating winding, open maps, ensuring contiguity in map design.

Voronoi Diagrams are presented as versatile tools for creating structured or random map elements, like city layouts or alien cell structures.

Perlin/Simplex Noise is discussed for its widespread use in generating smooth, continuous maps for overworlds and terrain.

Combining multiple procedural generation techniques is encouraged to create maps with depth and narrative.

Prefabs are suggested as a way to inject human design elements into procedurally generated maps, adding uniqueness.

Dijkstra maps are introduced as a powerful tool for ensuring map accessibility and for placing strategic points like exits or locked doors.

The 'Hot Path' technique is explained for refining maps by focusing on the most direct path between points, enhancing game progression.

Herbert Wolverson's GitHub repository contains the source code related to the talk, providing practical examples of the discussed techniques.

The talk concludes with a Q&A session addressing questions on map diversity and generating vertical structures in map generation.

Transcripts

play00:00

Noah: Our next speaker is Herbert Wolverson.

play00:04

Herbert is a hobby game developer, and he has been since the 1990s.

play00:10

He developed Nox Futura, One Night in the Dungeon,

play00:14

and a bunch of 7DRLs. He also wrote a book

play00:18

about Rust roguelike game development, and he's currently writing another book

play00:26

about learning Rust through making games.

play00:29

This talk is called Procedural Map Generation Techniques,

play00:32

and this is acctually something I'm super excited about, as I've always

play00:36

wanted someone to give a talk about this topic.

play00:38

So without further ado, here's Herbert.

play00:41

Herbert: Hi. Welcome to Procedural Map Generation.

play00:45

I'm Herbert Wolverson of Bracket Productions,

play00:47

which is really just my consulting company.

play00:50

I'm gonna be talking to you about using algorithms to generate

play00:53

maps, and then using more algorithms to fix the maps you

play00:57

just created and find out if they're even usable.

play01:00

There's a lot of content to cover, so I'm gonna be going on

play01:03

at quite a rate of knots.

play01:05

So, who am I? As Noah just said, I'm the author

play01:08

of the Rust Roguelike Tutorial, on the address on the screen there.

play01:11

I talk way too much on Twitter @herberticus. If you ever want to

play01:15

get in touch with me, /u/thebracket on Reddit is the best way to find me.

play01:19

I love hanging out on the roguelike dev forums, answering short answer

play01:23

questions with SAS. I do have a book coming out very soon, Hands-on Rust:

play01:28

Effective Learning through 2D Game Development and Play,

play01:31

which will be out on PragProg.com.

play01:35

I promise I won't keep promoting that, but I really wanted to mention it,

play01:38

and all the sourcecode that goes with this talk can be found on GitHub

play01:41

at that address. That'll be repeated on the final slide of this presentation.

play01:48

So we're gonna give a quick shoutout to Rogue, from 1980,

play01:52

because we really wouldn't be here without it. It's one of the

play01:55

seminal and first uses of procedural generation that really defined

play01:59

the genre. It splats out up to nine rooms, connected randomly.

play02:03

It's been said that they did that because they needed to keep

play02:07

the game small and really couldn't fit in 50 beautifully hand-designed

play02:10

levels, but really that created one of the strengths of the genre

play02:14

in the first place. When you start a new game, you have a different

play02:18

map every time. So every time you play, instead of memorizing that

play02:22

I need to go up, up, up, right, you're learning instead that

play02:26

I should interact this way with different monsters, and interact

play02:29

this way with rooms, navigate like this, learning the system rather

play02:32

than learning the game itself, giving you effectively infinite replay.

play02:37

Also, any talk on procgen really has to mention Dwarf Fortress,

play02:40

because no other procgen game has ever managed to cram this

play02:43

much procedural generation into one binary.

play02:46

If you haven't played it, go out and do so.

play02:50

Support them on Steam, and tell them how awesome they are.

play02:54

They generate everything from a massive overworld with

play02:58

sweeping mountain ranges, dense forests, volcanoes,

play03:01

demon-infested fortresses, fill it up with procedurally-generated

play03:05

civilizations who either like or hate each other, and then

play03:08

you can drill all the way down to Urist and find out which

play03:11

proedurally-generated deity he worships, which procedurally-generated

play03:15

tavern he drinks in, and learn all about his quest to cross the land

play03:19

and find the perfect sock.

play03:22

At the mid-scale, you can zoom in to any particular land block on the map,

play03:25

find out that it is beautifully rendered, still matches the overall shape

play03:30

of the overall world above it, the trees gain foliage, lose foliage,

play03:34

depending on their type and the type spawns appropriate to the biome.

play03:38

In other words, there is pretty much every procgen technique that you

play03:41

can think of in this game. Hang out in the Bay 12 forums

play03:44

and that is a great place to learn about them.

play03:47

So one thing that's clear from both of these games is that,

play03:50

while they're random, their randomness doesn't define the game.

play03:53

The randomness is fed into an algorithm that generates something

play03:56

that approximates what you want to get, but ensures that it is different

play03:59

every time. So, we're gonna start looking at some algorithms

play04:03

for doing that.

play04:05

A simple room placement. If you've done any of the

play04:07

roguelike development tutorials, then you've seen this one.

play04:10

You start with a solid map. You pick a random rectangle.

play04:14

If there isn't a room already there, you fill in the rectangle.

play04:18

You keep adding rooms until you meet whatever criteria you've

play04:22

come up with for enough, and then you join the rooms

play04:24

together with corridors. Let's watch this in action.

play04:28

As you can see, it's placing rooms randomly. When you see the

play04:32

red rectangles with the exclamation marks, they tried to generate one

play04:35

that overlaps, so you have to discard it and try again.

play04:38

And then it joins them together with corridors. In this case, they went

play04:41

with a simple dog leg algorithm, that randomly switches between

play04:44

being either vertical first or horizontal first.

play04:47

That's pretty much exactly the algorithm from the Python

play04:50

roguelike dev tutorial that the roguelike dev subreddit recommends

play04:57

that you start with.

play04:59

So a good refinement of that is Binary Space Partition rooms, or BSP.

play05:04

Binary Space Partition is fancy developer talk for chopping in half.

play05:08

It gives a similar result to random room placement,

play05:12

but it pretty much guarantees that everything is better spaced out.

play05:15

You'll find that it's used in Nethack, amongst other games.

play05:18

So to do BSP, you divide your map in half, and you randomly decide

play05:23

whether you want to divide vertically or horizontally, and divide that half in half.

play05:28

Then you keep dividing your halves all the way down until you have

play05:31

a space that's roughly the right size you want to use for a room.

play05:35

And I personally like to then add a gutter of one tile around it,

play05:38

to ensure that you don't get rooms joining together, unless that's

play05:41

what you want. So watching that in action,

play05:43

you see that there's absolutely no rejections, the rooms are nicely

play05:47

spaced out, and you wind up with a pretty usable map.

play05:51

So complete change of gear, Cellular Automata.

play05:56

I personally love this one, because it involves an ordered-looking

play06:00

natural map from complete chaos. You know, I said you don't always

play06:04

start with complete random? Well, this one, you do.

play06:07

You can literally make half your map walls half your map floors,

play06:12

randomly picked, no chance of getting through it,

play06:15

and you'll end up with something you can use.

play06:18

If you played Conway's Game of Life or seen articles about it,

play06:22

it's the same principle here. So once you've got your map,

play06:26

you make a copy of it, you iterate every tile that isn't

play06:30

on the edge, and you count the number of neighbors, including diagonals.

play06:33

If there are no neighbors, then it becomes a wall. If there's one to

play06:40

four neighbors, it becomes empty. Five or more neighbors, it becomes

play06:43

a wall. Now, you can and should tweak these rules to suit your game.

play06:48

Let's watch this in action. Completely random soup quickly turns into a

play06:52

far more natural looking structure that can actually be turned into a

play06:58

pretty useful map. And it's a really simple algorithm, really fast,

play07:03

and given the same seed, you get the same result every time.

play07:07

Next one to talk about is Drunkard's Walk. This is another popular one for beginners.

play07:11

So the basic principle of Drunkard's Walk is that you start with a solid map, find one

play07:17

Umber Hulk, and ply it with beer until he's staggering randomly.

play07:21

Place him somewhere on the map. As he staggers, he randomly smashes

play07:24

through walls, and carving out a map. Don't bother worrying about whether

play07:28

he backtracks. Let him stagger wherever he wants. Pick a maximum distance for him

play07:34

to travel, or her. I'm really not sure how Umber Hulk's gender works.

play07:38

If they travel too far, they pass out, and you can pick another

play07:42

Umber Hulk, spawn them somewhere within the open map, and let them smash.

play07:47

Then you stop spawning Hulks when enough of your map is open.

play07:51

In this case, I've used one-third of the map.

play07:53

So watching this in action, you can see that each Hulk is staggering

play07:57

completely randomly, carving out more and more of the map.

play08:00

One big advantage of this is that you can guarantee that your map will

play08:04

be contiguous. It won't generate any areas that your player

play08:08

can't reach. It tends to give you maps that looks like it was

play08:11

carved out by water, ideal for creating limestone caverns and similar.

play08:17

Another algorithm, Diffusion Limited Aggregation.

play08:20

I highly recommend the RogueBasin article on this one.

play08:23

So for the simple version of this, you start by digging out a small

play08:26

target seed, and then you pick a random point anywhere on the map, a random

play08:31

direction, and shoot a particle. If you're really lucky, the particle

play08:34

will hit one of the already open areas. If it doesn't, you keep shooting until it

play08:38

hits something. Something I've heard from a lot of military friends.

play08:43

In the event that you do hit a target area, then you carve out the last solid

play08:48

area that you passed through. This tends to give you a very winding,

play08:52

open map. Again, it's guaranteed to be contiguous.

play08:56

And there's a lot of ways that you can tweak the algorithm to make something

play08:59

more interesting.

play09:01

So the Central Attractor is much more likely to always hit the target.

play09:05

You randomly spawn your starting point and then shoot the particle directly

play09:09

at the middle of the map. This pretty much ensures that you

play09:12

get an open space in the middle, ideal, for example, for you to put

play09:15

a dragon with his hoard, and then a more interesting pattern forming

play09:19

around the edges, which could be where the hobbit would lurk while he

play09:23

torments the poor dragon. On the right, you can see what happens if we

play09:28

use the same Central Attractor algorithm, but simply apply

play09:31

a symmetry down the vertical. You start to get maps that look

play09:35

a lot like they either want to eat you, or maybe it's a butterfly,

play09:38

maybe it's a Space Invaders character.

play09:43

I recommend using this one sparingly, but a bit of symmetry like that can be

play09:47

applied to any algorithm when you want to produce something

play09:50

that looks a lot less random.

play09:54

Another algorithm that everyone should have in their toolkit is the

play09:59

Voronoi Diagram.

play10:01

So to make one of these, I do recommend Googling it.

play10:05

You randomly or deliberately place seeds all over your map.

play10:09

You randomly place them if you just want to produce something random.

play10:14

If you place them very deliberately - for example, you can equally space

play10:17

them all over the map - you can produce something that looks

play10:20

very, very much like a beehive.

play10:24

And then you iterate every point on the map, and it joins the

play10:29

area belonging to the closest seed. There are various fancy algorithms,

play10:35

like Delaunay triangulations, to do this quickly. In the source code I've

play10:39

provided, I just brute forced it and did it the hard way.

play10:43

Now, one neat trick for customizing what you get is that you can

play10:48

use a different distance algorithm to determine which group

play10:53

every tile joins. So on the left, I've used Pythagoras, and it gives you

play10:58

relatively smooth edges. Using Manhattan distance, which is the same distance

play11:05

that you get if you ask a New York taxi driver how far it is to get to

play11:10

somewhere, a number of blocks north plus number of blocks east,

play11:13

it gives you a much more manmade-looking, sharp-edged structure. And Chebychev

play11:19

is a similar distance algorithm, and tends to give you somewhere in between

play11:23

the two. So what do you do with Voronoi diagrams? Well,

play11:29

the first thing you can do with them is find the edges, place walls there,

play11:35

and wind up with an alien cell structure. Another good thing to do is

play11:41

decide that when you're spawning monsters, you'll spawn the monsters together

play11:45

within a Voronoi cell.

play11:47

So, for example, you've decided that the orc king should always be

play11:51

seated with his retinue. Then, you should probably spawn them

play11:54

in the same cell together, if possible. Likewise, if you decided that orcs

play11:58

must never, in fact, be near dark elves, make sure that you spawn them in

play12:02

far away cells. You can also use this for very effective city generation.

play12:07

In my PROCJAM game, Apocalypse Taxi, I used the edges of Voronoi cells to

play12:14

determine where the roads went, and then randomly populated the content of each

play12:19

cell with something like heavy industrial city, light industrial, and it worked pretty well.

play12:25

Combined with other techniques, this can be extremely useful.

play12:29

The next one up is Perlin/Simplex Noise, which is used all over the place,

play12:34

more than you might think.

play12:37

So Perlin/Simplex Noise are basically a bunch of gradients combined together

play12:42

with a few variables we'll talk about in a moment.

play12:46

You can generate it in either two or three dimensions. If you look in X/Y value,

play12:51

it gives you a number between -1 and 1.

play12:56

And the nice thing is, if you look at an adjacent one, it will be smoothly

play13:00

moving either up or down, relative to the neighboring squares.

play13:06

It's also continuous, so if you decide to look from X 1 through 2,

play13:12

and then decide to zoom in to 1.5 through 2, you'll actually get

play13:16

exactly the same shape as you saw on the right-hand side in the first one.

play13:20

So what do the variables mean? Now, the number of octaves

play13:23

give how many different gradients it's mixing in. Gain is how long the various

play13:27

gradients last. Lacunarity adds in randomness, and as you can see,

play13:34

from the picture on the right-hand side, which I guess is my left, this starts

play13:40

to feather it in and make it look a lot more random.

play13:43

Now, frequency is how frequently each of the various octaves

play13:47

peaks. So, what I recommend you do is find a Perlin/Simplex Noise tool

play13:53

and simply play with these values until you get something that you like.

play13:56

So what can you do with them? The answer is actually quite a lot.

play13:59

The most common use is to make an overworld. Because Perlin

play14:05

is deterministic by random seed, every time you use the same seed,

play14:09

you get the same map. Now, what I've done here is

play14:12

altitudes from -1 to 0 blued out as water, altitudes from 0 to .75

play14:19

are in green, shaded as terrain, altitudes above that are marked

play14:23

as mountains. And this is very common. You'll find this used in a lot of games.

play14:28

And as I mentioned, you can zoom in. So as you zoom in, you start to see more

play14:32

of the gradient. The problem is that the gradients are actually

play14:36

kind of dull.

play14:38

Now, you can fix that. The best way to fix that is to make a second layer

play14:41

of noise. So in this case, we've got a second layer of noise that is much more

play14:45

bumpy, has much more fine-grained detail, but looks terrible as

play14:49

a continent as a whole. And then as you zoom in,

play14:53

you change the percentage of each of the two gradients that you're

play14:56

mixing together. So when you're zoomed all the way out like that, you're seeing

play15:01

the relatively coherent overworld. As you start to zoom in, you see

play15:04

bays, peaks, valleys, troughs. And the great thing is, this is

play15:08

actually really easy to implement. There's a lot of really good

play15:11

Perlin/Simplex libraries out there. I highly recommend it.

play15:16

You can use it for anything from making a pirate game with cool seas

play15:20

to sail around, or just building the overworld for your map.

play15:23

You can also use it if you want to generate realistic-looking

play15:29

clouds, particles. You can even make wood grain with it, with the right values.

play15:34

And that brings me to one point that I can't emphasize enough.

play15:38

You very rarely need to use just one technique on a map.

play15:44

So here, on the top left, we've used WSP technique to produce a

play15:49

pretty linear-looking dwarven fortress. On the right, Cellular Automata

play15:54

has made a really open-looking sort of cavern system. It might

play15:59

be a dangerous underworld. So running with that theme,

play16:02

I simply took the left half of the dwarven fortress and the right half

play16:06

of the Cellular Automata, and you have what looks like a fortress

play16:11

that suddenly breaks out into a nasty underworld. Well, I thought,

play16:16

a better theme for that might be that the dwarves were digging, they

play16:20

came to the underworld, and they needed to protect themselves.

play16:23

So I added a prefab, a predesigned section in the middle, adding fortifications.

play16:28

And so, with two very simple techniques, you've produced a map that actually

play16:31

tells a story, rather than just being a bunch of random rooms.

play16:36

Another popular combination is take a map and then use DLA

play16:40

to fire particles at it, and blast parts of the map away.

play16:43

This starts to look like dwarves failed to pay their maintenance bill,

play16:46

or had a serious water problem, as the map becomes more and more

play16:52

organic-looking while keeping its basic structure.

play16:55

I mentioned prefabs before. Prefabs are a great idea.

play17:00

So you can make a massively random map, but if you start injecting

play17:05

human design elements into it, then you get the chance to really make the game

play17:08

your own.

play17:09

So I've got a prefab here that is definitely not a trap. It's death

play17:13

traps surrounding a treasure chest. You've probably seen that in a lot

play17:17

of console RPGs. You enter a room, you see a chest,

play17:20

with nothing guarding it. You can be pretty sure that

play17:22

something bad's about to happen to you.

play17:25

So the room structure makes it relatively easy to place a prefab. You can go

play17:30

through the room list, find a room that's bigger than the prefab, and you know

play17:34

the prefab fits there.

play17:36

On a map that doesn't have rooms, it can be a little more tricky.

play17:39

What I usually do is I pick random locations, look and see if the prefab

play17:42

will fit, and place them. If it won't, then I don't place it there.

play17:47

If I've got a nice, big list of prefabs, then I'll keep going until I've added

play17:52

a few of them and been careful not to add all of them, so the game is

play17:56

different next time I play.

play17:58

Very quick change of gears, because the next set of algorithms

play18:01

all are going to rely on this one, the Dijkstra maps.

play18:05

I highly recommend that you go to RogueBasin and read

play18:08

The Incredible Power of Dijkstra Maps on there. It is an excellent article.

play18:13

And Dijkstra maps are a very powerful tool if you're into making roguelikes.

play18:18

I recommend that you learn about them.

play18:21

To make them, you start with one or more starting points.

play18:25

In this case, the blue knight. The rest of the map gets marked to a sentinel

play18:29

value, meaning you can't go there. And then you look at all the tiles

play18:33

adjacent to your starting point. If you can walk into them, you put

play18:37

a 1 on them. You can get there in one step away from the starting point.

play18:42

Then you keep going. So every walkable tile that's next to a 1

play18:46

gets a 2, and a 3, and a 4, and a 5.

play18:49

Eventually, you have a complete map that tells you, first of all,

play18:54

the sentinel value means that you can't go there. So now, you've got

play19:06

a list of all the cells you can't use. Likewise, the numbered tiles tell

play19:11

you how far away you are from a starting point.

play19:16

So the first big use for this is when you've generated something like

play19:20

Cellular Automata, that can give you chunks of a map that you can't get to.

play19:23

Pick a central point, find one that's open, generate a

play19:27

Dijkstra map, and then all of the tiles that are open that have the

play19:32

sentinel value on your Dijkstra map can't be reached, and I've highlighted

play19:36

those in red on the map. You can delete those, because

play19:39

nobody can get there. Or, if you've got a game system

play19:42

that encourages tunneling, then go ahead and hide the stuff that needs

play19:46

to be reached with tunneling in those areas.

play19:50

This can also help you with placing a starting point on your map.

play19:53

Making sure that you cull the unreachable areas before

play19:59

you pick a starting point ensures that you won't place the player

play20:03

somewhere that they can't get out of, and it avoids the

play20:06

always embarassing case of the map that's only got two tiles

play20:09

that you can actually walk on.

play20:12

That has happened to me.

play20:14

So typically, to place a starting point, if I know that I want to be on the

play20:18

left, I'll place somewhere in the middle on the left, and then I'll

play20:21

simply look around for a neighboring tile that is open and hasn't been culled

play20:26

by the Dijkstra map.

play20:28

To find an endpoint, you can use the same thing, if you want

play20:30

to go left to right. A lot of games prefer to have more of a

play20:35

structured progression. Once you've culled the map,

play20:39

you know that anywhere on the map can be - that is still open after you've

play20:44

removed the areas you can't get to, it's safe to place an exit.

play20:48

So you find the rough area you want to put the exit and you place on a nearby

play20:54

open tile. I've gone ahead and marked the optimal route through that map.

play21:00

You can also, if you really dislike your player, use Dijkstra to find

play21:04

the least accessible part of the map and put the exit there.

play21:07

If they're starting in the middle, this is a really bad idea,

play21:10

because three-quarters of the map is basically irrelevant.

play21:16

However, if you want to hide something, this is a great way to do it.

play21:19

Find the starting point, then find the least accessible point on

play21:22

the map, hide something there, and you force the player to go on a

play21:25

treasure hunt, if they're gonna get the bonus item.

play21:29

That leads to one of my favorite techniques for refining a map,

play21:32

once you've generated it. I call it the "Hot Path."

play21:35

Once you've got your start point and your end point, you generate

play21:38

the path between the two. I use ASTAR. In this case,

play21:41

I think I used a Dijkstra map and just walked the distance between the two.

play21:47

Then you make another Dijkstra map, using all the points on the path as

play21:52

your hot path. Then, on that Dijkstra map, everything with a tile value of under,

play21:57

say ten, is the hot path and is close, but not necessarily directly

play22:03

on the best path through the dungeon.

play22:06

So what can you do with this? Well, if you prefer a less-branchy game,

play22:10

you can use it to remove the parts of the map that are completely irrelevant.

play22:14

If your game involves a great deal of progression from, say, left to right,

play22:20

this is a good way to do it, and a good way to not force the player

play22:24

to explore huge, winding labyrinths with no real purpose to them.

play22:29

If you're using a room-based generation, then this can be even more useful.

play22:34

I've marked in yellow the rooms that are on the hot path that go directly

play22:37

from point A to point B. Also, that means the grey

play22:40

rooms aren't really necessary. Or are they?

play22:43

Maybe the grey rooms could be culled, if you just want to have a go to room,

play22:48

go to room, go to room type of game. Or, the grey rooms could be where

play22:52

you hide bonus things. You might have the yellow rooms mark some breadcrumbs

play22:56

to give the player a clue as to where to go, and teach them by putting

play23:00

really scary things in the grey area that are off the beaten path

play23:04

and only to be done once you're a little more experienced.

play23:08

You can also use this knowledge to order the progression of the story.

play23:14

So you know that if the player's gonna go through this dungeon, they're

play23:18

probably gonna go through one to nine.

play23:22

And that's okay. If you're telling a story, let's say your grandfather

play23:27

tells you that it is your destiny to go out and save the world, he's probably

play23:32

going to want to tell you that somewhere around room one, so you can't avoid

play23:36

the old windbag. Somewhere around two, somebody should show up and

play23:39

tell you that your destiny is futile, you should abandon it,

play23:43

give up, and the whole adventuring thing isn't for you, and so on.

play23:49

Alternatively, you might have decided that you wanted to do the old

play23:52

saw of the locked door that has a key somewhere on the map.

play23:56

Supposing that you've decided that room five is gonna be where the locked

play24:01

door shall be, it would be a good choice because you can do a flood-fill and

play24:05

discover that there's nowhere else, there's no alternates to going through

play24:09

the exit from room five.

play24:11

So you place a locked door there, and now you absolutely know that the key

play24:15

has to be somewhere between rooms one and four, for this to be a

play24:19

solvable puzzle. It would really suck if you decided to spawn the key

play24:22

in room six, and leave yourself with a map that cannot be solved

play24:27

without finding some other way to open the door. You know, unless

play24:30

of course that's your point. And really, that is the point

play24:35

of what I've been trying to say, is guide your randomness

play24:38

and then use algorithms to check your randomness, to make sure that

play24:41

it matches what you want.

play24:44

I've written quite a bit about other algorithms on my

play24:46

roguelike tutorial, tried really hard to be language-agnostic, even though

play24:51

all the examples are in Rust. So, I do recommend checking there

play24:55

for a few more. I wanted to talk about Wave Form Collapse, and realized

play24:58

that I needed another 30 minutes.

play25:01

Alright, so like I said before, the source code for this talk is all up on my GitHub.

play25:06

That repost should have gone public a few minutes ago.

play25:10

And just to be a terrible shill one more time, my book

play25:14

Hands-on Rust: Effective Learning through 2D Game Development and Play

play25:18

will be in beta on PragProg relatively soon, next few weeks, as long as

play25:23

I get off my butt and finish editing it, and in your favorite bookstore

play25:27

pretty soon. If there's any questions, I'd be happy to take them.

play25:33

Noah: Wonderful. Thank you so much for that talk.

play25:35

Herbert: Thanks for having me. Noah: Yeah. We have a few questions.

play25:40

The first one is from Darren Gray, who asks, "How do you make

play25:44

generated maps not look very samey?" For example, he says that

play25:48

he can always notice when an overworld is generated with

play25:52

Perlin noise.

play25:55

Herbert: Yeah, that's actually a fun one, and I play spot the Perlin.

play25:58

One of the best things to do is to generate multiple noise maps

play26:03

and mix them together. So if you've decided that this region is mountains,

play26:07

start mixing in height values from another more mountainous-looking height map.

play26:17

That gets you something that is, as well as just going up,

play26:20

actually goes up and down, up and down, and starts to look more like

play26:22

mountains and less like a boring little gradient.

play26:25

You can also have a lot of fun generating your Perlin, and then

play26:29

run something like a Russian on it. Running a simpler

play26:32

Russian simluator, especially if you decide that some rocks are

play26:36

harder than others, gives you a beautiful map in no time.

play26:38

I think that's how World Machine works.

play26:42

Noah: Cool. Our next question is do you know any techniques for

play26:46

generating vertical structures, or Z levels in map generation?

play26:52

Herbert: That is something I am honestly terrible at.

play26:55

I've seen Wave Form Collapse used to make some absolutely

play26:58

amazing Voxel-based cities. I can't honestly pretend that I know how

play27:03

to do that.

play27:06

Noah: Cool. That looks like all of the questions that people have

play27:09

put in.

play27:12

But thank you so much, and then I'm sure if you hang out

play27:15

somewhere in the social space, people will come and ask you more questions.

play27:19

Herbert: Yes, I should be around there and on the Discord tonight.

play27:22

I'll be editing my book and alternating between the two. Thank you.

play27:26

Noah: Cool, thanks so much.

Rate This
โ˜…
โ˜…
โ˜…
โ˜…
โ˜…

5.0 / 5 (0 votes)

Related Tags
Game DevelopmentProcedural GenerationRoguelike TutorialAlgorithmsMap DesignCellular AutomataDijkstra MapsVoronoi DiagramsPerlin NoiseRust Programming