Gerrit15 / 8x8Pong

this is a small project I did for school to get a version of pong running on a Raspberry Pi and a 8x8 LED matrix. Read the readme to get a deeper understanding of the code, although the code isn't too complex (or good) so any reader shouldn't have too hard of a time understanding just the code.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Setting up the matrix wires
A LED Matrix that is 8x8 has only 16 pins. 8 positive, and 8 negative. The reason this works is because you can power pin [x] and ground pin [y] and pin [x, y] will light up because it’s circuit is completed. Fortunately there is just enough (actually just 1 more) GPIO pins on the Raspberry pi to make this work. The next issue however, requires some more thoughtful wiring. Sure, setting up ground and power is fine in theory, just the issue occurs when you want to control it. You can set up a GPIO pin to give output, and to take input, but you can’t properly set it up to turn on and off grounding a GPIO pin. The solution here is to create a kind of fake ground using a transistor. If you set up the collector to take the ground 8x8 pins, and the emitter into a ground rail, you can connect the base to the GPIO board and power that pin to turn on and off the ground. **note: at least 220 ohm resistors should be used to protect the transistors.** Using this website (https://components101.com/displays/8x8-led-matrix-module), I connected up all the wires to the GPIO board. 

Setting up the basic matrix methods:
Now that the pins are all wired up, the next step is to set up the pins internally. You can see in the code that I set up an array of rows and columns, holding the x and y axis, and then setting up the pins using some for loops. The first method that I created was a all() method that simply turned it all on or off depending on whether a True or False value is passed. Aside from being a good first test of the board, this method is also useful for testing the physical matrix and the connections and to catch any conceivable errors before they occur. The next step was the single() method, which takes in a row int, a column int, and a toggle bool. What this would do was it would turn on or off a single light. Herein the next issue arises. If I had a 3x3 matrix, and I wanted to turn on (0, 0) and (2, 2), I would ground the ground pins 0 and 2, and I would power the power pins 0 and 2. However now what happens is pins (0, 0) and (2, 2) will turn on, but also pins (0, 2) and (2, 0). This is because these pins are now also powered and grounded, completing their circuit. The solution that is generally used is to basically turn on and off the lights very, very fast, row by row, making it look like they are all turned on at once. This solution is called multiplexing. The final piece of setup before the game can be started is the full() method, which takes in a 8x8 array and utilizes the single() method to turn on or off LEDs based on whether the item at index [x][y] is 0 or >0. This also has a nice ‘seconds’ parameter based on how small the delay is to choose how long the full() method displays the array for. 

Setting up the game variables:
p1 and p2 are arrays of 3 ints, holding the y coordinate of each of the 3 points of the individual players. This is only the y coordinate because they will never move on the x axis so their x coords will always be either 0 or 7. The ball however has both x and y coords, so that’s what bx and by hold. Technically this could have been converted into a 2 int array, but that would be overkill for just two numbers. bVx and bVy hold the x and y velocities, or more accurately the direction of the ball in the x and y axis, and since our board is so small they’re only 1 each. The baseState is a 2d array holding the base board state for each game, with ‘2’ representing the players and ‘1’ representing the ball. While this is a nice visual representation, it also serves to allow us to simply check later if an item at index is equal to 2 as opposed to checking every item in both player arrays. From there gameBoard is used to “initialize” a new gameBoard so the baseState remains untouched. 

Setting up the game methods:
This is going to be in a somewhat different order then what it is in the code because I kind of built them in weird spots. The playerMove takes in a parameter z so it can be called multiple times within the gameloop before and after the ball moves without error. z should be exclusively a 0 or 1 value. There are two if statements within playerMove, and are functionally identical, except for a few differences within the checks of where the ball is. It executes if 
-The middle of the player is not in line with the ball
-Moving towards the middle being inline would not put the top out of bounds
-Moving towards the middle being inline would not put the bottom out of bounds
-The ball is moving towards the player
-The ball’s x value is not at (0 or 7, depending on which player)+z, attempting to stop the player from colliding with/clipping into the ball in bad ways
If it executes then the player is moved in the direction of the ball’s velocity y. 
The ballRebound function takes in the x and y values of the ball alongside the board and the velocities x and y. It’s purpose is to contain the ball’s movement logic (although not the action, technically.) If the ball is at y index 0 or 7, it will return ‘y’ for a swap on the y index movement.  If the ball is at x index 0 or 7 it will return ‘k’ for “kill.” If the ball is going to move out of bounds, it will also return k. This is a running theme as you might have seen, attempting to make sure that there are not out of bounds errors. If the player would hit a player (that is the ball would move to an index that holds 2 and that wouldn’t assign it out of bounds) it returns ‘x’ for a swap on the x axis movement. Otherwise it returns ‘n’ for no, as in the ball is in “empty space.” Next is the clearBoard function, that takes in the information about the ball, uses nested for loops to essentially just clear the gameBoard, and then has another section where it checks -again- if the ball would be assigned out of bounds. The reassignment method uses nested for loops to find the indexes where the ball and the player should be, and assigns them to that spot on the gameBoard. This should be called exclusively after the clearBoard method. 

Quirks within the gameloop
As a quick run through the gameloop, before all of that as a quick precaution we turn off the entire board. After that we move into the gameLoop, where we call the playerMovement script, passing 1 because it needs to predict where the ball will be as opposed to later when the ball has already moved. Then we call ballRebound, checking for ‘y’, if that is true then we multiply the ball’s y velocity by -1, effectively turning it around, and we do the same process but checking for ‘x’ and reversing bVx instead. We also check for ‘k’ and ‘n’, killing and nothing hit respectively. Next called is playerMove again, but this time with 0 because the ball has had it’s velocity changed. From there clearBoard is called, and if it returns True then we can have the ball move in the direction of it’s velocities. From there the board is reassigned and the gameBoard is shown with the full method. 

About

this is a small project I did for school to get a version of pong running on a Raspberry Pi and a 8x8 LED matrix. Read the readme to get a deeper understanding of the code, although the code isn't too complex (or good) so any reader shouldn't have too hard of a time understanding just the code.


Languages

Language:Python 100.0%