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:
Mon May 11 04:40:23 2015 +0000
Revision:
18:709ea375b0df
Parent:
17:d6a3b29cab31
Fixed some formatting errors in documentation.

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