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:
Sat May 09 13:56:14 2015 +0000
Revision:
13:7ab71c7c311b
Parent:
12:8178fad5e660
Child:
17:d6a3b29cab31
Expanded functionallity of drawImage - inverse, flipX, flipY. Collision test for all entities. Added simple enemy.

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 13:7ab71c7c311b 50 * Only the solid pixels are drawn. If two images overlap, the second image drawn will
Siriagus 13:7ab71c7c311b 51 * not clear pixels which are solid in the first image.
Siriagus 12:8178fad5e660 52 * @param img const int array where a solid pixel equals 1, and a blank pixel equals zero
Siriagus 12:8178fad5e660 53 * @param x Horizontal position of image (leftmost pixel)
Siriagus 12:8178fad5e660 54 * @param y Vertical position of image (uppermost pixel)
Siriagus 13:7ab71c7c311b 55 * @param Inverses images. Default value is false
Siriagus 12:8178fad5e660 56 * See seperate program for how this array can be generated from an image file using SFML!
Siriagus 12:8178fad5e660 57 */
Siriagus 12:8178fad5e660 58 template<size_t rows, size_t cols>
Siriagus 13:7ab71c7c311b 59 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 60
Siriagus 4:d6661b976359 61 protected:
Siriagus 4:d6661b976359 62 N5110 *lcd;
Siriagus 4:d6661b976359 63 InputManager *input;
Siriagus 4:d6661b976359 64
Siriagus 4:d6661b976359 65 private:
Siriagus 4:d6661b976359 66 StateManager *fsm;
Siriagus 4:d6661b976359 67
Siriagus 1:0cfe2255092a 68 };
Siriagus 1:0cfe2255092a 69
Siriagus 12:8178fad5e660 70 // Template functions needs to be declared in the header file
Siriagus 12:8178fad5e660 71 // TODO: Add functions for inverse drawing
Siriagus 12:8178fad5e660 72 template<size_t rows, size_t cols>
Siriagus 13:7ab71c7c311b 73 void State::drawImage(const int (&img)[rows][cols], int x, int y, bool inverse, bool flipX, bool flipY)
Siriagus 12:8178fad5e660 74 {
Siriagus 13:7ab71c7c311b 75 int targetX, targetY; // The position on the lcd we are writing to
Siriagus 13:7ab71c7c311b 76
Siriagus 12:8178fad5e660 77 for (int i = 0; i < rows; ++i)
Siriagus 12:8178fad5e660 78 {
Siriagus 13:7ab71c7c311b 79 targetY = (flipY) ? (y + (rows-1) - i) : (y + i);
Siriagus 13:7ab71c7c311b 80
Siriagus 12:8178fad5e660 81 // Skip if outside dimensions of LCD
Siriagus 13:7ab71c7c311b 82 if (targetY < 0) continue;
Siriagus 13:7ab71c7c311b 83 else if (targetY >= HEIGHT) continue;
Siriagus 12:8178fad5e660 84
Siriagus 12:8178fad5e660 85 for (int j = 0; j < cols; ++j)
Siriagus 12:8178fad5e660 86 {
Siriagus 13:7ab71c7c311b 87 targetX = (flipX) ? (x + ((cols - 1) - j)) : (x + j);
Siriagus 13:7ab71c7c311b 88
Siriagus 12:8178fad5e660 89 // Dimensions check. Draws left to right.
Siriagus 13:7ab71c7c311b 90 if (targetX < 0) continue;
Siriagus 13:7ab71c7c311b 91 else if (targetX >= WIDTH) continue;
Siriagus 12:8178fad5e660 92
Siriagus 13:7ab71c7c311b 93 int solid = img[i][j];
Siriagus 13:7ab71c7c311b 94
Siriagus 13:7ab71c7c311b 95 if ((solid && !inverse) || (!solid && inverse))
Siriagus 13:7ab71c7c311b 96 lcd->setPixel(targetX, targetY);
Siriagus 12:8178fad5e660 97
Siriagus 12:8178fad5e660 98 }
Siriagus 12:8178fad5e660 99 }
Siriagus 12:8178fad5e660 100 }
Siriagus 1:0cfe2255092a 101 #endif