25. Structs

As we have several dots, we are using arrays for their data. One array contains the X coordinates of the points, another array holds the Y coordinates, and the last one is for the "visible or not" propoerty of each dot:

static int[] xDot;
static int[] yDot;
static bool[] visible;
 

But this is not "natural": a dot has all these attributes, so we might gather them using a struct (we'll see other possibilities later):

struct Dot
{
    public int x;
    public int y;
    public bool visible;
}
 
static Dot[] dots;
 

From here on, we will not use "xDot[i]" but "dots[i].x" and so on, so the whole program might be:

/*
  First mini-graphics-game skeleton
  Version O: array of structs
*/
 
using System;
 
public class SdlMuncher
{
    struct Dot
    {
        public int x;
        public int y;
        public bool visible;
    }
    static Dot[] dots;
    static int amountOfDots;
 
    struct Enemy
    {
        public float x;
        public float y;
        public float xSpeed;
        public float ySpeed;
    }
    static Enemy[] enemies;
    static int amountOfEnemies;
 
    static bool sessionFinished = false;
    static int startX = 32 * 8;
    static int startY = 32 * 8;
    static int lives;
    static int x, y;
    static int pacSpeed;        
 
    static Image dotImage;
    static Image enemyImage;
    static Image pacImage;
    static Image wallImage;
 
    static string[] map = {
            "-----------------",
            "-.......-.......-",
            "-.--.--.-.--.--.-",
            "-...............-",
            "-.--.-.---.-.--.-",
            "-....-..-..-....-",
            "----.--...--.----",
            ".................",
            "----.-.-.-.-.----",
            "-....-.-.-.-....-",
            "-.--.-.---.-.--.-",
            "-...............-",
            "-.--.-.---.-.--.-",
            "-....-.....-....-",
            "-----------------"
    };
    static int score;
    static Font sans18;
 
 
    public static void Init()
    {
        bool fullScreen = false;
        SdlHardware.Init(800, 600, 24, fullScreen);
 
        dotImage = new Image("data/dot.png");
        enemyImage = new Image("data/ghostGreen.png");
        pacImage = new Image("data/pac01r.png");
        wallImage = new Image("data/wall.png");
 
        sans18 = new Font("data/Joystix.ttf", 18);
 
        // Data for the dots
        // First: count how many dots are there
        amountOfDots = 0;
        for (int row = 0; row < 15; row++)
        {
            for (int column = 0; column < 17; column++)
            {
                if (map[row][column] == '.')
                    amountOfDots++;
            }
        }
        dots = new Dot[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] == '.')
                {
                    dots[currentDot].x = column * 32;
                    dots[currentDot].y = row * 32;
                    currentDot++;
                }
            }
        }
 
        // And enemies
        amountOfEnemies = 4;
        enemies = new Enemy[amountOfEnemies];        
    }
 
 
    public static void PrepareGameStart()
    {
        // Pac coordinates and speed
        x = startX;
        y = startY;
        pacSpeed = 4;
 
        // Coordinates for the enemies        
        enemies[0].x = 150; enemies[0].y = 100; enemies[0].xSpeed = 5;
        enemies[1].x = 400; enemies[1].y = 200; enemies[1].xSpeed = 3;
        enemies[2].x = 500; enemies[2].y = 300; enemies[2].xSpeed = 6;
        enemies[3].x = 600; enemies[3].y = 400; enemies[3].xSpeed = 4.5f;
 
        // All dots must be visible
        for (int i = 0; i < amountOfDots; i++)
            dots[i].visible = true;
 
        // Resto of data for a new game
        score = 0;
        lives = 3;
    }
 
 
    public static void Intro()
    {
        Image pac = new Image("data/pac01r.png");
        Image ghost = new Image("data/ghostGreen.png");        
        int x = -40;
        bool exitIntro = false;
        do
        {
            SdlHardware.ClearScreen();
            SdlHardware.WriteHiddenText("Hit SPACE to start",
                300, 500,
                0xCC, 0xCC, 0xCC,
                sans18);
            SdlHardware.WriteHiddenText("or Q to Quit",
                340, 540,
                0x99, 0x99, 0x99,
                sans18);
            SdlHardware.DrawHiddenImage(ghost, x - 50, 300);
            SdlHardware.DrawHiddenImage(pac, x, 300);
            SdlHardware.ShowHiddenScreen();
            x += 8;
            if (x > 850) x = -40;
            SdlHardware.Pause(20);
            if (SdlHardware.KeyPressed(SdlHardware.KEY_SPC))
                exitIntro = true;
            if (SdlHardware.KeyPressed(SdlHardware.KEY_Q))
            {
                exitIntro = true;
                sessionFinished = true;
            }
        }
        while (!exitIntro);
    }
 
    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();
        Intro();
 
        while (!sessionFinished)
        {
            PrepareGameStart();
 
            // Game Loop
            bool gameFinished = false;
            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 (dots[i].visible)
                        SdlHardware.DrawHiddenImage(dotImage, dots[i].x, dots[i].y);
                }
 
                SdlHardware.DrawHiddenImage(pacImage, x, y);
 
                for (int i = 0; i < amountOfEnemies; i++)
                    SdlHardware.DrawHiddenImage(enemyImage,
                        (int)enemies[i].x, (int)enemies[i].y);
 
                SdlHardware.WriteHiddenText("Score: " + score,
                    610, 100,
                    0x80, 0x80, 0xFF,
                    sans18);
 
                SdlHardware.WriteHiddenText("Lives: " + lives,
                    610, 140,
                    0x80, 0x80, 0xFF,
                    sans18);
 
                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++)
                {
                    enemies[i].x += enemies[i].xSpeed;
                    if ((enemies[i].x < 1) || (enemies[i].x > 760))
                        enemies[i].xSpeed = -enemies[i].xSpeed;
                }
 
                // Collisions, lose energy or lives, etc
                for (int i = 0; i < amountOfDots; i++)
                    if (dots[i].visible &&
                        (x > dots[i].x - 32) &&
                        (x < dots[i].x + 32) &&
                        (y > dots[i].y - 32) &&
                        (y < dots[i].y + 32)
                        )
                    {
                        score += 10;
                        dots[i].visible = false;
                    }
 
                for (int i = 0; i < amountOfEnemies; i++)
                    if (
                        (x > enemies[i].x - 32) &&
                        (x < enemies[i].x + 32) &&
                        (y > enemies[i].y - 32) &&
                        (y < enemies[i].y + 32)
                        )
                    {
                        x = startX;
                        y = startY;
                        lives--;
                        if (lives == 0)
                            gameFinished = true;
                    }
 
                // Pause till next fotogram
                SdlHardware.Pause(40);
            } // end of game loop
 
            Intro();
 
        } // end of session
    } // end of  Main
} // end of class