A simple one-level platform game. Developed as part of ELEC2645 at University of Leeds, spring 2015.

Dependencies:   N5110 PinDetect PowerControl mbed

An ARM mbed LPC1768 microcontroller have been used to develop a handheld arcade game in the style of an old-school platformer. This project is entirely my own independent work in all stages of the development; including design, defining project specifications, breadboard prototyping, schematic and PCB layout using CAD, assembly, testing and software development. Due to this being part of the ELEC2645 Embedded Systems Project module at University of Leeds, spring 2015, limitations were given on the available hardware components. Credit is due to the authors of the dependent libraries (N5110, Pin Detect, PowerControl and mbed). I would also like to thank the author of Game Programming Patterns as well as the authors of SFML Game Development for providing me with useful sources for programming design patterns.

/media/uploads/Siriagus/game_assembled.jpg

Project aims

  • Implement simple gameplay:
    • A single, fixed (no scrolling) level.
    • Player can move left to right, jump and shoot.
    • Enemies will drop from the top of the screen.
    • The player gets points for shooting enemies.
    • The player dies when it gets hits by an enemy.
  • Implement a simple menu system.
  • Enable the user to adjust the brightness of the display.
  • Output sound to enhance the user experience.

Software

The program flow is controlled by a finite state machine. The implemented design was inspired by the State design pattern from the books Game Programming Patterns and SFML Game Development. The StateManager class is responsible for updating and rendering the current selected state. It also changes the state based on request from the current state. The framework built for the state machine used in this project makes it easy to add new screens. The different main states (indicated by the background colour) and how the user interaction is shown below: /media/uploads/Siriagus/arcadegameuserinteraction.png

Hardware

Schematic:

/media/uploads/Siriagus/schematic.png

Printed circuit board (PCB):

/media/uploads/Siriagus/pcb.png

Images

A seperate program was written to convert images (png) to text-representation of the maps. Enemies and numbers on the screen are also collected from a sprite-sheet created in the same manner.

/media/uploads/Siriagus/unileeds3.png /media/uploads/Siriagus/newmap2.png

Committer:
Siriagus
Date:
Fri May 08 23:51:26 2015 +0000
Revision:
12:8178fad5e660
Parent:
10:f2488a0ecab7
Child:
13:7ab71c7c311b
Added template drawImage function which can draw images of any dimension.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Siriagus 1:0cfe2255092a 1 #ifndef STATE_H
Siriagus 1:0cfe2255092a 2 #define STATE_H
Siriagus 1:0cfe2255092a 3
Siriagus 4:d6661b976359 4 #include "N5110.h"
Siriagus 4:d6661b976359 5 #include "PinDetect.h"
Siriagus 4:d6661b976359 6 #include "InputManager.h"
Siriagus 4:d6661b976359 7
Siriagus 10:f2488a0ecab7 8 /** @file State.h
Siriagus 10:f2488a0ecab7 9 * @author Andreas Garmannslund
Siriagus 10:f2488a0ecab7 10 * @date April 2015
Siriagus 10:f2488a0ecab7 11 */
Siriagus 10:f2488a0ecab7 12
Siriagus 4:d6661b976359 13 class StateManager;
Siriagus 4:d6661b976359 14
Siriagus 10:f2488a0ecab7 15 /// States used in the finite state machine.
Siriagus 8:9ac6a428fa26 16 enum MainState {MAIN_MENU, GAME, SUBMIT_HIGHSCORE, GAME_OVER, NO_STATE, TITLE_SCREEN};
Siriagus 4:d6661b976359 17
Siriagus 10:f2488a0ecab7 18 /// Abstract class for states in the program's main finite state machine. All state implementations is derived from this abstract class.
Siriagus 1:0cfe2255092a 19 class State
Siriagus 5:100d960fc6d5 20 {
Siriagus 1:0cfe2255092a 21 public:
Siriagus 10:f2488a0ecab7 22
Siriagus 10:f2488a0ecab7 23 /* Creates a new state object. Should be called from child's constructor.
Siriagus 10:f2488a0ecab7 24 * @param fsm Pointer to finished state machine.
Siriagus 10:f2488a0ecab7 25 * @param lcd Pointer to the N5110 lcd object.
Siriagus 10:f2488a0ecab7 26 * @param input Pointer to the InputManager object, used for controlling user input.
Siriagus 10:f2488a0ecab7 27 */
Siriagus 4:d6661b976359 28 State(StateManager* fsm, N5110 *lcd, InputManager* input)
Siriagus 7:678873947b29 29 :lcd(lcd), input(input), fsm(fsm){}
Siriagus 4:d6661b976359 30
Siriagus 10:f2488a0ecab7 31 /// Handle user input and update logic.
Siriagus 7:678873947b29 32 virtual void update(float dt) = 0;
Siriagus 10:f2488a0ecab7 33
Siriagus 10:f2488a0ecab7 34 /// Draw to screen.
Siriagus 4:d6661b976359 35 virtual void render() = 0;
Siriagus 4:d6661b976359 36
Siriagus 7:678873947b29 37 protected:
Siriagus 10:f2488a0ecab7 38 /* Requests the finite state machine to switch to a new state when possible.
Siriagus 10:f2488a0ecab7 39 * @param newState The state the fsm should switch to.
Siriagus 10:f2488a0ecab7 40 **/
Siriagus 7:678873947b29 41 void requestStateChange(MainState newState);
Siriagus 10:f2488a0ecab7 42
Siriagus 10:f2488a0ecab7 43 /** Draws an image to the lcd
Siriagus 10:f2488a0ecab7 44 * @param img Array with the same size as the display, where 1 is opaque, 0 is blank.
Siriagus 10:f2488a0ecab7 45 */
Siriagus 12:8178fad5e660 46 //void drawImage(const int img[BANKS][WIDTH]); // Draws an image from array
Siriagus 12:8178fad5e660 47
Siriagus 12:8178fad5e660 48
Siriagus 12:8178fad5e660 49 /** Draws an image/sprite to the lcd
Siriagus 12:8178fad5e660 50 * @param img const int array where a solid pixel equals 1, and a blank pixel equals zero
Siriagus 12:8178fad5e660 51 * @param x Horizontal position of image (leftmost pixel)
Siriagus 12:8178fad5e660 52 * @param y Vertical position of image (uppermost pixel)
Siriagus 12:8178fad5e660 53 * See seperate program for how this array can be generated from an image file using SFML!
Siriagus 12:8178fad5e660 54 */
Siriagus 12:8178fad5e660 55 template<size_t rows, size_t cols>
Siriagus 12:8178fad5e660 56 void drawImage(const int (&img)[rows][cols], int x, int y);
Siriagus 12:8178fad5e660 57
Siriagus 12:8178fad5e660 58 /** Draws an image/sprite to the lcd with origin in upper-left corner of the lcd
Siriagus 12:8178fad5e660 59 * @param img Array where 1 corresponds to opaque and 0 corresponds to blank
Siriagus 12:8178fad5e660 60 */
Siriagus 12:8178fad5e660 61 template <size_t rows, size_t cols>
Siriagus 12:8178fad5e660 62 void drawImage(const int (&img)[rows][cols]) { drawImage(img, 0, 0); }
Siriagus 4:d6661b976359 63
Siriagus 4:d6661b976359 64 protected:
Siriagus 4:d6661b976359 65 N5110 *lcd;
Siriagus 4:d6661b976359 66 InputManager *input;
Siriagus 4:d6661b976359 67
Siriagus 4:d6661b976359 68 private:
Siriagus 4:d6661b976359 69 StateManager *fsm;
Siriagus 4:d6661b976359 70
Siriagus 1:0cfe2255092a 71 };
Siriagus 1:0cfe2255092a 72
Siriagus 12:8178fad5e660 73 // Template functions needs to be declared in the header file
Siriagus 12:8178fad5e660 74 // TODO: Add functions for inverse drawing
Siriagus 12:8178fad5e660 75 template<size_t rows, size_t cols>
Siriagus 12:8178fad5e660 76 void State::drawImage(const int (&img)[rows][cols], int x, int y)
Siriagus 12:8178fad5e660 77 {
Siriagus 12:8178fad5e660 78 for (int i = 0; i < rows; ++i)
Siriagus 12:8178fad5e660 79 {
Siriagus 12:8178fad5e660 80 // Skip if outside dimensions of LCD
Siriagus 12:8178fad5e660 81 if (y + i < 0) continue;
Siriagus 12:8178fad5e660 82 else if (y + i >= HEIGHT) break; // Drawing top to bottom, so all succeding points will also be outside
Siriagus 12:8178fad5e660 83
Siriagus 12:8178fad5e660 84 for (int j = 0; j < cols; ++j)
Siriagus 12:8178fad5e660 85 {
Siriagus 12:8178fad5e660 86 // Dimensions check. Draws left to right.
Siriagus 12:8178fad5e660 87 if (x + j < 0) continue;
Siriagus 12:8178fad5e660 88 else if (x + j >= WIDTH) break;
Siriagus 12:8178fad5e660 89
Siriagus 12:8178fad5e660 90 if (img[i][j])
Siriagus 12:8178fad5e660 91 lcd->setPixel(x+j,y+i);
Siriagus 12:8178fad5e660 92
Siriagus 12:8178fad5e660 93 }
Siriagus 12:8178fad5e660 94 }
Siriagus 12:8178fad5e660 95 }
Siriagus 1:0cfe2255092a 96 #endif