Klemen's Stuff
| Pacman game | Game Logic | Generating font | Case | Source code
Making a pacman game on STM32H750B-DK
The goal of the project is to implement pacman game using C programing language. I'll be using a template project1 that allready has implemented some basic functionalities and additional drivers.
1 https://github.com/LAPSyLAB/ORLab-STM32H7/tree/main/STM32H750B-DK_BSP_C_Basic
Video of aA pacman game gameplay on STM32H750B-DK

Parts list

Pacman game

Pac-Man is a classic arcade game released in 1980 by Namco. Player controls Pac-Man, a yellow circular character, navigating through a maze while eating dots and avoiding four ghosts. There are four energizer dots, located in the corners of the maze, which temporarily turn the ghosts blue, allowing Pac-Man to eat them for extra points. The goal of the game is to get as many points as you can, before the ghosts gets you.

You can read more about the game and it's mechanich hereon https://pacman.holenet.info/.

Implementation

A classic pacman map has a grid of 31 rows and 28 columns and looks like this. Where 0 represents a wall, 1 represents a path, 2 represents a dot and 3 represents an energizer dot.

The player spawn at row 24, ghosts spawns at row 12, and "fruits" spawn at row 18. All between column 14 and 15.

The logic behind the game is pretty straight forward, we just check in what cell we are in, and move to the next one if it's not a wall. A player needs some extra logic to collect the dots and fruits, and ghost needs to move around on their own.

The game goes on until one of the ghosts colides with a player. In a classic game, you loose a life, but in my implementation you loose the game.

Game Logic

To simplify draw calls so we don't need multiple layers, we draw grid, arrows, "score" text, "high score" text and dots once at the start of the game.

Player

Player logic is pretty straight forward. We just need to check if it can move in a given direction, and update the score. Most other things in the following functions are just translations between pixels and grid. The only special part is the "tunnel" where we just teleport the player on the other side of the map by updating it's position in grid and on screen. We also need to implement touch controlls for the player. We could connect a physical buttons or a joystick to the MCU, but since it has a touch display we can implenet movement by creating sections in display.

I decided to have up and down on both sides of the screen, so it's easier to play the game.

Even though I set the touchscreen size the same as the screen, we still need to check if the given position is less than the screen.

Ghost

Ghost logic is pretty much the same as the player logic. The three differences are that it doesn't need to update the score, that it has to redraw dots and that it randomly decides in what directions the ghost will move next at the intersections. For ghosts 2, 3 and 4, we need to implenet wait functions. The ghosts waits until player has left 150 dots, 100 dots and 50 dots respectedly, and then get's moved to a ghost starting position so they can continue their jurney. When the energizer is not active, the ghost is just checking if the player is colliding with it and it sets game over. But when the energizer is active a gray color is drawn, and the score is adjusted acordingly if the player eats the ghost.

The energizer is active for around 9 seconds, and then normal functionality of a ghost is resumed.

Fruit

Fruits spawns twice per level, once at 174 dots left and second time at 74 dots left and despawn after around 9 seconds. The only thing that fruit does, is checking if the player is at it's position and increases the score if it is, drawing itself and despawning if it's not collected in time. This function only clears fruit from the screen and sets the fruit function to empty function so the fruit is not active anymore.

Comment

The game would run smoother if CPU cache was enabled, but it was causing unexpected bugs so I had to turn it off.

The screen is pretty small, so creating animations for ghosts and a player was not "wroth it" since it wouldn't be that noticable, but the performance would be slithly worse.

There is also a bug that a player will change direction on a last button press, even if the press happened a while ago, so instead of trying to fix it I decided it will be a feature so you can pre-move your next move.

Things for STM32

Generating font

I wanted a font with arrow keys, so I look online and found thishttps://github.com/zst-embedded/STM32-LCD_Font_Generator project by zst-embedded, that generates font with python. The code didn't work since there was a lot of changes in the libraries used and I had to change a few things to make it work.

More specificly this function of PIL library that was deprecated: to this and while I was at it, I also added a few more functionalities, like character offset and generating source files (.c) instead of just header files (.h).

Case for the MCU

Since standalone STM32H750B-DK is not the most comfortable thing to hold in hands so I also designed a cases for easier useage of it. The case can be easily opened from the back to access board connectors that are on the back, all other connectors that are on the side are also accessible.

Before printing the case needs to be scaled to match 3D printer tolerances by up to 1%, since it's designed 1:1 with the CAD files that I found herehttps://www.st.com/en/evaluation-tools/stm32h750b-dk.html#cad-resources. Otherwise you will need a lot of sanding if you decide not to do so.

You will need 4 screws. I'm using Ø2.5 10 mm with a head hight of 2.5mm that I had laying around.

The case was designed in blender and you can find it hereon https://makerworld.com/en/models/517051.

Case - front side
Case - back side
Case - opened