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
Diff: Pacman.h
- 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