16. Labyrinth

For the background labyrinth, we might simply draw an image. But in classic platform and arcade games, it was more usual to use small repetitive images called "tiles". If we draw a grid over the screen of many classic games, we will find these tiles:

collision

We can imitate this by using a two dimensional array. In a first approach, we might use a 1 for a piece of wall and a 0 for a blank space:

byte [,] map = {
    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
    {1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1},
    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    {1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1},
    {1,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,1},
    {1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1},
    {1,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1},
    {1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1},
    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    {1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1},
    {1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1},
    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
 

And we would need a new image for those "pieces of wall":

Image wallImage = new Image("wall.bmp");

Which we would draw in a repetitive sequence, analyzing the array:

// Background map
for(int row=0; row<15; row++)
{
    for(int column=0; column<17; column++)
    {
        if (map[row,column] == 1)
            SdlHardware.DrawHiddenImage(wallImage, column*32, row*32);
    }
}
 


Now the whole source would be:

/*
  First mini-graphics-game skeleton
  Version D: background map for the labyrinth
*/
 
using System;
 
public class Game02d
{
    public static void Main()
    {
        bool fullScreen = false;
        SdlHardware.Init(800, 600, 24, fullScreen);
 
        Image dotImage = new Image("dot.bmp");
        Image enemyImage = new Image("ghostGreen.bmp");
        Image pacImage = new Image("pac01r.bmp");
        Image wallImage = new Image("wall.bmp");
 
        int x=40, y=12;
        int pacSpeed = 6;
 
        int amountOfDots = 100;
        int[] xDot = new int[amountOfDots];
        int[] yDot = new int[amountOfDots];
        bool[] visible = new bool[amountOfDots];
 
        Random randomNumberGenerator = new Random();
        for(int i=0; i<amountOfDots; i++)
        {
            xDot[i] = randomNumberGenerator.Next(0,760);
            yDot[i] = randomNumberGenerator.Next(40,560);
            visible[i] = true;
        }
 
        int amountOfEnemies = 4;
        float[] xEnemy = { 150, 400, 500, 600 };
        float[] yEnemy = { 100, 200, 300, 400 };
        float[] incrXEnemy = { 5f, 3f, 6f, 4.5f };
 
        byte [,] map = {
            {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
            {1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
            {1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1},
            {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
            {1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1},
            {1,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,1},
            {1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1},
            {1,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1},
            {1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1},
            {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
            {1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1},
            {1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1},
            {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
        };
 
        int score = 0;
        bool gameFinished = false;
 
        // Game Loop
        while( ! gameFinished )
        {
            // Draw
            SdlHardware.ClearScreen();
            //Console.Write("Score: {0}",score);
 
            // Background map
            for(int row=0; row<15; row++)
            {
                for(int column=0; column<17; column++)
                {
                    if (map[row,column] == 1)
                        SdlHardware.DrawHiddenImage(wallImage, column*32, row*32);
                }
            }
 
            for(int i=0; i<amountOfDots; i++)
            {
                if (visible[i])
                    SdlHardware.DrawHiddenImage(dotImage, xDot[i], yDot[i]);
            }
 
            SdlHardware.DrawHiddenImage(pacImage, x, y);
 
            for(int i=0; i<amountOfEnemies; i++)
                SdlHardware.DrawHiddenImage(enemyImage, 
                    (int)xEnemy[i], (int)yEnemy[i]);
 
            SdlHardware.ShowHiddenScreen();
 
            // Read keys and calculate new position
            if (SdlHardware.KeyPressed(SdlHardware.KEY_RIGHT)) x+=pacSpeed;
            if (SdlHardware.KeyPressed(SdlHardware.KEY_LEFT)) x-=pacSpeed;
            if (SdlHardware.KeyPressed(SdlHardware.KEY_DOWN)) y+=pacSpeed;
            if (SdlHardware.KeyPressed(SdlHardware.KEY_UP)) y-=pacSpeed;
 
            if (SdlHardware.KeyPressed(SdlHardware.KEY_ESC)) 
                gameFinished = true;
 
            // Move enemies and environment
            for(int i=0; i<amountOfEnemies; i++)
            {
                xEnemy[i] += incrXEnemy[i];
                if ((xEnemy[i] < 1) || (xEnemy[i] > 760))
                    incrXEnemy[i] = -incrXEnemy[i];
            }
 
            // Collisions, lose energy or lives, etc
            for(int i=0; i<amountOfDots; i++)
                if ( visible[i] &&
                    (x > xDot[i] - 32) && 
                    (x < xDot[i] + 32) &&
                    (y > yDot[i] - 32) && 
                    (y < yDot[i] + 32)
                    )
                {
                    score += 10;
                    visible[i] = false;
                }
 
            // Pause till next fotogram
            SdlHardware.Pause(40);
        }
    }
}
 

Which would look this way:

Appearance of Game02d - all the dots

And as we "eat" dots, the labyrinth will become more visible:

Appearance of Game02d - fewer dots


If we have many different kinds of tiles, it might be easier to "see" the labyrinth when we have a look at our source code, if we use "chars" instead of numbers to define the map:

char [,] map = {
    {'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-'},
    {'-','.','.','.','.','.','.','.','-','.','.','.','.','.','.','.','-'},
    {'-','.','-','-','.','-','-','.','-','.','-','-','.','-','-','.','-'},
    {'-','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','-'},
    {'-','.','-','-','.','-','.','-','-','-','.','-','.','-','-','.','-'},
    {'-','.','.','.','.','-','.','.','-','.','.','-','.','.','.','.','-'},
    {'-','-','-','-','.','-','-','.','.','.','-','-','.','-','-','-','-'},
    {'.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'},
    {'-','-','-','-','.','-','.','-','.','-','.','-','.','-','-','-','-'},
    {'-','.','.','.','.','-','.','-','.','-','.','-','.','.','.','.','-'},
    {'-','.','-','-','.','-','.','-','-','-','.','-','.','-','-','.','-'},
    {'-','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','-'},
    {'-','.','-','-','.','-','.','-','-','-','.','-','.','-','-','.','-'},
    {'-','.','.','.','.','-','.','.','.','.','.','-','.','.','.','.','-'},
    {'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-'}
};        
 
...
 
for(int row=0; row<15; row++)
{
    for(int column=0; column<17; column++)
    {
        if (map[row,column] == '-')
            SdlHardware.DrawHiddenImage(wallImage, column*32, row*32);
    }
}
 


And even easier if we use an array of strings:

    string [] map = {
    "-----------------",
    "-.......-.......-",
    "-.--.--.-.--.--.-",
    "-...............-",
    "-.--.-.---.-.--.-",
    "-....-..-..-....-",
    "----.--...--.----",
    ".................",
    "----.-.-.-.-.----",
    "-....-.-.-.-....-",
    "-.--.-.---.-.--.-",
    "-...............-",
    "-.--.-.---.-.--.-",
    "-....-.....-....-",
    "-----------------"
};
 
...
 
for(int row=0; row<15; row++)
{
    for(int column=0; column<17; column++)
    {
        if (map[row][column] == '-')
            SdlHardware.DrawHiddenImage(wallImage, column*32, row*32);
    }
}
 

(Note that we now use "map[row][column]" to access each position, instead of "map[row,column]" as it is not a two-dimensional array any more).


There is a new image ("wall.bmp") in our project, so you can download again the whole project, including images, DLL files and the auxiliary "SdlHardware.cs" file. It is in the "Google Code" page for this project. This version is called "SdlMuncher004.zip": code.google.com/p/sdl-muncher/