Roguelike Game in C++17

Dungeon Generation

The player can move around, and there are few rooms. But at this time nothing connects the rooms, so player cannot go from one room to another. Additionally, room generation is very static, it's the same everytime; and that's boring.

Goals

So let's fix both these issues.

  • Simple rooms generator
  • Connect all the generated rooms

For this round, neither of these two goals will use a complex algorithm. Idea is to get it to be random enough that it feels different. But is simple to implement and understand.

Brief detour into Refactoing lands

As is always the case, one can never be satisfied with how things are. So things must change. For this cycle, we want to do two things:

  • Change game_map structure so that it has list of rooms.
  • Ensure that player always starts in one of these rooms.

All the changes in this refactor are in service of these two items. I've added room structure, and game_map structure has an array of these rooms. Additionally, I am changing the tile structure, such that it now has two data members and two function members; and everything that use tile was updated to use new members. And lastly, renamed map_size to dimension, since game_map has dimension, and room has dimension. They can use the same type. The way we ensure that player always starts in one of the rooms, we get 1st room from game_map and put the player in centre of that room.

Simple rooms generator

We start by adding two member functions to room, center and intersects, first just returns centre of the room, while second tells you if this room intersects another room.

Most of the changes for this section, will be modifying game_map.cpp file. We will also be using vcpkg to get a library to help with iterating over arrays. The library in question is called CppIterTools, there are many librarys for C++ that do similar things as this library. e.g. NanoRanges, Easy Iterator, Range-V3, etc. You could achieve the same with any of them. You can download the library using following command.

vcpkg install cppitertools

And because it's a header only library, we don't have to change anything in CMakeLists to make use of it. vcpkg automagic!!!.

We start by changing generate_map function, first we change how tiles array is populated. Previously, we populated the tiles member with default wall type of ground, now we make it a wall. Using the CppIterTools the code is much more readable, and simpler to write.

The idea is each room we make will change the tile type from being wall to ground. Continuing on, our rooms array will be generated by make_rooms function. This function will take in size of our map, as well as tiles on the map.

Now I could have written make_rooms function in many different ways. However, I've choosen to compartmentalize each sub-process used to make rooms into their own lambda function. So there are two lambda functions within make_rooms function. change_tiles which will given a room structure change the tiles array to ground type for that part of the map array. make_random_room simply generates a randomly sized room, keep it constrained with in map size and room size. Randomization is generated using C++'s <random> header.

Then taking make_random_room lambda functions, make a random room, check if it intersects with any other room already in the array, if it intersects we reject that random room and generate a new one. If the room does not intersect then we add it to the list of rooms. The intersection test against rooms array is done using C++'s find_if algorithm function.

After I have list of rooms, I loop through them and call change_tiles to make sure room is visually and structurally represented. And we return to our generate_map function.

There are also few file local variables defined to constrain the size of rooms, and how many rooms we want per map generation.

And that's our "Simple Rooms Generator". There are many better algorithms out there. This one is very much dependent on just simple random number generator. No smarts required/applied.

Part-3a.png

GitHub Repo

Connecting all the rooms

Having a billion rooms you can't get to is not fun. A game must be fun. So, next up, connect_rooms function. Similar to make_rooms, we have few lambda functions that do the various sub tasks involved in connecting two rooms.

Similar to make_rooms's change_tiles lambda, here we have make_hallway lambda, which changes 1 tile to tunnel type, if tile is not already ground. I know naming is inconsistent. Might fix that in future. For rest of the this article assume hallway and tunnel are used interchangably.

Next we have two lambda that do same effective job, one makes vertical tunnels/hallways other makes horizontal tunnels/hallways. All the connections between rooms will have a 90 degree turn, if required.

Lastly we loop through all the rooms, and pass to previously mentioned lambdas, there is a random number generator here, to determine which room is primary. Notice we change the flip value between horizontal and vertical hallway calls. This is to ensure, that we don't start both tunnels at primary room.

Having done all this, we now have a series of rooms, we can walk around in. We can control how many rooms there are on a map, how big or small they can be. Amount of code is not all that much. Just organizing it makes a lot of difference.

Part-3b.png

Links

GitHub Repo ╠═══
Home ╠═══
╣ Prev: The entity and the map ╠═══
╣ Next: Player's field of view ╠═══

Author: Neel Raiyani [Roy Fokker]

Created: 2019-10-26 Sat 19:45

Validate