ABHHGD.zip (11001Bytes)
AbHHGD-updated.zip (13456Bytes)
This is a write-up on my Arduino based hand-held gaming device. I realize it’s a somewhat poshy statement but hey, it is Arduino based, it’s hand-held (Ok, technically at this point it is more like table-spread) and it’s a device that plays games!
The parts
To build this little hack requires just a few parts:
- Arduino Uno.
- Max7219 LED matrix.
- Mini bread board.
- Two push-buttons.
- 50K Potentiometer.
- And of course, some jumper wires.
The wiring
The LED matrix already contains a Max7219 LED driver chip so wiring it is very easy. Five wires is all it takes and each of them go to the Arduino. The attached sketch expects the following pins:
- VCC - 5V
- GND - GND
- DIN - D12
- CS - D10
- CLK - D11
Then the controller stuff: the potentiometer is wired to 5v, ground and analog port #1. The buttons are wired to ground and respectively D4 and D5. I used the Arduino’s internal pull-up resistors to pull the in-ports high. Since the game loop runs rather slow there’s no need to bother with debouncing so I didn’t bother using any capacitors, although a 10uF capacitor between the potentiometer’s middle pin and ground might take care of some occasional jerkiness in the dial’s readings.
The menu
I’ve put in a menu system in which each game is represented with a sprite, in casu an identifying letter: P for Pong, T for Tedshow (see below), SI for Space Invaders and S for Snake. The menu options may be selected through turning the dial and the corresponding game is started pressing either one of the push buttons. When the game is finished playing it returns to the menu system allowing the user to immerse herself in yet another one of the many exciting gaming experiences the AbHhGD has to offer!
The games
Four of ‘m as of yet:
1. Good ol’ Pong, the well-known infinite loop [Bounce the ball with the paddle. Wait for the ball to return. Repeat]. I’ve put in a very rudimentary level-up strategy, mainly to keep me from going insane while testing during development: everytime the ball hits the paddle a level-up-counter goes up by one, every ten level-ups the game runs a little bit faster. After two times going a bit faster two bumpers appear in the playing field. If the player even survives that ordeal for ten hits in a row the paddle shrinks by one dot. This repeats until the paddle has shrunk to no paddle at all.
2. Tedshow. A regular feature in a rather moronic quiz show called “De Ted Show” which was aired during the early eighties in the Netherlands would require the winner of the quiz catching some sticks falling randomly out of the ceiling to determine the prizes he or she would win. The game is as brain dead as the quiz show I’m afraid.
3. Space Invaders. This true classic features some of the most effective A.I. in gaming history: [Keep moving left, until hit wall. Move down. Keep moving right, until hit wall. Move down. Repeat]. Due to scarce real-estate however, I modified it a bit in having the invaders bounce to and fro a couple of times before moving down. The player is allowed to fire a single bullet at the time, as are the invaders. Starting with two rows of invaders, each level-up adds another row. Again, scarce real-estate forced me to refrain from adding a fourth level. Guess I should have put in a boss-level..
4. Snake. Turn left and right using the push buttons. Eat apple, snake grows and moves faster. Don’t bite yourself!
The sketch
The sketch contains a number of different units. Some of those units in turn consist of both a .h (header) file and a .ino file.
controller.h and controller.ino
The controller object represents the paddle and the buttons. The paddle has a size, a position and an update method that reads the sensor to finds out where it’s supposed to move to. The buttons can be read using the isPressed (button is down) and wasPressed (button was down and is up) methods.
display.h and display.ino
The Display class deals with the output of the games. It holds a reference to the LedControl object, provided by the LedControl library. This hides all the complexities regarding controlling the actual leds in the matrix component, which is great because we don’t have to deal with that then. In addition, the Display class has methods to display sprites (see below) making up the cut-scenes and methods to draw the game components. This all should be rather self-explanatory when examinimg the code.
ball.h and ball.ino
This is, as you might have guessed, the representation of the ball in the Pong game. It has a position, a direction and methods to start, move and find out if it has hit the paddle. If it does so, it selects a random new direction which is not equal to the previous direction. This is to keep it from repeating the same angle over and over again, which is boring. It also detects if it has crossed the line so the game is over.
sprites.h
This file contains the sprite layouts, an array of bytes, one per line of LEDs.
types.h
Contains the point struct, making up a position and some enums for game and menu control purposes.
menu.h and menu.ino
The menu graphics are defined as very wide sprites. The eight columns to be drawn are calculated from the potentiometer position, as is the game to be played when the users presses one of the buttons.
pong.h and pong.ino
Contains the pong game logic; initialise, update, game over and level-up. Everything else required is defined in the ball and controller classes.
I added the bumpers to provide some additional action. The ball bounces back upon hitting those. The implementation is as simple as it gets: it has a position and is updated in the detectCollision method. The latter takes a pointer to the ball as a parameter and detects if the ball is hitting it, in which case the ball direction is multiplied by -1 (guess I should have overloaded the *= operator, but I wouldn’t bother).
tedShow.h and tedShow.ino
There are two states: blinking the light building up tension and the falling stick. Reads the potentiometer on the controller to position the catcher. The stick may drop earlier or later, just like the real Tedshow in my childhood memories. Writing this game was more fun than playing it I’m afraid. Wasn’t even that much fun watching it back then
SpaceInvaders.h and SpaceInvaders.ino
This one uses a linked list of structs (positions) containing the invaders. Although the code is rather lengthy I guess it is pretty self-explanatory. I put some comments in the code to clarify.
Snake.h and Snake.ino
Again a linked list of positions. They make up the segments of the snake. A new segment is added each time the snake eats the apple. At that point, a new apple is spawned. Collision detection handles the snake going off limits, biting itself or the apple.
Conclusion
Future developments may include developing some more games. Currently, its memory footprint is about 41% of the maximum program size of the Arduino Uno, so there’s plenty of space left. I would also really love to craft this little hack in steampunk, but that is an entirely different kettle of fish…
Disclaimer
This code is far from perfect. Actually, it doesn’t even come close to anywhere near production ready. There’s loads of optimizations to be done, it leaks memory like water from a drainer; it really needs some heavy refactoring. That being said, the code does what I want it to do, which is running the games, as you can see watching the vids I posted along with this write-up.
Update 18/10
No audio support yet, but I did manage to cram the components in a case. It is somewhat bulky, especially with the 9v battery container hot-glued to the back, but certainly a handheld gaming device now it is!
I started out with a little plastic container. The lid would fit the LED matrix and the buttons and dial. I made a square hole in it and hot-glued the LED matrix fixed.
I had to bend the Nano’s pins to make it fit the container. I used a lot of hot glue to prevent the pins from shortening with any metal parts inside the container.
I also added two more games: well known breakout and a racing game. The updated code is in the attached zip-file.
https://www.youtube.com/watch?v=y_NxYoID2eY