2021-09-28 11:40:09 +00:00
|
|
|
# Pac-Man
|
|
|
|
|
|
|
|
The project is split into three parts (solutions).
|
|
|
|
|
|
|
|
- **libpacman** - This is where the entire game lives
|
2021-10-05 08:37:48 +00:00
|
|
|
- **pacman** - This is the project that generates the executable, the only thing it does is to create the game instance
|
|
|
|
and call the `run()` function
|
2021-09-28 11:40:09 +00:00
|
|
|
- **pacman_tests** - All of the unit tests for the game
|
|
|
|
|
|
|
|
## libpacman
|
|
|
|
|
|
|
|
The libpacman solution has 3 main parts.
|
|
|
|
|
|
|
|
- **Game** - A class that holds the Canvas and GameState objects
|
|
|
|
- **Canvas** - A class that uses the SFML library to draw objects to the screen. Also manages the game window
|
2021-10-05 08:37:48 +00:00
|
|
|
- **GameState** - A class that holds all of the state for Pac-Man. Contains classes like the Ghosts, PacMan and the
|
|
|
|
Pellets PacMan eats
|
2021-09-28 11:40:09 +00:00
|
|
|
|
|
|
|
## Updating the game state
|
|
|
|
|
2021-10-05 08:37:48 +00:00
|
|
|
Within the `Game.cpp` file there is a function called `run()`, this function draws the current game state to
|
|
|
|
screen `canvas.update(gameState);` but it only calls the game state update function at a fixed interval, it also sends
|
|
|
|
this interval to the game state update function `gameState.step(delta_time);`
|
2021-09-28 11:40:09 +00:00
|
|
|
|
2021-10-05 08:37:48 +00:00
|
|
|
Then in the `step()` function in `GameState.cpp` the magic happens. Each object in the game world is updated and the
|
|
|
|
state of the game world is checked. Did Pac-Man just eat a pellet? Are the ghosts touching Pac-Man? Which direction is
|
|
|
|
Pac-Man moving?
|
2021-09-28 11:40:09 +00:00
|
|
|
|
|
|
|
## The game board
|
|
|
|
|
2021-10-05 08:37:48 +00:00
|
|
|
The game board is stored as a two dimensional array of integers in the `Board.cpp` file. The array itself is only
|
|
|
|
accessible within that file, which is why we export helper functions that use the array as a global variable. This
|
|
|
|
exporting happens in `Board.hpp`
|
2021-09-28 11:40:09 +00:00
|
|
|
|
|
|
|
## Ghosts
|
|
|
|
|
2021-10-05 08:37:48 +00:00
|
|
|
All ghosts inherit from the parent Ghost class defined in `Ghost.hpp/cpp`, there are a couple of pure virtual functions
|
|
|
|
those ghosts need to implement, otherwise you are not able to create an instance of them. A ghost stores its current
|
|
|
|
location, its current target and other state regarding if it is frightened or not. At each `update()` call a ghost needs
|
|
|
|
to decide what its target is and which direction it should turn next.
|
2021-09-28 11:40:09 +00:00
|
|
|
|
|
|
|
## Pac-Man
|
|
|
|
|
2021-10-05 08:37:48 +00:00
|
|
|
Pac-Man has similar state to a Ghost, like direction and position. Pac-Man's behavior is also similar in `update()` as
|
|
|
|
we need to determine where to place Pac-Man in the next game state. But the information on which direction to turn comes
|
|
|
|
from the player (or a bot).
|
2021-09-28 11:40:09 +00:00
|
|
|
|
|
|
|
## Unit tests
|
|
|
|
|
2021-10-05 08:37:48 +00:00
|
|
|
Because updates of game state and drawing the game on screen are completely separate, we can create game state within
|
|
|
|
unit tests and give it arbitrary delta time and call whatever functions we want to simulate the game being played. Most
|
|
|
|
unit tests only focus on one single class but some (like `testFruits`) use the `GameState` class.
|
2021-10-05 10:51:55 +00:00
|
|
|
|
|
|
|
## Ghosts characters and algorithms
|
|
|
|
|
|
|
|
These will probably become relevant
|
|
|
|
* https://en.wikipedia.org/wiki/Ghosts_(Pac-Man)
|
|
|
|
* [Video: Pac-Man Ghost AI Explained](https://youtu.be/ataGotQ7ir8)
|
|
|
|
* https://gameinternals.com/understanding-pac-man-ghost-behavior
|
|
|
|
* https://www.gamasutra.com/view/feature/3938/the_pacman_dossier.php?print=1
|
|
|
|
* https://www.slideshare.net/grimlockt/pac-man-6561257
|
|
|
|
* http://donhodges.com/pacman_pinky_explanation.htm
|