This program simulates a game of Pac-Man that allows for multiplayer. One player controls Pac-Man, while two other players control a red and yellow ghost using different tactile switches.

Dependencies:   4DGL-uLCD-SE PinDetect mbed

Fork of Pac-Man by Eric Xu

Pacman.h

Committer:
soapy12312
Date:
2015-10-19
Revision:
1:839f59c6d021
Parent:
0:8b6686f2d4be

File content as of revision 1:839f59c6d021:

/******************************************************
 * Author: Yuanzhe Xu
 * Institution: Georgia Institute of Technology
 * Date: October 18, 2015
 *
 * This header file declares all the functions and
 * variables needed for the Pacman object. Specific
 * Pac-Man functionalities can be found in main.cpp.
 ******************************************************/

// Pacman class
class Pacman {
    public:
        // Pac-Man constructor
        Pacman(uLCD_4DGL& uLCD, Stage& stage)
            : uLCD(uLCD), stage(stage) {
        }

        // 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();
        }

        // Set the next direction
        void setNextDirection(int next) {
            nextDirection = next;
        }

        // 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;
        }

        // 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);
            }
        }

        // 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:
        // Current horizontal position
        int x;
        // Current vertical position
        int y;
        // Current direction
        int direction;
        // Next direction
        int nextDirection;
        // Number of lives
        int lives;
        // The lives display updates when livesChanged is true
        bool livesChanged;
        // Score
        int score;
        // The score display updates when scoreChanged is true
        bool scoreChanged;
        // Mouth open or closed for animation
        bool mouthOpen;
        // Number of pac dots eaten
        int pacDotsEaten;
        // Number of big pac dots eaten
        int bigPacDotsEaten;
        // Invincibility counter
        int powerUp;
        // Changes the color of the ghosts when powerUpChanged is true
        bool powerUpChanged;
        // Number of ghosts eaten
        int ghostsEaten;
        // Ghosts reset when dead is true
        bool dead;
        // uLCD display
        uLCD_4DGL& uLCD;
        // Stage reference
        Stage& stage;
        // Set Ghost as a friend class
        friend class Ghost;

        // 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();

            // 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);
        }
};