ARTICLE

Building the Really Really Really Simple RogueLike V0.1 With C#

Posted by Dom Millar Articles | Visual C# February 02, 2012
Want to build a Roguelike game with C# in 5 minutes? The following is a really quick game I built in about 2 hours and shows how easy it is to get a simple game going.
Reader Level:

Really Really Really Simple Roguelike V0.1

Want to build a Roguelike game with C# in 5 minutes? The following is a really quick game I built in about 2 hours and shows how easy it is to get a simple game going.

Its a very very very simple game - all you do is pickup a sword before the monster gets to you and you win. Obviously, if the monster gets to you first - well you can work out the ending.

What do you need?

C# on Visual Studio 2005/2008 or 2010. Any version should be fine as long as you can create a console application.

Now we are going to add the following into 1 file in Visual Studio; rather than using multiple files and whilst this is not the best practice for a serious application, we are doing this to keep things really simple, and to display the entire application on a few pages of paper.
Here we go.

  1. Start Visual Studio 2010
  2. File->New Project
  3. Select the Windows->Console Application
  4. Name the Project ReallyReallyRealySimpleRogueLike and click OK
  5. Right click on References->Add Reference...
  6. Click on Assemblies then Framework and select System.Drawing
  7. At the top of Program.cs insert the following line using System.Drawing;
  8. Replace the program class with the following:

    class ReallyReallyReallySimpleRogueLike
        {
            static void Main(string[] args)
            {
                Dungeon dungeon = new Dungeon(Constants.DungeonWidth, Constants.DungeonHeight);
                string displayText = Constants.IntroductionText;

                while (dungeon.IsGameActive)
                {
                    dungeon.DrawToConsole();
                    Console.WriteLine(displayText);
                    Console.Write(Constants.CursorImage);
                    displayText = dungeon.ExecuteCommand(Console.ReadKey());
                }

                Console.WriteLine(ConcludeGame(dungeon));
                Console.ReadLine();
            }

            private static string ConcludeGame(Dungeon dungeon)
            {
                return (dungeon.player.Hits > 0) ? Constants.PlayerWinsText : Constants.MonsterWinsText;
            }
        }
     
     

  9. Now add the following class:

    class Dungeon
        {
            Random r;
            public Player player;
            List monsters;
            List swords;
            List walls;

            public Tile[,] Tiles;
            private int xMax;
            private int yMax;
            public enum Direction
            {
                North,
                South,
                East,
                West
            }

            public bool IsGameActive
            {

                get
                {
                    return (player.Hits > 0 && monsters.Any(m => m.Hits > 0));
                }
            }

            public Dungeon(int xMax, int yMax)
            {
                monsters = new List();
                walls = new List();
                swords = new List();

                this.xMax = xMax;
                this.yMax = yMax;
                Tiles = new Tile[xMax, yMax];
                BuildRandomDungeon();
                SetDungeonTiles();
            }

            public string ExecuteCommand(ConsoleKeyInfo command)
            {
                string commandResult = ProcessCommand(command);
                ProcessMonsters();
                SetDungeonTiles();

                return commandResult;
            }

            private void ProcessMonsters()
            {
                if (monsters != null && monsters.Count > 0)
                {
                    monsters.Where(m => m.Hits >= 0).ToList().ForEach(m =>
                    {
                        MoveMonsterToPlayer(m);
                    });
                }
            }

            private void BuildRandomDungeon()
    {
    r = new Random();
    SetAllDungeonSquaresToTiles();

    for (int i = 0; i < xMax; i++)
    {
    Wall top = new Wall(i, 0);
    walls.Add(top);
    Wall bottom = new Wall(i, yMax - 1);
    walls.Add(bottom);
    }

    for (int i = 0; i < yMax; i++)
    {
    Wall left = new Wall(0, i);
    walls.Add(left);
    Wall right = new Wall(xMax - 1, i);
    walls.Add(right);
    }

    for (int i = 0; i < Constants.NumberOfSwords; i++)
    {
    Sword s = new Sword(GetValidRandomPoint());
    swords.Add(s);
    }

    for (int i = 0; i 0 && monster.X player.X) ? -1 : 1;

    if ((monster.Y > 0 && monster.Y player.Y) ? -1 : 1;

    if (!IsInvalidValidMove(move.X, move.Y))
    {
    monster.X = move.X;
    monster.Y = move.Y;
    }

    if (monster.X == player.X && monster.Y == player.Y)
    ResolveCombat(monster);
    }

            private void ResolveCombat(Monster monster)
            {
                if (player.Inventory.Any())
                    monster.Die();
                else
                    player.Die();
            }
     
            public string ProcessCommand(ConsoleKeyInfo command)
            {
     
                string output = string.Empty;
                switch (command.Key)
                {
                    case ConsoleKey.UpArrow:
                    case ConsoleKey.DownArrow:
                    case ConsoleKey.RightArrow:
                    case ConsoleKey.LeftArrow:
                        output = GetNewLocation(command, new Point(player.X, player.Y));
                        break;
                    case ConsoleKey.F1:
                        output = Constants.NoHelpText;
                        break;
                }
     
                return output;
            }

            private string GetNewLocation(ConsoleKeyInfo command, Point move)
            {
                switch (command.Key)
                {
                    case ConsoleKey.UpArrow:
                        move.Y -= 1;
                        break;
                    case ConsoleKey.DownArrow:
                        move.Y += 1;
                        break;
                    case ConsoleKey.RightArrow:
                        move.X += 1;
                        break;
                    case ConsoleKey.LeftArrow:
                        move.X -= 1;
                        break;
                }

                if (!IsInvalidValidMove(move.X, move.Y))
                {
                    player.X = move.X;
                    player.Y = move.Y;
                    if (Tiles[move.X, move.Y] is Sword && player.Inventory.Count == 0)
                    {
                        Sword sword = (Sword)Tiles[move.X, move.Y];
                        player.Inventory.Add(sword);
                        swords.Remove(sword);
                    }
                    return Constants.OKCommandText;
                }
                else
                    return Constants.InvalidMoveText;
            }

            public bool IsInvalidValidMove(int x, int y)
            {
                return (x == 0 || x == Constants.DungeonWidth - 1 || y == Constants.DungeonHeight - 1 || y == 0);
            }

            public void SetDungeonTiles()
            {
                //Draw the empty dungeon
                SetAllDungeonSquaresToTiles();

                SetAllDungeonObjectsToTiles();
            }

            private void SetAllDungeonObjectsToTiles()
            {
                //Now draw each of the parts of the dungeon
                walls.ForEach(w => Tiles[w.X, w.Y] = w);
                swords.ForEach(s => Tiles[s.X, s.Y] = s);
                monsters.ForEach(m => Tiles[m.X, m.Y] = m);
                Tiles[player.X, player.Y] = player;
            }

            private void SetAllDungeonSquaresToTiles()
            {

                for (int i = 0; i < yMax; i++)
                {
                    for (int j = 0; j < xMax; j++)
                    {
                        Tiles[j, i] = new Tile(i, j);
                    }
                }
            }

            public void DrawToConsole()
            {
                Console.Clear();
                for (int i = 0; i < yMax; i++)
                {
                    for (int j = 0; j < xMax; j++)
                    {
                        Console.ForegroundColor = Tiles[j, i].Color;
                        Console.Write(Tiles[j, i].ImageCharacter);
                    }
                    Console.WriteLine();
                }
            }
        }
     

  10. Now underneath, add the following code for the Tile, Wall and Sword classes:

    public class Tile
        {
            public string name { get; set; }
            public string ImageCharacter { get; set; }
            public ConsoleColor Color { get; set; }
            public int X { get; set; }
            public int Y { get; set; }

            public Tile() { }

            public Tile(int x, int y)
                : base()
            {
                this.X = x;
                this.Y = y;
                ImageCharacter = Constants.TileImage;
                Color = Constants.TileColor;
            }
        }

        public class Wall : Tile
        {
            public Wall(int x, int y)
                : base(x, y)
            {
                ImageCharacter = Constants.WallImage;
                this.Color = Constants.WallColor;
            }
        }

        public class Sword : Tile
        {
            public Sword(Point p)
            {
                ImageCharacter = Constants.SwordImage;
                this.Color = Constants.SwordColor;
                X = p.X;
                Y = p.Y;
            }
        } 
     

  11. Now add the classes you need for the various creatures:

    public class Creature : Tile
        {
            public int Hits { get; set; }

            public void Die()
            {
                Hits = 0;
            }
        }

        public class Player : Creature
        {
            public Player(Point p)
            {
                ImageCharacter = Constants.PlayerImage;
                Color = Constants.PlayerColor;
                Inventory = new List();
                X = p.X;
                Y = p.Y;
                Hits = Constants.StartingHitPoints;
            }

            public List Inventory { get; set; }
        }

        public class Monster : Creature
        {
            public Monster(Point p)
            {
                ImageCharacter = Constants.MonsterImage;
                Color = Constants.MonsterColor;
                X = p.X;
                Y = p.Y;
                Hits = Constants.StartingHitPoints;
            }
        }

     

  12. Now add the following class for all our constants:

        public static class Constants
        {
            public readonly static int DungeonHeight = 20;
            public readonly static int DungeonWidth = 20;
            public readonly static int NumberOfSwords = 5;
            public readonly static int MonsterDamage = 2;
            public readonly static int NumberOfMonsters = 1;
            public readonly static int StartingHitPoints = 10;

            public readonly static string TileImage = ".";
            public readonly static string WallImage = "#";
            public readonly static string PlayerImage = "@";
            public readonly static string SwordImage = "s";
            public readonly static string StepsImage = "S";
            public readonly static string MonsterImage = "M";
            public readonly static string CursorImage = ">";

            public readonly static ConsoleColor MonsterColor = ConsoleColor.Blue;
            public readonly static ConsoleColor PlayerColor = ConsoleColor.Gray;
            public readonly static ConsoleColor WallColor = ConsoleColor.DarkCyan;
            public readonly static ConsoleColor SwordColor = ConsoleColor.Yellow;
            public readonly static ConsoleColor TileColor = ConsoleColor.White;

            public readonly static string InvalidCommandText = "That is not a valid command";
            public readonly static string OKCommandText = "OK";
            public readonly static string InvalidMoveText = "That is not a valid move";
            public readonly static string IntroductionText = "Welcome to the dungeon - grab a sword kill the monster(s) win the game";
            public readonly static string PlayerWinsText = "Player kills monster and wins";
            public readonly static string MonsterWinsText = "Monster kills player and wins";
            public readonly static string NoHelpText = "No help text";
        }
     

  13. Compile and Run this and you should see something like:

    Rougelike.gif

Next Time.

Next time I will present the first iteration of the program and we'll see some nice improvements.

COMMENT USING