Page 1 of 1

C# Roguelike Console Map Writeup/Tutorial

Poll: C# Roguelike Console Map Writeup/Tutorial (1 member(s) have cast votes)

How helpful was this?

  1. Very nice A++ (0 votes [0.00%])

    Percentage of vote: 0.00%

  2. Nice (1 votes [100.00%] - View)

    Percentage of vote: 100.00%

  3. 50/50 (0 votes [0.00%])

    Percentage of vote: 0.00%

  4. Pretty bad (0 votes [0.00%])

    Percentage of vote: 0.00%

  5. Horrible (0 votes [0.00%])

    Percentage of vote: 0.00%

Vote Guests cannot vote

#1 frostyraver  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 13
  • View blog
  • Posts: 195
  • Joined: 21-April 09

Posted 25 March 2011 - 11:14 PM

Hey everyone!

With the release of my roguelike engine, people will probably want to know how I got a maze style effect, well in this tutorial/write up I will explain how I have done it.

Keep in mind I'm going assume you know the basics and just want to use this as an idea on 1 way how it can be achieved, this is not necessarily the best way, but a way I find easiest for me.

The engine I'll refer too is a custom build one, that I made, you should be able to link this or get some idea on how to implement this into your own project, a tutorial is coming soon for it though, so you will want to have some type of display happening because this is an overview tutorial, which means I'm not going in-depth with every little thing.

For reference the classes I use are:
Main Menu - Holds my main menu where the user can select what they want to do
Main Game - Holds all my main game data, such as drawing, putting the shops in, sorta the core of the engine
Monster - When I want to create a new monster class I can just stick this class into an array loop to loop in 50 monsters stats, position, anything!
Player - Holds the varibles for a player, movement is done here also.
Shop - Holds the shop varibles and stuff, items for sale and what not
Map - This is what we're creating today, the map class generates, and hold all the map data, so the idea is when you want a new map you can just type:
Map currentmap = new Map;



I don't have reference links on where or how I came up with this code, if I was going to give a reference link I'd give you this one.

Roguelike Wiki

It's a writeup on the concept of a roguelike.

Also you can view my blog, ask questions, there's a neat way I delt with a tile water generator which is pretty neat.
My blog

Lets begin!

You will want to start by creating a map class, and we will refer to this, in your main game area, so that when we want a new floor level, we can just put :

int MapLevels = 100;
Classes.Map[] map = new Classes.Map[MapLevels];



So now we have defined 100 levels for the class we can add some code to the actual class.

Please Note that you don't have to use an integer for the amount of levels you can specify it in instead of MapLevels, for the sake of this I like to use it so I can just alter this here Instead of looking through code for it, and you can alter it later In game and do all kinds of things.

Go back to our blank map class you will want to specify some varibles for the map, such as the entrance/exit location.etc

        public int XMax = 100;
        public int YMax = 57;
        public char[,] MapArray = new char[100, 57];
        public int XExit = 5;
        public int YExit = 5;
        public int XEntrance = -1;
        public int YEntrance = -1;
        public int[] MonsterArray = new int[50];
        public Random random = new Random(DateTime.Now.Millisecond);



I like having a randomizer there, It's not necessary none the less it doesn't hurt.
MapArray is the map size, MonsterArray is how many monsters we want.

Now we got all of this setup, we want to create the generator, in the same class.

Put in this:

        public void Generate_Run(Map map, Player player1)
        {
            // Clear rooms
            map.Generator_Clear(map, player1);

            // Generate Maze
            map.Generator_Maze(map, player1);
        }


I love public classes, I have no real need for privates if you know what your doing and we're not using passwords as such, Maybe if you want too you can rework the stats to private or what ever but for now we will do this.

We want to first CLEAR the map, creates all our bounds and basic dirt tiles, what we actually want to do is CARVE into them, you should by now be getting some idea, about this.

        // map Generation
        public void Generator_Clear(Map map, Player player1)
        {
            for (int y = 0; y < YMax; y++)
            {
                for (int x = 0; x < XMax; x++)
                {
		    // Create dirt level clear it.
                    map.MapArray[x, y] = '█';

                }
            }
        }


Everything's on an X and Y base, I have the XMAX and YMAX of the whole level and it gots from left to right, increment y++ and moves down, now we have an arra of '█', I use chars because they are FAST and 1 byte not like strings, you must keep it consistant if you have a 2 space length then 1 space length generating your maze will look out of wack, so you NEED to work with single tiles.

'█' could also be what you like, but I'm old fashioned and I love it looking like my atari 2600.

Next is the actualy maze generation, we want to CARVE into it.
public void Generator_Maze(Map map, Player player1)
        {
            int AmountOfCaves = 17;
            int CaveCount = 0;
            int DeathCount = 0;

            while (CaveCount < AmountOfCaves)
            {
                // Increment 1 cave
                CaveCount++;

                // Create a random varible
                Random randy = new Random(DateTime.Now.Millisecond);

                // Random a start location
                int x = randy.Next(0, map.XMax);
                int y = randy.Next(0, map.YMax);
                bool Dead = false;

                // Set the direction
                int Direction = 1;
                int count = 0;

                // Move a random direction, if Direction isn't 0 continue
                while (count < 1000)
                {
                    // Clear the space
                    if (y > 1 && y < map.YMax - 1 && Dead == false)
                        map.MapArray[x, y] = ' ';

                    // Set the exit
                    map.MapArray[map.XExit, map.YExit] = 'v';

                    // Bools
                    bool Up = false;
                    bool Right = false;
                    bool Down = false;
                    bool Left = false;
                    bool UUp = false;
                    bool RRight = false;
                    bool DDown = false;
                    bool LLeft = false;
                    bool Moved = false;
                    char LastMove = ' ';
                    Dead = false;

                    // Check spaces
                    // Move only selected direction

                    while (Moved == false)
                    {
                        // Check spaces
                        // If we're within bounds
                        if ((y - 1 > 1 && map.MapArray[x, y - 1] == '█') || LastMove == 'D')
                        {
                            Up = true;
                        }
                        // Right
                        // If we're within bounds
                        if ((x + 1 < map.XMax - 1 && map.MapArray[x + 1, y] == '█') || LastMove == 

'L')
                        {
                            Right = true;
                        }
                        // Down
                        // If we're within bounds
                        if ((y + 1 < map.YMax - 1 && map.MapArray[x, y + 1] == '█') || LastMove == 

'U')
                        {
                            Down = true;
                        }
                        // Left
                        // If we're within bounds
                        if ((x - 1 > 1 && map.MapArray[x - 1, y] == '█') || LastMove == 'R')
                        {
                            Left = true;
                        }
                        // 1 across
                        // If we're within bounds
                        if ((y - 2 > 1 && map.MapArray[x, y - 2] == '█') || LastMove == 'D')
                        {
                            UUp = true;
                        }
                        // Right
                        // If we're within bounds
                        if ((x + 2 < map.XMax - 1 && map.MapArray[x + 2, y] == '█') || LastMove == 

'L')
                        {
                            RRight = true;
                        }
                        // Down
                        // If we're within bounds
                        if ((y + 2 < map.YMax - 1 && map.MapArray[x, y + 2] == '█') || LastMove == 

'U')
                        {
                            DDown = true;
                        }
                        // Left
                        // If we're within bounds
                        if ((x - 2 > 1 && map.MapArray[x - 2, y] == '█') || LastMove == 'R')
                        {
                            LLeft = true;
                        }


                        // Set the direction for this loop
                        Direction = randy.Next(1, 5);

                        // Move accordingly
                        switch (Direction)
                        {
                            case 0:
                                break;
                            // Up
                            case 1:
                                // If we're within bounds
                                if (UUp == true)
                                {
                                    y--;
                                    Moved = true;
                                    LastMove = 'U';
                                }
                                break;
                            // Right
                            case 2:
                                // If we're within bounds
                                if (RRight == true)
                                {
                                    x++;
                                    Moved = true;
                                    LastMove = 'R';
                                }
                                break;
                            // Down
                            case 3:
                                // If we're within bounds
                                if (DDown == true)
                                {
                                    y++;
                                    Moved = true;
                                    LastMove = 'D';
                                }
                                break;
                            // Left
                            case 4:
                                // If we're within bounds
                                if (LLeft == true)
                                {
                                    x--;
                                    Moved = true;
                                    LastMove = 'L';
                                }
                                break;
                        }

                        if ((Up == false && Right == false && Down == false && Left == false) ||
                            (UUp == false && RRight == false && DDown == false && LLeft == false))
                        {
                            Moved = true;
                            //map.MapArray[x, y] = ' ';
                            x = randy.Next(0, map.XMax);
                            y = randy.Next(0, map.YMax);
                            Dead = true;
                            DeathCount++;
                        }
                    }

                    count++;

                }

            }
        }



Let me break this down for you.

            int AmountOfCaves = 17;
            int CaveCount = 0;
            int DeathCount = 0;
[code]
It's actually made up of a BUNCH of caves, so when we enter we want to tell the generator how many caves we want, we could use a loop but for the sake of this we can just use this.

[code]
            while (CaveCount < AmountOfCaves)
            {


While the cave count is less than amount of caves we want to keep making caves.

                // Increment 1 cave
                CaveCount++;

                // Create a random varible
                Random randy = new Random(DateTime.Now.Millisecond);

                // Random a start location
                int x = randy.Next(0, map.XMax);
                int y = randy.Next(0, map.YMax);
                bool Dead = false;

                // Set the direction
                int Direction = 1;
                int count = 0;



Now that is all setup we increment 1 cave, set the randomizer, Probably should reuse the one we've done previously but anyway.

Random a start location, 0 - xmax and 0 - ymax, anything else will cause out of bounds errors.

Set the direction and another counter.

// Move a random direction, if Direction isn't 0 continue
                while (count < 1000)
                {
                    // Clear the space
                    if (y > 1 && y < map.YMax - 1 && Dead == false)
                        map.MapArray[x, y] = ' ';

                    // Set the exit
                    map.MapArray[map.XExit, map.YExit] = 'v';

                    // Bools
                    bool Up = false;
                    bool Right = false;
                    bool Down = false;
                    bool Left = false;
                    bool UUp = false;
                    bool RRight = false;
                    bool DDown = false;
                    bool LLeft = false;
                    bool Moved = false;
                    char LastMove = ' ';
                    Dead = false;



While count is less than 1000, keep looping, we could do another for loop here.

When the mover moves to the end it dies, when it can't move anymore, so then it won't keep generating and make our maze look odd, a 1000 counter is enough because you get random maze sizes from huge to tiny.

We set the exit, probably should have an if statement but anyway.

Set up the directions we're going to need to scan ahead and make sure we're breaking down spaces.

Reset the lastmove and if it died.

                    // Check spaces
                    // Move only selected direction

                    while (Moved == false)
                    {



While the move == false, so while we havn't moved keep looping.

// Check spaces
                        // If we're within bounds
                        if ((y - 1 > 1 && map.MapArray[x, y - 1] == '█') || LastMove == 'D')
                        {
                            Up = true;
                        }
                        // Right
                        // If we're within bounds
                        if ((x + 1 < map.XMax - 1 && map.MapArray[x + 1, y] == '█') || LastMove == 

'L')
                        {
                            Right = true;
                        }
                        // Down
                        // If we're within bounds
                        if ((y + 1 < map.YMax - 1 && map.MapArray[x, y + 1] == '█') || LastMove == 

'U')
                        {
                            Down = true;
                        }
                        // Left
                        // If we're within bounds
                        if ((x - 1 > 1 && map.MapArray[x - 1, y] == '█') || LastMove == 'R')
                        {
                            Left = true;
                        }
                        // 1 across
                        // If we're within bounds
                        if ((y - 2 > 1 && map.MapArray[x, y - 2] == '█') || LastMove == 'D')
                        {
                            UUp = true;
                        }
                        // Right
                        // If we're within bounds
                        if ((x + 2 < map.XMax - 1 && map.MapArray[x + 2, y] == '█') || LastMove == 

'L')
                        {
                            RRight = true;
                        }
                        // Down
                        // If we're within bounds
                        if ((y + 2 < map.YMax - 1 && map.MapArray[x, y + 2] == '█') || LastMove == 

'U')
                        {
                            DDown = true;
                        }
                        // Left
                        // If we're within bounds
                        if ((x - 2 > 1 && map.MapArray[x - 2, y] == '█') || LastMove == 'R')
                        {
                            LLeft = true;
                        }


Direction checkers so we don't smash through a random wall only if the direction 2 spots over is a dirt tile.

			// Set the direction for this loop
                        Direction = randy.Next(1, 5);

                        // Move accordingly
                        switch (Direction)
                        {
                            // Up
                            case 1:
                                // If we're within bounds
                                if (UUp == true)
                                {
                                    y--;
                                    Moved = true;
                                    LastMove = 'U';
                                }
                                break;
                            // Right
                            case 2:
                                // If we're within bounds
                                if (RRight == true)
                                {
                                    x++;
                                    Moved = true;
                                    LastMove = 'R';
                                }
                                break;
                            // Down
                            case 3:
                                // If we're within bounds
                                if (DDown == true)
                                {
                                    y++;
                                    Moved = true;
                                    LastMove = 'D';
                                }
                                break;
                            // Left
                            case 4:
                                // If we're within bounds
                                if (LLeft == true)
                                {
                                    x--;
                                    Moved = true;
                                    LastMove = 'L';
                                }
                                break;
                        }


Move in a direction, if it's avalible via LLeft == true, and then set that we have moved.

                        if ((Up == false && Right == false && Down == false && Left == false) ||
                            (UUp == false && RRight == false && DDown == false && LLeft == false))
                        {
                            Moved = true;
                            //map.MapArray[x, y] = ' ';
                            x = randy.Next(0, map.XMax);
                            y = randy.Next(0, map.YMax);
                            Dead = true;
                            DeathCount++;
                        }


If no spaces are avalible then kill off the digger.

                    }
                    count++;

                }


Increment the counter.

Now with that inplace you want to display the map.

        // Display map
        public void Generator_Display(Map map, Player player1)
        {

            for (int y = 0; y < map.YMax; y++)
            {
                for (int x = 0; x < map.XMax; x++)
                {
                    if (map.MapArray[x, y] == '@')
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.Write(map.MapArray[x, y]);
                        Console.ForegroundColor = ConsoleColor.White;
                    }
                    else
                        Console.Write(map.MapArray[x, y]);

                }
                Console.WriteLine("");
            }
        }



Basically this is how we update a player and draw a map, you just loop, much like the clear game, but this time display!

And that's the basics of it, easy huh?

I won't show you how to link it to your maingame, That should be a task for you, take note also I have (Map map, Player player1) on all my lines, this should give you some clue as how to handle this ;)

Is This A Good Question/Topic? 0
  • +

Page 1 of 1