RogueSharp V3 Tutorial – Simple Room Generation

Next Tutorial Post – Connecting Rooms
Previous Tutorial Post – Player Input


During this tutorial we’ll handle adding rooms to our map. We’ll save connecting the rooms via hallways until the next tutorial.

Dungeon Map Rooms

The first thing we’ll need to do is create a place to hold our room information in DungeonMap.cs. Since all of our rooms are going to start out simple and be rectangular in nature we’ll simple use the Rectangle class included with RogueSharp to represent a room.

Some of you might ask why Rectangle in RogueSharp is a class and not a struct like in many other libraries. The answer is that it’s a mistake on my part. It really should be a struct. Here is an article on MSDN explaining the difference and when to use one over the other.

Choosing Between Class and Struct:

Thanks to James Neal for pointing this out and for submitting a pull request to fix it. For our purposes it will work just fine as a class. On to creating our rooms! Add the following code to DungeonMap.cs

public class DungeonMap : Map
  // ... start of new code
  public List<Rectangle> Rooms;

  public DungeonMap()
    // Initialize the list of rooms when we create a new DungeonMap
    Rooms = new List<Rectangle>();
  // ... old code continues here

Random Number Generator Singleton

Since our levels will be randomly generated it will be nice to have easy access to a random number generator. By using the same random number generator that was created with a known seed we can always regenerate a level exactly as it was generated before by using the same seed. Open Game.cs and add the following code:

// Singleton of IRandom used throughout the game when generating random numbers
public static IRandom Random { get; private set; }

public static void Main()
  // Establish the seed for the random number generator from the current time
  int seed = (int) DateTime.UtcNow.Ticks;
  Random = new DotNetRandom( seed );

  // The title will appear at the top of the console window 
  // also include the seed used to generate the level
  string consoleTitle = $"RougeSharp V3 Tutorial - Level 1 - Seed {seed}";
  // .. old code continues here

RogueSharp has several different random number generators that you can read about here –

For our purposes we’ll use DotNetRandom which uses the standard RNG included with .NET. To establish a unique seed each time we start a new game we’ll get the Ticks (The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001) of the current time. We’re also writing this seed into the title so that we could generate the level again in the future which could be useful for testing or debugging.

Generating Rooms with MapGenerator.cs

If you remember previously we generated our map by only making the outside edges walls, and the entire rest of the map wide open floors. Because we are changing this completely I’m going to paste the entire source code for the new MapGenerator.cs below and then I’ll review the changes.

public class MapGenerator
  private readonly int _width;
  private readonly int _height;
  private readonly int _maxRooms;
  private readonly int _roomMaxSize;
  private readonly int _roomMinSize;

  private readonly DungeonMap _map;

  // Constructing a new MapGenerator requires the dimensions of the maps it will create
  // as well as the sizes and maximum number of rooms
  public MapGenerator( int width, int height, 
  int maxRooms, int roomMaxSize, int roomMinSize )
    _width = width;
    _height = height;
    _maxRooms = maxRooms;
    _roomMaxSize = roomMaxSize;
    _roomMinSize = roomMinSize;
    _map = new DungeonMap();

  // Generate a new map that places rooms randomly
  public DungeonMap CreateMap()
    // Set the properties of all cells to false
    _map.Initialize( _width, _height );

    // Try to place as many rooms as the specified maxRooms
    // Note: Only using decrementing loop because of WordPress formatting
    for ( int r = _maxRooms; r > 0; r-- )
      // Determine the size and position of the room randomly
      int roomWidth = Game.Random.Next( _roomMinSize, _roomMaxSize );
      int roomHeight = Game.Random.Next( _roomMinSize, _roomMaxSize );
      int roomXPosition = Game.Random.Next( 0, _width - roomWidth - 1 );
      int roomYPosition = Game.Random.Next( 0, _height - roomHeight - 1 );

      // All of our rooms can be represented as Rectangles
      var newRoom = new Rectangle( roomXPosition, roomYPosition, 
        roomWidth, roomHeight );

      // Check to see if the room rectangle intersects with any other rooms
      bool newRoomIntersects = _map.Rooms.Any( room => newRoom.Intersects( room ) );

      // As long as it doesn't intersect add it to the list of rooms
      if ( !newRoomIntersects )
        _map.Rooms.Add( newRoom );
    // Iterate through each room that we wanted placed 
    // call CreateRoom to make it
    foreach ( Rectangle room in _map.Rooms )
      CreateRoom( room );

    return _map;

  // Given a rectangular area on the map
  // set the cell properties for that area to true
  private void CreateRoom( Rectangle room )
    for ( int x = room.Left + 1; x < room.Right; x++ )
      for ( int y = room.Top + 1; y < room.Bottom; y++ )
        _map.SetCellProperties( x, y, true, true, true );

You’ll notice that we added 3 new parameters to the MapGenerator constructor. The new parameters are maxRooms, roomMaxSize, and roomMinSize. The way this algorithm works is it will try to create a number of rooms up to maxRooms on the map. Each room it will try to place in a random position on the map. It will also choose a width and height for the room between roomMinSize and roomMaxSize. The final step when placing the room is to see if it overlaps with any other room. If it does overlap then we throw it out.

Hooking up the MapGenerator

Technically the MapGenerator is already used in Game.cs however if you tried to build you would get errors. We need to make sure we provide the new parameters that our MapGenerator requires. In Game.cs update the following line:

// Old code to change
MapGenerator mapGenerator = new MapGenerator( _mapWidth, _mapHeight );

// New code to replace with
MapGenerator mapGenerator = new MapGenerator( _mapWidth, _mapHeight, 20, 13, 7 );

We’ll attempt to create 20 rooms with sides that are between 7 and 13 cells long. The result should be less than 20 rooms as we throw out any that overlap.


If you run the program now and you are lucky you’ll end up with the Rogue in a room and will be able to move around in that room. Unfortunately since the rooms are not connected you will not be able to leave the room.


When Lucky

If you’re not so lucky you’ll end up with your poor Rogue being stuck in a wall outside of the room.


Unlucky – Outside of Room Bug

We’ll fix this issue in the next tutorial post where we’ll also get all of our rooms connected. If you are bored waiting for the next tutorial you should try and see if you can come up with a fix for this and also start experimenting with ways to connect the rooms.

The code for the tutorial series so far can be found on Bitbucket:


8 thoughts on “RogueSharp V3 Tutorial – Simple Room Generation

  1. Pingback: RogueSharp V3 Tutorial – Player Input | Creating a Roguelike Game in C#

  2. Pingback: RogueSharp V3 Tutorial – Connecting Rooms with Hallways | Creating a Roguelike Game in C#

  3. D1versity

    Now i actually have a problem. Visual does not recognize IRandom as anything other than a variable without context, heres my code:

    namespace Actual_Roguelike
    public class Game
    public static CommandSystem CommandSystem { get; private set; }

    public static Player Player
    get; private set;

    public static DungeonMap DungeonMap
    get; private set;

    public static IRandom Random { get; private set; }

    private static bool _renderRequired = true;

    // The screen height and width are in number of tiles
    private static readonly int _screenWidth = 100;
    private static readonly int _screenHeight = 70;
    private static RLRootConsole _rootConsole;

    private static readonly int _mapWidth = 80;
    private static readonly int _mapHeight = 48;
    private static RLConsole _mapConsole;

    private static readonly int _messageWidth = 80;
    private static readonly int _messageHeight = 11;
    private static RLConsole _messageConsole;

    private static readonly int _statWidth = 20;
    private static readonly int _statHeight = 70;
    private static RLConsole _statConsole;

    private static readonly int _inventoryWidth = 80;
    private static readonly int _inventoryHeight = 11;
    private static RLConsole _inventoryConsole;

    public static void Main()
    int seed = (int)DateTime.UtcNow.Ticks;
    Random = new DotNetRandom(seed);
    Player = new Player();
    MapGenerator mapGenerator = new MapGenerator(_mapWidth, _mapHeight);
    DungeonMap = mapGenerator.CreateMap();
    CommandSystem = new CommandSystem();

    I also included the part where Random = new DotNetRandom(seed); because visual does not recognize DotNetRandom. what’s the issue?

    1. Faron Bracy Post author

      I apologize for the slow response.
      IRandom and DotNetRandom are both in the RogueSharp.Random namespace.
      In order to use them you’ll need to add `using RogueSharp.Random;`

      If it’s still not working for you, feel free to post your code to Github and I’ll take a look at it.

      1. NN

        Those “using” notes are killing me. So far on every lesson I have to dig into your build to see what was left out. I would suggest adding those notes to these posts. I know you must presume some preexisting knowledge of C# here, but I can’t imagine I’m the only one having this issue.

        On MapGenerator:

        bool newRoomIntersects = _map.Rooms.Any(room => newRoom.Intersects(room));

        CS1061 ‘List’ does not contain a definition for ‘Any’ and no accessible extension method ‘Any’ accepting a first argument of type ‘List’ could be found (are you missing a using directive or an assembly reference?)

        Solution was to add “using Systsem.Linq;” to the beginning.

  4. No

    It’s saying “The name DateTime does not exist in the current context.” and “The variable didPlayerAct is assigned but its value is never used.”

    1. Faron Bracy Post author

      `DateTime` is from the System namespace. Try adding `using System;` at the top of your code. The `didPlayerAct` variable is not part of the code for this section. At the bottom of each part of the tutorial I have a direct link to the source code. Check it out here for this part: Compare what you have to the original to see what might have been missed.

  5. No

    It’s giving this error whenever I try to launch the game and refusing to run.
    Message=Object reference not set to an instance of an object.
    at Pipis.Systems.MapGenerator.CreateMap() in C:\Code\Pipis\Systems\MapGenerator.cs:line 33


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.