20. Function for collisions

Right now, our source code is too repetitive. For example, we do the following when we try to move to the right:

if (SdlHardware.KeyPressed(SdlHardware.KEY_RIGHT))
{
    bool canMove = true;
    for (int row = 0; row < 15; row++)
    {
        for (int column = 0; column < 17; column++)
        {
            if (map[row][column] == '-')
                if ((x + pacSpeed > column * 32 - 32) &&
                    (x + pacSpeed < column * 32 + 32) &&
                    (y > row * 32 - 32) &&
                    (y < row * 32 + 32)
                    )
                {
                    canMove = false;
                }
        }
    }
    if (canMove)
        x += pacSpeed;
}
 

And almost the same (and that's 21 lines of code!) when we try to move to the left:

if (SdlHardware.KeyPressed(SdlHardware.KEY_LEFT))
{
    bool canMove = true;
    for (int row = 0; row < 15; row++)
    {
        for (int column = 0; column < 17; column++)
        {
            if (map[row][column] == '-')
                if ((x - pacSpeed > column * 32 - 32) &&
                    (x - pacSpeed < column * 32 + 32) &&
                    (y > row * 32 - 32) &&
                    (y < row * 32 + 32)
                    )
                {
                    canMove = false;
                }
        }
    }
    if (canMove)
        x -= pacSpeed;
}
 

We can make it simpler if we create a function called "CanMoveTo", to tell us if we can move to a certain coordinates on screen. If we assume that the width and height of every tile and character is 32, we might just pass it as parameters the position (X and Y) to check, and the map, and it would return "true" if we can move to those coordinates or "false" if we cannot (because there is a piece of wall):

 

So the structure for the keys checking would become:

if (SdlHardware.KeyPressed(SdlHardware.KEY_RIGHT)
        && CanMoveTo(x + pacSpeed, y, map))
    x += pacSpeed;
 
if (SdlHardware.KeyPressed(SdlHardware.KEY_LEFT)
        && CanMoveTo(x - pacSpeed, y, map))
    x -= pacSpeed;
 
...
 


The resulting program would be over 50 lines shorter than the previous version:

/*
  First mini-graphics-game skeleton
  Version J: function CanMoveTo
*/
 
using System;
 
public class Game02j
{
    public static void Init()
    {
        bool fullScreen = false;
        SdlHardware.Init(800, 600, 24, fullScreen);
    }
 
    public static void Intro()
    {
        Image pac = new Image("pac01r.bmp");
        Image ghost = new Image("ghostGreen.bmp");
        int x = -40;
        do
        {
            SdlHardware.ClearScreen();
            SdlHardware.DrawHiddenImage(ghost, x - 50, 300);
            SdlHardware.DrawHiddenImage(pac, x, 300);
            SdlHardware.ShowHiddenScreen();
            x += 8;
            if (x > 850) x = -40;
            SdlHardware.Pause(20);
        }
        while (!SdlHardware.KeyPressed(SdlHardware.KEY_SPC));
    }
 
    public static bool CanMoveTo(int x, int y, string[] map)
    {
        bool canMove = true;
        for (int row = 0; row < 15; row++)
        {
            for (int column = 0; column < 17; column++)
            {
                if (map[row][column] == '-')
                    if ((x > column * 32 - 32) &&
                        (x < column * 32 + 32) &&
                        (y > row * 32 - 32) &&
                        (y < row * 32 + 32)
                        )
                    {
                        canMove = false;
                    }
            }
        }
        return canMove;
    }
 
    public static void Main()
    {
        Init();
 
        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 = 32, y = 32;
        int pacSpeed = 4;
 
        int amountOfEnemies = 4;
        float[] xEnemy = { 150, 400, 500, 600 };
        float[] yEnemy = { 100, 200, 300, 400 };
        float[] incrXEnemy = { 5f, 3f, 6f, 4.5f };
 
        string[] map = {
            "-----------------",
            "-.......-.......-",
            "-.--.--.-.--.--.-",
            "-...............-",
            "-.--.-.---.-.--.-",
            "-....-..-..-....-",
            "----.--...--.----",
            ".................",
            "----.-.-.-.-.----",
            "-....-.-.-.-....-",
            "-.--.-.---.-.--.-",
            "-...............-",
            "-.--.-.---.-.--.-",
            "-....-.....-....-",
            "-----------------"
        };
 
        // Data for the dots
        // First: count how many
        int amountOfDots = 0;
        for (int row = 0; row < 15; row++)
        {
            for (int column = 0; column < 17; column++)
            {
                if (map[row][column] == '.')
                    amountOfDots++;
            }
        }
        int[] xDot = new int[amountOfDots];
        int[] yDot = new int[amountOfDots];
        bool[] visible = new bool[amountOfDots];
        // Now, assign their coordinates
        int currentDot = 0;
        for (int row = 0; row < 15; row++)
        {
            for (int column = 0; column < 17; column++)
            {
                if (map[row][column] == '.')
                {
                    xDot[currentDot] = column * 32;
                    yDot[currentDot] = row * 32;
                    visible[currentDot] = true;
                    currentDot++;
                }
            }
        }
 
 
        int score = 0;
        bool gameFinished = false;
 
        Intro();
 
        // 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] == '-')
                        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)
                    && CanMoveTo(x + pacSpeed, y, map))
                x += pacSpeed;
 
            if (SdlHardware.KeyPressed(SdlHardware.KEY_LEFT)
                    && CanMoveTo(x - pacSpeed, y, map))
                x -= pacSpeed;
 
            if (SdlHardware.KeyPressed(SdlHardware.KEY_DOWN)
                    && CanMoveTo(x, y + pacSpeed, map))
                y += pacSpeed;
 
            if (SdlHardware.KeyPressed(SdlHardware.KEY_UP)
                    && CanMoveTo(x, y - pacSpeed, map))
                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);
        }
    }
}