Multi-game multiplayer arcade gaming system meant for the red X when playing Super Tic-Tac-Toe.

Dependencies:   uLCD_4DGL_SE PinDetect SDFileSystem mbed wave_player

Pacman.h

Committer:
soapy12312
Date:
2015-12-04
Revision:
2:d35fde2d82cd
Parent:
0:218d3fb75950

File content as of revision 2:d35fde2d82cd:

/******************************************************
 * This header program declares all the functions and
 * variables used by the Pac-Man player in Pac-Man.
 ******************************************************/


#define DIE     "/sd/Die.wav"
#define THEME   "/sd/Theme.wav"


// Pacman class
class Pacman {
    public:
        // Pac-Man constructor
        Pacman(PinDetect &PacmanRight, PinDetect &PacmanDown, PinDetect &PacmanLeft, PinDetect &PacmanUp, Stage &stage, uLCD_4DGL &uLCD, wave_player &waver) :
            PacmanRight(PacmanRight), PacmanDown(PacmanDown), PacmanLeft(PacmanLeft), PacmanUp(PacmanUp), stage(stage), uLCD(uLCD), waver(waver) {
            // Use internal pullups
            PacmanRight.mode(PullUp);
            PacmanDown.mode(PullUp);
            PacmanLeft.mode(PullUp);
            PacmanUp.mode(PullUp);
            wait(0.01);
            // Interrupt callback functions
            PacmanRight.attach_deasserted(this, &Pacman::PacmanRightTrigger);
            PacmanDown.attach_deasserted(this, &Pacman::PacmanDownTrigger);
            PacmanLeft.attach_deasserted(this, &Pacman::PacmanLeftTrigger);
            PacmanUp.attach_deasserted(this, &Pacman::PacmanUpTrigger);
            wait(0.01);
            // Set sampling frequency
            PacmanRight.setSampleFrequency();
            PacmanDown.setSampleFrequency();
            PacmanLeft.setSampleFrequency();
            PacmanUp.setSampleFrequency();
            wait(1);
        }

        // Play a sound file
        void playSound(char *wav) {
            // Open sound file
            FILE *wave_file;
            wave_file = fopen(wav, "r");

            // Play wav file
            waver.play(wave_file);

            // Close wav file
            fclose(wave_file);
        }

        // Initialize Pac-Man at the start of the game
        void initialize() {
            x = 64;
            y = 108;
            lives = 3;
            livesChanged = true;
            score = 0;
            scoreChanged = true;
            direction = FACEUP;
            mouthOpen = false;
            pacDotsEaten = 0;
            bigPacDotsEaten = 0;
            powerUp = 0;
            powerUpChanged = false;
            ghostsEaten = 0;
            dead = false;
            draw(x, y);
            displayStatus();
        }

        // Display score and number of lives remaining
        void displayStatus() {
            // If the number of lives just changed
            if (livesChanged == true) {
                // Draw the corresponding number of lives
                switch (lives) {
                    case 3:
                        drawLives(56, 12);
                        drawLives(64, 12);
                        drawLives(72, 12);
                        break;
                    case 2:
                        erase(72, 12);
                        drawLives(56, 12);
                        drawLives(64, 12);
                        break;
                    case 1:
                        erase(56, 12);
                        drawLives(64, 12);
                        break;
                    default:
                        break;
                }

                // Reset livesChanged
                livesChanged = false;
            }

            // If the score just changed
            if (scoreChanged == true) {
                // Print the new score
                uLCD.locate(0, 1);
                uLCD.printf("%d", score);
                scoreChanged = false;
            }

            // Print the invincibility counter
            uLCD.locate(14, 1);

            if (powerUp == 100) {
                uLCD.printf("100");
            } else if (powerUp >= 10) {
                uLCD.printf(" %d", powerUp);
            } else {
                uLCD.printf("  %d", powerUp);
            }
        }

        // Move Pac-Man and return whether the game is over
        bool move() {
            // If all the pac dots are eaten or Pac-Man is out of lives
            if (((pacDotsEaten == stage.pacDots) &&
                (bigPacDotsEaten == stage.bigPacDots)) ||
                (lives == 0)) {
                // Return true that the game is over and exit out of the function
                return true;
            }

            // If Pac-Man is not invincible
            if (powerUp == 0) {
                // Reset the ghosts eaten counter
                ghostsEaten = 0;
            }

            // If Pac-Man is invincible
            if (powerUp > 0) {
                // Decrement the invincibility counter
                powerUp--;

                // If invincibility just ended or just started
                if ((powerUp == 0) || (powerUp == 99)) {
                    // Changes the color of the ghosts
                    powerUpChanged = true;
                // If invincibility did not just end or did not just start
                } else {
                    // Set powerUpChanged to false
                    powerUpChanged = false;
                }
            }

            // Move Pac-Man in his current direction
            switch (direction) {
                case FACERIGHT:
                    moveRight();
                    break;
                case FACEDOWN:
                    moveDown();
                    break;
                case FACELEFT:
                    moveLeft();
                    break;
                case FACEUP:
                    moveUp();
                    break;
                default:
                    break;
            }

            // Return false that the game is over
            return false;
        }

        // Game over
        void gameOver() {
            // If all the pac dots have been eaten
            if ((pacDotsEaten == stage.pacDots) &&
                (bigPacDotsEaten == stage.bigPacDots)) {
                // Pac-Man wins
                win();
            // If the number of lives is 0
            } else if (lives == 0) {
                // Pac-Man loses
                lose();
            }
        }


    private:
        PinDetect &PacmanRight;
        PinDetect &PacmanDown;
        PinDetect &PacmanLeft;
        PinDetect &PacmanUp;
        Stage &stage;
        uLCD_4DGL &uLCD;
        wave_player &waver;
        int x;
        int y;
        int direction;
        volatile int nextDirection;
        int lives;
        bool livesChanged;
        int score;
        bool scoreChanged;
        bool mouthOpen;
        int pacDotsEaten;
        int bigPacDotsEaten;
        int powerUp;
        bool powerUpChanged;
        int ghostsEaten;
        bool dead;
        friend class Ghost;

        // Set the next Pac-Man direction to be right
        void PacmanRightTrigger() {
            nextDirection = FACERIGHT;
        }

        // Set the next Pac-Man direction to be down
        void PacmanDownTrigger() {
            nextDirection = FACEDOWN;
        }

        // Set the next Pac-Man direction to be left
        void PacmanLeftTrigger() {
            nextDirection = FACELEFT;
        }

        // Set the next Pac-Man direction to be up
        void PacmanUpTrigger() {
            nextDirection = FACEUP;
        }

        // Draw the Pac-Man to display lives
        void drawLives(int xCoordinate, int yCoordinate) {
            uLCD.filled_circle(xCoordinate, yCoordinate, 3, YELLOW);
            int x1 = xCoordinate - 2;
            int x2 = xCoordinate - 3;
            int y1 = yCoordinate - 1;
            int y2 = yCoordinate + 1;
            uLCD.rectangle(x1, y1, x2, y2, BLACK);
            uLCD.pixel(xCoordinate, yCoordinate, BLACK);
            uLCD.pixel(xCoordinate - 1, yCoordinate, BLACK);
        }

        // Draw Pac-Man based on his direction
        void draw(int xCoordinate, int yCoordinate) {
            // If his mouth is closed
            if (mouthOpen == false) {
                // Draw Pac-Man with his mouth closed as a circle
                uLCD.filled_circle(xCoordinate, yCoordinate, 3, YELLOW);
            // If his mouth is open
            } else {
                // Draw Pac-Man with his mouth open based on his direction
                int x1;
                int x2;
                int y1;
                int y2;

                switch (direction) {
                    case FACERIGHT:
                        uLCD.filled_circle(xCoordinate, yCoordinate, 3, YELLOW);
                        x1 = xCoordinate + 2;
                        x2 = xCoordinate + 3;
                        y1 = yCoordinate - 1;
                        y2 = yCoordinate + 1;
                        uLCD.rectangle(x1, y1, x2, y2, BLACK);            
                        uLCD.pixel(xCoordinate, yCoordinate, BLACK);
                        uLCD.pixel(xCoordinate + 1, yCoordinate, BLACK);
                        break;
                    case FACEDOWN:
                        uLCD.filled_circle(xCoordinate, yCoordinate, 3, YELLOW);
                        x1 = xCoordinate - 1;
                        x2 = xCoordinate + 1;
                        y1 = yCoordinate + 2;
                        y2 = yCoordinate + 3;
                        uLCD.rectangle(x1, y1, x2, y2, BLACK);
                        uLCD.pixel(xCoordinate, yCoordinate, BLACK);
                        uLCD.pixel(xCoordinate, yCoordinate + 1, BLACK);
                        break;
                    case FACELEFT:
                        uLCD.filled_circle(xCoordinate, yCoordinate, 3, YELLOW);
                        x1 = xCoordinate - 2;
                        x2 = xCoordinate - 3;
                        y1 = yCoordinate - 1;
                        y2 = yCoordinate + 1;
                        uLCD.rectangle(x1, y1, x2, y2, BLACK);
                        uLCD.pixel(xCoordinate, yCoordinate, BLACK);
                        uLCD.pixel(xCoordinate - 1, yCoordinate, BLACK);
                        break;
                    case FACEUP:
                        uLCD.filled_circle(xCoordinate, yCoordinate, 3, YELLOW);
                        x1 = xCoordinate - 1;
                        x2 = xCoordinate + 1;
                        y1 = yCoordinate - 2;
                        y2 = yCoordinate - 3;
                        uLCD.rectangle(x1, y1, x2, y2, BLACK);
                        uLCD.pixel(xCoordinate, yCoordinate, BLACK);
                        uLCD.pixel(xCoordinate, yCoordinate - 1, BLACK);
                        break;
                    default:
                        break;
                }
            }
        }

        // Erase Pac-Man from the given position
        void erase(int xCoordinate, int yCoordinate) {
            uLCD.filled_circle(xCoordinate, yCoordinate, 3, BLACK);
        }

        // Move Pac-Man right
        void moveRight() {
            // If the space to the right is a valid positions and is not the rightmost space
            if ((stage.positions[x + 1][y] != 0) && (x != 124)) {
                // Erase Pac-Man from his current position
                erase(x, y);
                // Increment Pac-Man's x-coordinate
                x++;
                // Draw Pac-Man in his new position
                draw(x, y);
                // Alternate Pac-Man's mouth for animation
                mouthOpen = !mouthOpen;

                // If Pac-Man passes partially across a big pac dot
                if (stage.positions[x - 5][y] == 3) {
                    // Redraw the big pac dot part
                    uLCD.pixel(x - 4, y, YELLOW);
                }

                // Loop through Pac-Man's 7-pixel diameter
                for (int i = x - 3; i <= x + 3; i++) {
                    // If a pac dot is eaten
                    if (stage.positions[i][y] == 2) {
                        // Increment the number of pac dots eaten
                        pacDotsEaten++;
                        // Add 10 to the score
                        score += 10;
                        // Set the coordinates to represent only a valid position
                        stage.positions[i][y] = 1;
                        // Changes the score display
                        scoreChanged = true;
                    // If a big pac dot is eaten
                    } else if (stage.positions[i][y] == 3) {
                        // Erase the rest of the big pac dot
                        uLCD.pixel(x + 4, y, BLACK);
                        // Increment the number of big pac dots eaten
                        bigPacDotsEaten++;
                        // Add 50 to the score
                        score += 50;
                        // Set the coordinates to represent only a valid position
                        stage.positions[i][y] = 1;
                        // Set the invincibility counter to 100
                        powerUp = 100;
                        // Changes the score display
                        scoreChanged = true;
                    }
                }
            // If the space to the right is not a valid position
            } else if (stage.positions[x + 1][y] == 0) {
                // Draw Pac-Man with his mouth open
                uLCD.rectangle(x + 2, y - 1, x + 3, y + 1, BLACK);            
                uLCD.pixel(x, y, BLACK);
                uLCD.pixel(x + 1, y, BLACK);
                wait(0.001);
            }

            // If the rightmost space is reached
            if (x == 124) {
                // Erase Pac-Man from his current position
                erase(x, y);
                // Set Pac-Man's x-coordinate to 4
                x = 4;
                // Draw Pac-Man in his new positions
                draw(x, y);
            }

            // Set Pac-Man's next direction
            switch (nextDirection) {
                case FACEDOWN:
                    if (stage.positions[x][y + 1] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACELEFT:
                    if (stage.positions[x - 1][y] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACEUP:
                    if (stage.positions[x][y - 1] != 0) {
                        direction = nextDirection;
                    }

                    break;
                default:
                    break;
            }
        }

        // Move Pac-Man down
        void moveDown() {
            // If the space in the downward direction is a valid position
            if (stage.positions[x][y + 1] != 0) {
                // Erase Pac-Man from his current position
                erase(x, y);
                // Increment Pac-Man's y-coordinate
                y++;
                // Draw Pac-Man in his new position
                draw(x, y);
                // Alternate Pac-Man's mouth for animation
                mouthOpen = !mouthOpen;

                // If Pac-Man passes partially through a big pac dot
                if (stage.positions[x][y - 5] == 3) {
                    // Redraw the big pac dot part
                    uLCD.pixel(x, y - 4, YELLOW);
                }

                // Loop through Pac-Man's 7-pixel diameter
                for (int j = y - 3; j <= y + 3; j++) {
                    // If a pac dot is eaten
                    if (stage.positions[x][j] == 2) {
                        // Increment the number of pac dots eaten
                        pacDotsEaten++;
                        // Add 10 to the score
                        score += 10;
                        // Set the position to represent only a valid position
                        stage.positions[x][j] = 1;
                        // Changes the score display
                        scoreChanged = true;
                    // If a big pac dot is eaten
                    } else if (stage.positions[x][j] == 3) {
                        // Erase the rest of the big pac dot
                        uLCD.pixel(x, y + 4, BLACK);
                        // Increment the number of big pac dots eaten
                        bigPacDotsEaten++;
                        // Add 50 to the score
                        score += 50;
                        // Set the coordinates to represent only a valid position(1)
                        stage.positions[x][j] = 1;
                        // Set the invincibility counter to 100
                        powerUp = 100;
                        // Changes the score display
                        scoreChanged = true;
                    }
                }
            // If the space in the downward direction is not a valid position
            } else {
                // Draw Pac-Man with his mouth open
                uLCD.rectangle(x - 1, y + 2, x + 1, y + 3, BLACK);
                uLCD.pixel(x, y, BLACK);
                uLCD.pixel(x, y + 1, BLACK);
                wait(0.001);
            }

            // Set Pac-Man's next direction
            switch (nextDirection) {
                case FACERIGHT:
                    if (stage.positions[x + 1][y] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACELEFT:
                    if (stage.positions[x - 1][y] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACEUP:
                    if (stage.positions[x][y - 1] != 0) {
                        direction = nextDirection;
                    }

                    break;
                default:
                    break;
            }
        }

        // Move Pac-Man left
        void moveLeft() {
            // If the space to the left is a valid position and is not the leftmost space
            if ((stage.positions[x - 1][y] != 0) && (x != 4)) {
                // Erase Pac-Man from his current position
                erase(x, y);
                // Decrement Pac-Man's x-coordinate
                x--;
                // Draw Pac-Man in his new position
                draw(x, y);
                // Alternate Pac-Man's mouth for animation
                mouthOpen = !mouthOpen;

                // If Pac-Man passes partially through a big pac dot
                if (stage.positions[x + 5][y] == 3) {
                    // Redraw the big pac dot part
                    uLCD.pixel(x + 4, y, YELLOW);
                }

                // Loop through Pac-Man's 7-pixel diameter
                for (int i = x + 3; i >= x - 3; i--) {
                    // If a pac dot is eaten
                    if (stage.positions[i][y] == 2) {
                        // Increment the number of pac dots eaten
                        pacDotsEaten++;
                        // Add 10 to the score
                        score += 10;
                        // Set the coordinates to represent only a valid position
                        stage.positions[i][y] = 1;
                        // Changes the score display
                        scoreChanged = true;
                    // If a big pac dot is eaten
                    } else if (stage.positions[i][y] == 3) {
                        // Erase the rest of the big pac dot
                        uLCD.pixel(x - 4, y, BLACK);
                        // Increment the number of big pac dots eaten
                        bigPacDotsEaten++;
                        // Add 50 to the score
                        score += 50;
                        // Set the coordinates to represent only a valid position
                        stage.positions[i][y] = 1;
                        // Set the invincibility counter to 100
                        powerUp = 100;
                        // Changes the score display
                        scoreChanged = true;
                    }
                }
            // If the space to the left is not a valid position
            } else if (stage.positions[x - 1][y] == 0) {
                // Draw Pac-Man with his mouth open
                uLCD.rectangle(x - 2, y - 1, x - 1, y + 1, BLACK);
                uLCD.pixel(x, y, BLACK);
                uLCD.pixel(x - 1, y, BLACK);
                wait(0.001);
            }

            // If the leftmost position is reached
            if (x == 4) {
                // Erase Pac-Man from his current position
                erase(x, y);
                // Set Pac-Man's x-coordinate to 124
                x = 124;
                // Draw Pac-Man in his new position
                draw(x, y);
            }

            // Set Pac-Man's next direction
            switch (nextDirection) {
                case FACERIGHT:
                    if (stage.positions[x + 1][y] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACEDOWN:
                    if (stage.positions[x][y + 1] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACEUP:
                    if (stage.positions[x][y - 1] != 0) {
                        direction = nextDirection;
                    }

                    break;
                default:
                    break;
            }
        }

        // Move Pac-Man up
        void moveUp() {
            // If the space in the upward direction is a valid position
            if (stage.positions[x][y - 1] != 0) {
                // Erase Pac-Man from his current position
                erase(x, y);
                // Decrement Pac-Man's y-coordinate
                y--;
                // Draw Pac-Man in his new position
                draw(x, y);
                // Alternate Pac-Man's mouth for animation
                mouthOpen = !mouthOpen;

                // If Pac-Man passes partially through a big pac dot
                if (stage.positions[x][y + 5] == 3) {
                    // Redraw the big pac dot part
                    uLCD.pixel(x, y + 4, YELLOW);
                }

                // Loop through Pac-Man's 7-pixel diameter
                for (int j = y + 3; j >= y - 3; j--) {
                    // If a pac dot is eaten
                    if (stage.positions[x][j] == 2) {
                        // Increment the number of pac dots eaten
                        pacDotsEaten++;
                        // Add 10 to the score
                        score += 10;
                        // Set the coordinates to represent only a valid position
                        stage.positions[x][j] = 1;
                        // Changes the score display
                        scoreChanged = true;
                    // If a big pac dot is eaten
                    } else if (stage.positions[x][j] == 3) {
                        // Erase the reset of the big pac dot
                        uLCD.pixel(x, y - 4, BLACK);
                        // Increment the number of big pac dots eaten
                        bigPacDotsEaten++;
                        // Add 50 to the score
                        score += 50;
                        // Set the coordinates to represent only a valid position
                        stage.positions[x][j] = 1;
                        // Set the invincibility counter to 100
                        powerUp = 100;
                        // Changes the score display
                        scoreChanged = true;
                    }
                }
            // If the space in the upward direction is not a valid position
            } else {
                // Draw Pac-Man with his mouth open
                uLCD.rectangle(x - 1, y - 2, x + 1, y - 3, BLACK);
                uLCD.pixel(x, y, BLACK);
                uLCD.pixel(x, y - 1, BLACK);
                wait(0.001);
            }

            // Set Pac-Man's next direction
            switch (nextDirection) {
                case FACERIGHT:
                    if (stage.positions[x + 1][y] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACEDOWN:
                    if (stage.positions[x][y + 1] != 0) {
                        direction = nextDirection;
                    }

                    break;
                case FACELEFT:
                    if (stage.positions[x - 1][y] != 0) {
                        direction = nextDirection;
                    }

                    break;
                default:
                    break;
            }
        }

        // Dying animation
        void dyingAnimation() {   
            erase(x, y);         
            draw(x, y);
            uLCD.rectangle(x - 1, y - 2, x + 1, y - 3, BLACK);
            uLCD.pixel(x, y, BLACK);
            uLCD.pixel(x, y - 1, BLACK);

            uLCD.pixel(x - 1, y, BLACK);
            uLCD.pixel(x - 1, y - 1, BLACK);
            uLCD.pixel(x - 2, y - 2, BLACK);
            uLCD.pixel(x + 1, y, BLACK);
            uLCD.pixel(x + 1, y - 1, BLACK);
            uLCD.pixel(x + 2, y - 2, BLACK);
            wait(0.15);

            uLCD.pixel(x - 2, y, BLACK);
            uLCD.pixel(x - 3, y, BLACK);
            uLCD.pixel(x - 2, y - 1, BLACK);
            uLCD.pixel(x - 3, y - 1, BLACK);
            uLCD.pixel(x + 2, y, BLACK);
            uLCD.pixel(x + 3, y, BLACK);
            uLCD.pixel(x + 2, y - 1, BLACK);
            uLCD.pixel(x + 3, y - 1, BLACK);
            wait(0.15);

            uLCD.pixel(x - 1, y + 1, BLACK);
            uLCD.pixel(x - 2, y + 1, BLACK);
            uLCD.pixel(x - 3, y + 1, BLACK);
            uLCD.pixel(x - 2, y + 2, BLACK);
            uLCD.pixel(x + 1, y + 1, BLACK);
            uLCD.pixel(x + 2, y + 1, BLACK);
            uLCD.pixel(x + 3, y + 1, BLACK);
            uLCD.pixel(x + 2, y + 2, BLACK);
            wait(0.15);

            uLCD.pixel(x - 1, y + 2, BLACK);
            uLCD.pixel(x - 1, y + 3, BLACK);
            uLCD.pixel(x + 1, y + 2, BLACK);
            uLCD.pixel(x + 1, y + 3, BLACK);
            wait(0.15);

            uLCD.pixel(x, y + 1, BLACK);
            uLCD.pixel(x, y + 2, BLACK);
            uLCD.pixel(x, y + 3, BLACK);
            wait(0.15);
        }

        // Reinitialize Pac-Man after losing a life
        void reinitialize() {
            // Set Pac-Man's x-coordinate to the starting point
            x = 64;
            // Set Pac-Man's y-coordinate to the starting point
            y = 108;
            // Redraw the pac dots on the stage
            stage.redrawPacDots();
            // Changes the lives display
            livesChanged = true;
            // Draw Pac-Man at his starting point
            draw(x, y);
            // Display the lives and score counter
            displayStatus();
        }

        // Pac-Man dies
        void die() {
            // Decrement the number of lives
            lives--;
            // Erase Pac-Man from his current position
            erase(x, y);
            // Reset Pac-Man's direction to be up
            direction = FACEUP;
            // Displays Pac-Man's dying animation
            dyingAnimation();
            // Play dying sound
            playSound(DIE);

            // If the number of lives is 0
            if (lives == 0) {
                // Break out of the function
                return;
            }

            // Reinitialize Pac-Man
            reinitialize();
        }

        // Pac-Man wins
        void win() {
            uLCD.cls();
            uLCD.filled_rectangle(0, 0, 127, 127, BLACK);
            uLCD.locate(3, 7);
            uLCD.printf("Pac-Man wins.\n");
            uLCD.locate(3, 8);
            uLCD.printf("Score: %d", score);
        }

        // Pac-Man loses
        void lose() {
            uLCD.cls();
            uLCD.filled_rectangle(0, 0, 127, 127, BLACK);
            uLCD.locate(2, 7);
            uLCD.printf("Pac-Man loses.\n");
            uLCD.locate(3, 8);
            uLCD.printf("Score: %d", score);
        }
};