Retro Invaders a space invaders clone by Chris Favreau. Written for the RetroMbuino development board from outrageouscircuits.com for the game programming contest.

Dependencies:   mbed

This is a space invaders clone written for the Retro Mbuino from outrageous circuits.

Development board: http://www.outrageouscircuits.com/shop/product/15 ).

The game itself is basic space invaders. Shoot them before they get to the bottom of the screen. It has a UFO saucer which you can shoot for extra points. You get 4 shields and each shield can be hit up to 4 times before it is gone. Hmm... as each level increases the speed of the invaders shots goes up. The invaders only speed up when there is less of them. You complete the level when you shoot all the invaders. The game ends when a) you run out of lives (you start with 3) or the invaders get to the bottom.

The LEDs turned out to be a pretty cool addition to the game. I wrote a class that blinks them and turns them on for a specified amount of time. They add a nice extra to the game. I use them on the intro screen and when the UFO is present.

The sound turned out to be really difficult for a few reasons. The biggest was that I had never written a sound engine before. The interrupt service routine working off the timer was the easier part. I also had a lot of trouble because there is no filter to filter out the PWM frequency to the speaker... so I had to run the PWM frequency way up there 30 kHz.

The graphics turned out to be a bit of a bear too. Thanks to Chris Taylor for his really great LCD API. I picked up a couple of frames per second from that. I had modified the DisplayN18 class for blitting a single line buffer to the LCD panel however his is a little faster for some reason? I used a different approach to doing the graphics (as I have very little experience with anything other than double buffered displays). I have a tile map and a list of sprites. Each tile/sprite is 1 bit 8x8. They could be bigger. I ran out of time. That much is not special. What is different from what I can tell is that I use a 1 line buffer that is 160 shorts long. The render function first adds the tile map data into the line buffer first. Then the sprites are added over the existing data. You can have a great deal of different sprites and maps going to the screen and just have to rewrite the LCD memory once per frame. After each line is composited, the line is then drawn to the LCD. Kind of like an Atari 2600. Each sprite/tile has a foreground and background color and can be different from the other tiles/sprites. There is one color reserved for Transparency.

There are 16 colors to choose from. I chose a palette based on the Macintosh OS 4.1 palette I found on WikiPedia. It is a very nice mix of colors.

I found a sprite editor called SpriteX ( https://code.google.com/p/spritesx-ed/ )... it works nicely except that the 16x16 sprites are in a weird format. Time limited me to 8x8 sprites. Oh well.

I used nokring to make the music. It makes RTTTL formatted ring tones which my sound api can play. Here is a useful site that has lots of arcade/video game ring tones with a link to nokring in the utilities page. http://arcadetones.emuunlim.com/files.htm

Other than all that stuff I used state machines to do most of the game logic. Please excuse the horrible coding as I tried to comment a lot of it however it is not very nice to look at. Lots of long functions...

Committer:
cfavreau
Date:
Tue Mar 03 04:26:01 2015 +0000
Revision:
0:c79e1f29f029
Retro Invaders by Chris Favreau for the RetroMbuino Platform - outrageouscircuits.com game programming contest.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cfavreau 0:c79e1f29f029 1 #include "mbed.h"
cfavreau 0:c79e1f29f029 2 #include "./Display/display.h" // LCD Display Driver
cfavreau 0:c79e1f29f029 3 #include "./led/led.h" // LED Driver
cfavreau 0:c79e1f29f029 4 #include "./Input/input.h" // INPUT Driver
cfavreau 0:c79e1f29f029 5 #include "./Sound/sound.h" // SOUND Driver
cfavreau 0:c79e1f29f029 6
cfavreau 0:c79e1f29f029 7 #pragma once
cfavreau 0:c79e1f29f029 8
cfavreau 0:c79e1f29f029 9 enum GAME_MODE
cfavreau 0:c79e1f29f029 10 {
cfavreau 0:c79e1f29f029 11 eGameTitle,
cfavreau 0:c79e1f29f029 12 eGamePlay,
cfavreau 0:c79e1f29f029 13 eGameOver,
cfavreau 0:c79e1f29f029 14 };
cfavreau 0:c79e1f29f029 15
cfavreau 0:c79e1f29f029 16 #define FRAMES_PER_SECOND 20 // unfortunately this is what we get...
cfavreau 0:c79e1f29f029 17 #define MS_PER_FRAME 50
cfavreau 0:c79e1f29f029 18
cfavreau 0:c79e1f29f029 19 class Game
cfavreau 0:c79e1f29f029 20 {
cfavreau 0:c79e1f29f029 21 int frame_timeout;
cfavreau 0:c79e1f29f029 22 int frame_count;
cfavreau 0:c79e1f29f029 23 int now;
cfavreau 0:c79e1f29f029 24
cfavreau 0:c79e1f29f029 25 Timer timer;
cfavreau 0:c79e1f29f029 26 display disp;
cfavreau 0:c79e1f29f029 27 AnalogIn ain;
cfavreau 0:c79e1f29f029 28 led lights;
cfavreau 0:c79e1f29f029 29 input inputs;
cfavreau 0:c79e1f29f029 30 Sound sound;
cfavreau 0:c79e1f29f029 31
cfavreau 0:c79e1f29f029 32 GAME_MODE mode;
cfavreau 0:c79e1f29f029 33 int game_step;
cfavreau 0:c79e1f29f029 34 bool paused;
cfavreau 0:c79e1f29f029 35
cfavreau 0:c79e1f29f029 36 void initialize();
cfavreau 0:c79e1f29f029 37 bool dotick();
cfavreau 0:c79e1f29f029 38
cfavreau 0:c79e1f29f029 39 void DoGameTitle();
cfavreau 0:c79e1f29f029 40 void DoGamePlay();
cfavreau 0:c79e1f29f029 41 void DoGameOver();
cfavreau 0:c79e1f29f029 42
cfavreau 0:c79e1f29f029 43 uint8_t star_field_timer;
cfavreau 0:c79e1f29f029 44 void SetupStarfield();
cfavreau 0:c79e1f29f029 45 void UpdateStarfield();
cfavreau 0:c79e1f29f029 46
cfavreau 0:c79e1f29f029 47 void SetupInvaders();
cfavreau 0:c79e1f29f029 48 void UpdateInvaders();
cfavreau 0:c79e1f29f029 49 bool invaders[40];
cfavreau 0:c79e1f29f029 50 int8_t active_invaders;
cfavreau 0:c79e1f29f029 51 int8_t invaders_inc;
cfavreau 0:c79e1f29f029 52 uint8_t invaders_timer;
cfavreau 0:c79e1f29f029 53 uint8_t invaders_wait_time;
cfavreau 0:c79e1f29f029 54 uint8_t invaders_frame;
cfavreau 0:c79e1f29f029 55 uint8_t invaders_x, invaders_y;
cfavreau 0:c79e1f29f029 56 bool invader_active_shot[4];
cfavreau 0:c79e1f29f029 57 uint8_t invader_shot_interval;
cfavreau 0:c79e1f29f029 58 uint8_t invader_shot_x[4];
cfavreau 0:c79e1f29f029 59 uint8_t invader_shot_y[4];
cfavreau 0:c79e1f29f029 60 int8_t invader_shot_timer;
cfavreau 0:c79e1f29f029 61 uint8_t invader_march_note;
cfavreau 0:c79e1f29f029 62
cfavreau 0:c79e1f29f029 63
cfavreau 0:c79e1f29f029 64 void SetupPlayer();
cfavreau 0:c79e1f29f029 65 void UpdatePlayer();
cfavreau 0:c79e1f29f029 66 uint8_t player_x, player_y;
cfavreau 0:c79e1f29f029 67 bool player_shot_active;
cfavreau 0:c79e1f29f029 68 uint8_t player_shot_x, player_shot_y;
cfavreau 0:c79e1f29f029 69
cfavreau 0:c79e1f29f029 70 void SetupSaucer();
cfavreau 0:c79e1f29f029 71 void UpdateSaucer();
cfavreau 0:c79e1f29f029 72 bool saucer_active;
cfavreau 0:c79e1f29f029 73 int saucer_timer;
cfavreau 0:c79e1f29f029 74 int8_t saucer_inc;
cfavreau 0:c79e1f29f029 75 uint8_t saucer_x, saucer_y;
cfavreau 0:c79e1f29f029 76
cfavreau 0:c79e1f29f029 77 void SetupShields();
cfavreau 0:c79e1f29f029 78 void UpdateShields();
cfavreau 0:c79e1f29f029 79 uint8_t shield_x, shield_y;
cfavreau 0:c79e1f29f029 80 uint8_t shield_points[4];
cfavreau 0:c79e1f29f029 81
cfavreau 0:c79e1f29f029 82 void CheckCollisions();
cfavreau 0:c79e1f29f029 83
cfavreau 0:c79e1f29f029 84 void IncScore(int points);
cfavreau 0:c79e1f29f029 85 void UpdateScore();
cfavreau 0:c79e1f29f029 86 void UpdateLives();
cfavreau 0:c79e1f29f029 87 int hiscore;
cfavreau 0:c79e1f29f029 88 int score;
cfavreau 0:c79e1f29f029 89 uint8_t lives;
cfavreau 0:c79e1f29f029 90 uint8_t level;
cfavreau 0:c79e1f29f029 91
cfavreau 0:c79e1f29f029 92 uint8_t wait_timer;
cfavreau 0:c79e1f29f029 93
cfavreau 0:c79e1f29f029 94 void UpdateGameOverInvaders();
cfavreau 0:c79e1f29f029 95 uint8_t game_over_msg;
cfavreau 0:c79e1f29f029 96
cfavreau 0:c79e1f29f029 97 public:
cfavreau 0:c79e1f29f029 98
cfavreau 0:c79e1f29f029 99 Game();
cfavreau 0:c79e1f29f029 100
cfavreau 0:c79e1f29f029 101 void tick();
cfavreau 0:c79e1f29f029 102 };