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

Revision:
0:8b6686f2d4be
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pacman.h	Mon Oct 19 17:47:39 2015 +0000
@@ -0,0 +1,725 @@
+/******************************************************
+ * 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);
+        }
+};
\ No newline at end of file