RogueSharp V3 Tutorial – Stairs

Next Tutorial Post – Not Available Yet
Previous Tutorial Post – Doors


The purpose of this tutorial is start placing stairs in our dungeon. We want to be able to proceed down stairs to get into deeper and more difficult levels.

  • Stairs can either go up or down
  • The symbol for stairs going down will be a greater than sign “>”
  • The symbol for stairs going up will be a less than sign “<“
  • Each dungeon level will have one up and one down staircase
  • Stairs going down can be descended by the player by pressing the ‘>’ or ‘.’ key
  • Once a player has gone down to the next level they cannot go back
  • Stairs going up are only used to indicate where the player came from
  • When a player goes down stairs a brand new level is generated

Creating the Stairs Class

To begin we need a new class to represent the stairs as we outlined in our goals above. The stairs class should inherit from IDrawable because we will want to draw it on the map console. Create a new file named Stairs.cs in the Core folder and place the following code in it.

public class Stairs : IDrawable
  public RLColor Color
    get; set;
  public char Symbol
    get; set;
  public int X
    get; set;
  public int Y
    get; set;
  public bool IsUp
    get; set;

  public void Draw( RLConsole console, IMap map )
    if ( !map.GetCell( X, Y ).IsExplored )

    Symbol = IsUp ? '<' : '>';

    if ( map.IsInFov( X, Y ) )
      Color = Colors.Player;
      Color = Colors.Floor;

    console.Set( X, Y, Color, null, Symbol );

Updating DungeonMap Class

Now that our Stairs class is created, we need to update DungeonMap.cs with a few changes to be able to use the Stairs. At the top of DungeonMap.cs add the following two properties for our StairsUp and StairsDown next to the existing Rooms and Doors properties.

public Stairs StairsUp { get; set; }
public Stairs StairsDown { get; set; }

Next update the DungeonMap constructor to call Clear() on the SchedulingSystem when a new DungeonMap is constructed. We do this because when we make a new level by going down stairs we want to make sure that all of the monsters from the previous level are removed from the schedule and do not continue to try to act.

public DungeonMap()

  // Previous code omitted...

Now we need a new method which will check to see if the player is standing on the stairs going down. Create a method called CanMoveDownToNextLevel() with the following code.

public bool CanMoveDownToNextLevel()
  Player player = Game.Player;
  return StairsDown.X == player.X && StairsDown.Y == player.Y;

In the Doors tutorial last time we forgot to update the Draw() method and had to have a blog reader point out the mistake. We’ll try not to make the same mistake this time. Update the Draw() method and add the following lines of code to draw the stairs.

// Add the following code after we finish drawing doors.
StairsUp.Draw( mapConsole, this );
StairsDown.Draw( mapConsole, this );

Updating the MapGenerator Class

The next class we need to update is MapGenerator. We need to make sure that when we generate new maps, stairs are created along with the rest of the dungeon features. Open MapGenerator.cs and create a new private method named CreateStairs().

private void CreateStairs()
  _map.StairsUp = new Stairs
    X = _map.Rooms.First().Center.X + 1,
    Y = _map.Rooms.First().Center.Y,
    IsUp = true
  _map.StairsDown = new Stairs
    X = _map.Rooms.Last().Center.X,
    Y = _map.Rooms.Last().Center.Y,
    IsUp = false

We are not doing anything too fancy to generate the stairs. We are creating the stairs up in the center of the first room that was generated. This is the same room that the player starts in and the player is also in the center of the room, so we’ll offset the X coordinate by 1 to put the stairs next to the player. The last room we generated gets stairs going down and again we place them in the center of the room.

Make sure to call the CreateStairs() method from the existing CreateMap() method right before calling PlacePlayer();

public DungeonMap CreateMap()
  // Previous code omitted...

  // Call right before calling PlacePlayer();

  // Previous code

Also we want to change the signature of the MapGenerator constructor and add an additional integer parameter called mapLevel.

public MapGenerator( int width, int height, int maxRooms, int roomMaxSize, int roomMinSize, int mapLevel )
  // Keep all existing code in the constructor

If you have any sort of static analysis on like FxCop it will complain about having an unused parameter in the method. We really shouldn’t add it until we are prepared to use it, but rest assured we will use it very soon.

Updating the Game Class

Open up Game.cs which will be the final class that we need to update. Start by adding a new private static int member variable in with the rest of the member variables at the top of the class.

private static int _mapLevel = 1;

Next change the line was setting the console title in the Main() method. Also add the _mapLevel parameter to line where we instantiate a new MapGenerator.

// Old code was...
// string consoleTitle = $"RougeSharp V3 Tutorial - Level 1 - Seed {seed}";

// New code is
string consoleTitle = $"RougeSharp V3 Tutorial - Level {_mapLevel} - Seed {seed}";

// Old code was...
// MapGenerator mapGenerator = new MapGenerator( _mapWidth, _mapHeight, 20, 13, 7 );

// New code is
MapGenerator mapGenerator = new MapGenerator( _mapWidth, _mapHeight, 20, 13, 7, _mapLevel );

Finally in the OnRootConsoleUpdate(…) method where we are checking to see which key was pressed ad the following else if onto the end of the if block.

else if ( keyPress.Key == RLKey.Period )
  if ( DungeonMap.CanMoveDownToNextLevel() )
    MapGenerator mapGenerator = new MapGenerator( _mapWidth, _mapHeight, 20, 13, 7, ++_mapLevel );
    DungeonMap = mapGenerator.CreateMap();
    MessageLog = new MessageLog();
    CommandSystem = new CommandSystem();
    _rootConsole.Title = $"RougeSharp RLNet Tutorial - Level {_mapLevel}";
    didPlayerAct = true;

This last bit of code just checks for the “>” or “.” key being pressed. It then calls into DungeonMap.CanMoveDownToNextLevel() which will return true if the Player is standing on a stairway leading down. We then generate a new map and increment the _mapLevel.

If you run the game now you should be able to explore until you find stairs and descend deeper into the dungeon.


Going down stairs

Closing Thoughts

Although we got our stairs working we are still missing some important things. Currently levels don’t get any more difficult the deeper we go.

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

Bored waiting for the next tutorial post? The completed project is already available on Bitbucket.


12 thoughts on “RogueSharp V3 Tutorial – Stairs

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

  2. Andrea Magnelli

    Hey pal, this series is exceptional. I was trying to search some nasty tutorial to start up my project and this one sounds fantastic!
    I’m here waiting for others tutorials 🙂

    What will be really cool would be adding to future tutorials:

    – Going upstair \ downstair mantaining dungeon structures\mobs killed etc
    – Handling up lore forms or dialogue forms (which then brings to item shop etc)
    – Maybe mouse interaction?

    Congrats again, really really good stuff


      1. Andrea Magnelli

        Hi Faron, thanks for your fast answer 🙂

        I got a little difficult\doubt that is concerning me.

        I’ve tried to play a bit with the console layout of your tutorial project, and i was hoping that would have been pretty possible to display one console with a font & another with another font.

        Why that?

        Basically because sometimes you want to use a smaller font for various text\UI\interface, and maybe a bit more readable size for the map (maybe half of the map tile font).
        I know you can “extend” the font bitmap adding rows over the 256 cells that already are settled up, but that only extends the symbol collection.

        I’ve seen you brought up this “tutorial” with SadConsole too, and it looks easy understandable once you understood the concepts of your tutorial. It uses SadConsole v3.00 (now i think is gone out the 6.00).

        Every subConsole has a method to access & modify the current font, which is very useful, but i’m knocking a bit my head off trying to achieve that on RLNET.

        I’ve tried to extend\build my own RLConsole\RLCell etc classes to do what RLRootConsole basically does (it seems the only one to have a editable font-png source), but i surrendered after some tries ’cause it enters a bit too much in the hearth of GL libraries and i was pretty sure to mess up everything.

        Did you have tried something like that or is not possible at all with RLNET?
        Considering that, do you suggest me (if i really need this framework function) to switch over SadConsole 3.00?
        I’m a bit afraid that the 3.00 version will not receive too much support in the future ’cause it is a bit aged.

        I hope I’ve explained my doubt & concerns (i’m not an english mother tongue :D) and sorry for WoT!

        Thanks for your kindness Faron,



      2. Faron Bracy Post author

        Hi Andrea,

        As far as I am aware RLNet only allows one size of symbols for a console so it would not currently support two different font sizes.

        For choosing between RLNet and SadConsole, it’s a matter of preference. I can tell you that it seems the creator of RLNet has not been doing any updates or maintenance to the library. SadConsole on the other hand is very active and the author is constantly making updates as you pointed out by the frequent version changes.

        I assume by the SadConsole tutorial you mean the port that I did here ( That code could be using an older version of SadConsole, I used the most recent version that was stable at the time. If you want to make your own unique roguelike and not just follow the tutorial I would recommend using the latest version of SadConsole. My RogueSharp library should still work just fine with whatever console you choose.

        Another option is to use Unity ( RogueSharp works nicely with Unity and it is has a large and active community.

        I hope this helps to give you some options,

      3. Andrea Magnelli

        Hi Faron here is Andrea again,

        i noticed a bit problem: i tried to resize a bit the rooms & to add some monsters.

        Keeping the “moving” arrows pressed can result in some heavy stuttering\rendering lag (tried with different systems & console renderer – SadConsole & RLNET), and it seems to be related to the InputState controller instead of problems linked to pathfinding algorithms, scheduler or others, it happens also with a normal sized map with a bit more of monsters.

      4. Andrea Magnelli

        I investigated a bit more on the issue, i replicated it in a clean project, by adding a lot of monsters in one room and then “keeping movement key pressed”, the problem seems stronger when the map size exceed the console dimension and the stutter lag can became around 0.6-0.8 sec at turn, at this point i dont know if it is related to the input method or something else.

        Andrea (sorry for spam here but i dont know where to write you :D)

      5. Andrea Magnelli

        Okay, i noticed something else, that happens less when the monsters are just a few.

        The “output” console in VS pull out an enormous amount (in 10-12 turn — 300 or so) of “Exception thrown: ‘RogueSharp.PathNotFoundException’ in RogueSharp.dll” and some “Exception thrown: ‘RogueSharp.NoMoreStepsException’ in RogueSharp.dll”, from what i remember throwing out a lot of exception is not good in performance tuning, also if those are catched & handled by the wrapper classes that calls the function.

        If you pick your base example and but a considerable amout of monsters in a room, and start to “move around\combat” keeping keys pushed down you will notice that.


    1. Faron Bracy Post author

      Thanks for all of the feedback on the tutorial. You are correct about there being plenty of room for performance improvements. The code hasn’t been optimized for performance at all.

      I suspect most of the issues you are seeing are around the pathfinder. A new pathfinder is created for each monster and perhaps it would be better if they shared the same one for a given turn maybe using the GoalMap class instead of the PathFinder. The PathNotFoundException happens when asking for a path for a monster that is blocked by other monsters, which happens of course much more frequently when there are lots of monsters in a room. If monsters did an efficient check for being blocked before finding a path it could help. For big maps, only cells within a certain range of a monster could be passed in for pathfinding instead of the entire map.

      When working on my own projects, I usually save performance improvements for the very end and only if there is a noticeable issue as they can be time consuming and aren’t always necessary. Some even say premature optimization is the root of all evil

      If I get extra time this weekend I may look into profiling some code out of curiosity. I don’t plan on updating the tutorial even if it is inefficient as it is really just meant to give people an example and some ideas. If there are performance improvements that could be made to the RogueSharp library without making it more complicated to use, then I am definitely interested in that. There are already some great contributions to RogueSharp v4 that are in the works.


      1. Andrea Magnelli

        That phrase “premature optimization is the root of all evil” is in the first page of my computer engineering thesis 😀 (thanks Knuth)

        Don’t worry about performance that’s a problem that you can fight with later, i’m writing here just because i don’t know where to do it and it is useful to keep a track.

        Sorry again for the spam and good work on RS v4


  3. Andrea Magnelli

    Thanks again Faron for your insights.

    I think that the reason why i started following this tutorial was pretty the same that pushed you towards the completition of it, basically: think about the game, less about fancy graphics & stuff like that. And i think that RLNET pushes very well in this direction, with a simple but concrete DLL.

    I think that if I (or We, or just you) work well on the core game (RogueSharp or variations) then the only concern if one day we want to switch to something else should be just handling keyboard\mouse interaction, mapping new commands for printing on console and maybe adding some fancy animations or overlays. But the core, i think, should remain the same and that is the very soul of the game.

    I tried Unity too but i was searching for something more compact right now.

    Thanks again Faron, hope to read you soon,



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 )

Google+ photo

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

Connecting to %s