Tutorial 1 – Roguelike Map Generation using RogueSharp and MonoGame

This is part 1 in a set of tutorials for using RogueSharp and MonoGame to create a basic Roguelike game. It is meant to serve as an introduction to the RogueSharp library. This tutorial assumes that you already have Visual Studio installed. I’m using VS 2013.

Preparing the Project

  1. Go and download MonoGame if you don’t already have it. I’m using version 3.2 which can be found here: http://www.monogame.net/2014/04/07/monogame-3-2/
  2. Create a new MonoGame Windows Project.

    Create a new MonoGame Windows Project

    Create a new MonoGame Windows Project

  3. Start the project and make sure that you get a Blue Screen of Success. I know what you were thinking when I said Blue Screen but trust me, this one is good!

    Blue Screen Of Success

    Blue Screen Of Success

  4. Your code at this point should look something like this.
  5. Next we’ll need to add Floor and Wall sprites into the content folder. Be sure to set their Copy to Output Directory properties to “Copy if Newer”

    Add Floor and Wall Sprites

    Add Floor and Wall Sprites

  6. Here are the sprites I’m using but feel free to substitute your own.
    Floor Sprite

    Floor Sprite

    Wall Sprite

    Wall Sprite

  7. Now your code should be like this
  8. Next we are going to create two new Texture2D fields and load our Floor and Wall sprites into these using Content.Load. Lastly we’ll use a SpriteBatch to draw our two textures to the screen. I’m not going to go into great detail as to how this works as there are plenty of resource out there already for this. Here is one example
  9. Code so far
  10. You should now be able to run the project and verify that you are seeing the floor and wall textures on your patented Blue Screen of Success.

    Rendering Floor and Wall Sprites

    Rendering Floor and Wall Sprites

Introducing RogueSharp

Hopefully that wasn’t too bad getting here. Now is where the real tutorial begins. We’re going to start using the power of RogueSharp to get moving really quickly on our game.

Add the RogueSharp NuGet Package to the Project

Right click on the project and choose Manage NuGet Packages…

Manage NuGet Packages

Manage NuGet Packages

Search for “RogueSharp” and add it to the project.

RogueSharp NuGet Package

RogueSharp NuGet Package

Creating a Map

In the Game1.cs file we’ll first need to add a using directive for the RogueSharp namespace

using RogueSharp;

Next we want to create a private field of type IMap named _map in the Game1 class

private IMap _map;

In the Initialize() method place the following code just under where it says // TODO: Add your initialization logic here.

Code

IMapCreationStrategy<Map> mapCreationStrategy =
    new RandomRoomsMapCreationStrategy<Map>( 50, 30, 100, 7, 3 );
_map = Map.Create( mapCreationStrategy );

Explanation

There is a static method on the Map class that takes an IMapCreationStrategy as a parameter. Several implementations of this strategy are included with RogueSharp. This also allows anyone to create their own Map generation code by simply creating a class that implements the IMapCreationStrategy interface.

In this example we didn’t make our own class, but instead used the RandomRoomsMapCreationStrategy which is included with the RogueSharp library.

With this strategy a Map will be generated by trying to place rooms up to the maximum number specified in random locations around the Map. Each room will have a height and width between the minimum and maximum room size. If a room would be placed in such a way that it overlaps another room, it will not be placed. Once all rooms have have been placed, or thrown out because they overlap, corridors will be created between rooms in a random manner.

The constructor takes 5 parameters which are as follows:

  • width = The width of the Map to be created
  • height = The height of the Map to be created
  • maxRooms = The maximum number of rooms that will exist in the generated Map
  • roomMaxSize = The maximum width and height of each room that will be generated in the Map
  • roomMinSize = The minimum width and height of each room that will be generated in the Map

With the parameters we provided we said create a Map that is 50 by 30 Cells in size. Try to place up to 100 rooms on this Map (though many of these will be thrown out if they overlap an existing room). And last make sure that each side of the rooms are between 3 and 7 Cells long.

The source code for the RandomRoomsMapCreationStrategy can be found here.

Your code should now look something like this

Drawing the Map

It’s great that we created a Map, but we can’t actually see it yet.

To actually see our map we’re going to need to add some code to the Draw() method in Game1.cs. Place the following code just under where it says // TODO: Add your drawing code here.

Code

spriteBatch.Begin( SpriteSortMode.BackToFront, BlendState.AlphaBlend );

int sizeOfSprites = 64;
foreach ( Cell cell in _map.GetAllCells() )
{
   if ( cell.IsWalkable )
   {
      var position = new Vector2( cell.X * sizeOfSprites, cell.Y * sizeOfSprites );
      spriteBatch.Draw( _floor, position, Color.White );
   }
   else
   {
      var position = new Vector2( cell.X * sizeOfSprites, cell.Y * sizeOfSprites );
      spriteBatch.Draw( _wall, position, Color.White );
   }
}

spriteBatch.End();

Explanation

Line 3 – We set a variable corresponding to the size of the sprites we are using for our floor and wall Cells. If you used the graphics provided above these are 64 pixels square. This value will be used to calculate where to draw each sprite.

Line 4 – Next we call the GetAllCells() method on our newly created _map. This returns an IEnumerable<Cell> of all Cells in the map that we can iterate through using a foreach loop.

Line 6 – As we iterate through each Cell we check the IsWalkable property. This will determine if we should draw a floor as in Line 9 or a wall as in Line 14

Lines 8 and 13 – We calculate the position of where we should draw the sprite by looking at the corresponding Cell’s X and Y properties and multiplying it by the variable we set in Line 3

Lines 9 and 14 – This is where we make the actual calls to the Draw method on our SpriteBatch and provide either the floor or wall texture and the position we calculated earlier

Your code should now look something like this

The Scaling Problem

If you run the game now you’ll see a problem (at least if you used my 64 x 64 pixel sprites).

Drawing The Map

Drawing The Map

The map is too large to fit on the screen. There are several more elegant ways to handle this using transformation matrices and camera classes but we’ll talk about that in a later tutorial. For now lets just scale all of our sprites down to 1/4 size, 16 x 16 pixels.

Code

spriteBatch.Begin( SpriteSortMode.BackToFront, BlendState.AlphaBlend );

int sizeOfSprites = 64;
float scale = .25f;
foreach ( Cell cell in _map.GetAllCells() )
{
   var position = new Vector2( cell.X * sizeOfSprites * scale, cell.Y *  sizeOfSprites * scale  );
   if ( cell.IsWalkable )
   {
      spriteBatch.Draw( _floor, position, null, null, null, 0.0f, new Vector2( scale, scale ), Color.White );
   }
   else
   {
      spriteBatch.Draw( _wall, position, null, null, null, 0.0f, new Vector2( scale, scale ), Color.White );
   }
}

spriteBatch.End();

Explanation

Line 4 – Introduced a new variable “scale” which we will use both when drawing sprites and calculating their positions

Line 7 – Refactored position calculation out of each if / else block and placed it directly in the foreach. Also use scale when calculating the position

Lines 10 and 14 – Used a different overload of the Draw method on SpriteBatch which allows us to set the scale of the sprite to draw

Now if we run the project we should see something better

Map Scaled by 1/4

Map Scaled by 1/4

Your map will look different because each time the program is ran, a different seed is generated for the random number generator used behind the scenes to place all the rooms and corridors. In a later tutorial will look at the different pseudo-random number generators provided with RogueSharp and how you can even create your own.

And here is the final code for creating our map in this tutorial

[edit] Part 2 of the tutorial is now live

Additional Fun

If you are looking for some extra things to try until I post the next tutorial some ideas are

  • Try creating your own class that implements IMapCreationStrategy and use it to create your own unique maps. Look at the source code for RogueSharp for a few simple examples.
  • Use more map features like doors and pits, not just floors and walls
  • Clean up the code. Extract some methods, rename classes, organize what we have. I purposely left it as close to the default MonoGame project as possible, but Game1 is not a very interesting name for a class and who needs all those TODOs
  • Try creating your own camera class that allows you to pan around the Map and zoom in or zoom out.
  • Classic Roguelikes don’t use sprites. Try making it look like the classics by implementing an ASCII display. (or just fake it with sprites of ASCII characters)
Advertisements

11 thoughts on “Tutorial 1 – Roguelike Map Generation using RogueSharp and MonoGame

  1. Pingback: Tutorial 2 – Roguelike Field-of-View Calculation using RogueSharp and MonoGame | Creating a Roguelike Game in C#

  2. Joe Byall

    Very awesome tutorial here for those of us (me) who are uninitiated in both monogame and roguesharp.

    Reply
    1. Faron Bracy Post author

      Thank you Joe! I wasn’t sure if anyone would even see these, let alone get value out of them. I plan to post at least 1 tutorial a week, and am working on the third one now. I hope you’ll return to see the rest in the series.

      Reply
    1. Faron Bracy Post author

      The `Map` class in RogueSharp is really more for just calculating field-of-view and pathfinding. It doesn’t actually have much to do with the tile type other than having the `IsTransparent` and `IsWalkable` flags. A chest for example would normally be walkable and transparent. As far as RogueSharp is concerned it wouldn’t be any different than a normal floor tile. It would be up to you to wrap or extend RogueSharp’s existing Map class with something specific to your game and the tile types that appear in your game. So although a floor tile and a chest tile have the same properties as far as RogueSharp is concerned, your game would detect the difference and perhaps drop treasure or trigger a trap when the player walked over the chest tile. A locked door tile for instance might not be walkable unless the player is currently holding a key. The transparency of the door would change based on if it were open or closed. You normally couldn’t see past a solid door until you opened it. Let me know if this was the sort of thing you were looking for.

      Reply
  3. sonreintelobos

    I have been working with Xamarin on a mac. Is there a way to get RogueSharp into Xamarin? Obviously using the microsoft package is not going to work – I assume. I have been doing some “GDI+” tile stuff on my mac using the standard C# forms from VS. I have a pretty nice little test going but it lacks what it sounds like RogueSharp has. It would be great to see if your package or its contents would work in this environment.

    Reply
  4. Pingback: RogueSharp V3 Tutorial – Introduction and Goals | Creating a Roguelike Game in C#

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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