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
cfavreau 0:c79e1f29f029 3 #ifndef __SOUND_H__
cfavreau 0:c79e1f29f029 4 #define __SOUND_H__
cfavreau 0:c79e1f29f029 5
cfavreau 0:c79e1f29f029 6
cfavreau 0:c79e1f29f029 7 // Notes in Hertz
cfavreau 0:c79e1f29f029 8 enum NOTE
cfavreau 0:c79e1f29f029 9 {
cfavreau 0:c79e1f29f029 10 NOTE_C3 = 130,
cfavreau 0:c79e1f29f029 11 NOTE_Cs3 = 138,
cfavreau 0:c79e1f29f029 12 NOTE_Db3 = NOTE_Cs3,
cfavreau 0:c79e1f29f029 13 NOTE_D3 = 146,
cfavreau 0:c79e1f29f029 14 NOTE_Ds3 = 155,
cfavreau 0:c79e1f29f029 15 NOTE_Eb3 = NOTE_Ds3,
cfavreau 0:c79e1f29f029 16 NOTE_E3 = 164,
cfavreau 0:c79e1f29f029 17 NOTE_F3 = 174,
cfavreau 0:c79e1f29f029 18 NOTE_Fs3 = 184,
cfavreau 0:c79e1f29f029 19 NOTE_Gb3 = NOTE_Fs3,
cfavreau 0:c79e1f29f029 20 NOTE_G3 = 195,
cfavreau 0:c79e1f29f029 21 NOTE_Gs3 = 207,
cfavreau 0:c79e1f29f029 22 NOTE_Ab3 = NOTE_Gs3,
cfavreau 0:c79e1f29f029 23 NOTE_A3 = 220,
cfavreau 0:c79e1f29f029 24 NOTE_As3 = 233,
cfavreau 0:c79e1f29f029 25 NOTE_Bb3 = NOTE_As3,
cfavreau 0:c79e1f29f029 26 NOTE_B3 = 246,
cfavreau 0:c79e1f29f029 27 NOTE_C4 = 262,
cfavreau 0:c79e1f29f029 28 NOTE_Cs4 = 277,
cfavreau 0:c79e1f29f029 29 NOTE_Db4 = NOTE_Cs4,
cfavreau 0:c79e1f29f029 30 NOTE_D4 = 294,
cfavreau 0:c79e1f29f029 31 NOTE_Ds4 = 311,
cfavreau 0:c79e1f29f029 32 NOTE_Eb4 = NOTE_Ds4,
cfavreau 0:c79e1f29f029 33 NOTE_E4 = 330,
cfavreau 0:c79e1f29f029 34 NOTE_F4 = 349,
cfavreau 0:c79e1f29f029 35 NOTE_Fs4 = 370,
cfavreau 0:c79e1f29f029 36 NOTE_Gb4 = NOTE_Fs4,
cfavreau 0:c79e1f29f029 37 NOTE_G4 = 392,
cfavreau 0:c79e1f29f029 38 NOTE_Gs4 = 415,
cfavreau 0:c79e1f29f029 39 NOTE_Ab4 = NOTE_Gs4,
cfavreau 0:c79e1f29f029 40 NOTE_A4 = 440,
cfavreau 0:c79e1f29f029 41 NOTE_As4 = 466,
cfavreau 0:c79e1f29f029 42 NOTE_B4 = 494,
cfavreau 0:c79e1f29f029 43 NOTE_C5 = 523,
cfavreau 0:c79e1f29f029 44 NOTE_Cs5 = 554,
cfavreau 0:c79e1f29f029 45 NOTE_Db5 = NOTE_Cs5,
cfavreau 0:c79e1f29f029 46 NOTE_D5 = 587,
cfavreau 0:c79e1f29f029 47 NOTE_Ds5 = 622,
cfavreau 0:c79e1f29f029 48 NOTE_Eb5 = NOTE_Ds5,
cfavreau 0:c79e1f29f029 49 NOTE_E5 = 659,
cfavreau 0:c79e1f29f029 50 NOTE_F5 = 698,
cfavreau 0:c79e1f29f029 51 NOTE_Fs5 = 740,
cfavreau 0:c79e1f29f029 52 NOTE_Gb5 = NOTE_Fs5,
cfavreau 0:c79e1f29f029 53 NOTE_G5 = 784,
cfavreau 0:c79e1f29f029 54 NOTE_Gs5 = 831,
cfavreau 0:c79e1f29f029 55 NOTE_Ab5 = NOTE_Gs5,
cfavreau 0:c79e1f29f029 56 NOTE_A5 = 880,
cfavreau 0:c79e1f29f029 57 NOTE_As5 = 932,
cfavreau 0:c79e1f29f029 58 NOTE_Bb5 = NOTE_As5,
cfavreau 0:c79e1f29f029 59 NOTE_B5 = 988,
cfavreau 0:c79e1f29f029 60 NOTE_C6 = 1047,
cfavreau 0:c79e1f29f029 61 NOTE_Cs6 = 1109,
cfavreau 0:c79e1f29f029 62 NOTE_Db6 = NOTE_Cs6,
cfavreau 0:c79e1f29f029 63 NOTE_D6 = 1175,
cfavreau 0:c79e1f29f029 64 NOTE_Ds6 = 1245,
cfavreau 0:c79e1f29f029 65 NOTE_Eb6 = NOTE_Ds6,
cfavreau 0:c79e1f29f029 66 NOTE_E6 = 1319,
cfavreau 0:c79e1f29f029 67 NOTE_F6 = 1397,
cfavreau 0:c79e1f29f029 68 NOTE_Fs6 = 1480,
cfavreau 0:c79e1f29f029 69 NOTE_Gb6 = NOTE_Fs6,
cfavreau 0:c79e1f29f029 70 NOTE_G6 = 1568,
cfavreau 0:c79e1f29f029 71 NOTE_Gs6 = 1661,
cfavreau 0:c79e1f29f029 72 NOTE_Ab6 = NOTE_Gs6,
cfavreau 0:c79e1f29f029 73 NOTE_A6 = 1760,
cfavreau 0:c79e1f29f029 74 NOTE_As6 = 1865,
cfavreau 0:c79e1f29f029 75 NOTE_Bb6 = NOTE_As6,
cfavreau 0:c79e1f29f029 76 NOTE_B6 = 1976,
cfavreau 0:c79e1f29f029 77 NOTE_C7 = 2093,
cfavreau 0:c79e1f29f029 78 NOTE_Cs7 = 2217,
cfavreau 0:c79e1f29f029 79 NOTE_Db7 = NOTE_Cs7,
cfavreau 0:c79e1f29f029 80 NOTE_D7 = 2349,
cfavreau 0:c79e1f29f029 81 NOTE_Ds7 = 2489,
cfavreau 0:c79e1f29f029 82 NOTE_F7 = 2793,
cfavreau 0:c79e1f29f029 83 NOTE_Fs7 = 2959,
cfavreau 0:c79e1f29f029 84 NOTE_Gb7 = NOTE_Fs7,
cfavreau 0:c79e1f29f029 85 NOTE_G7 = 3135,
cfavreau 0:c79e1f29f029 86 NOTE_Gs7 = 3322,
cfavreau 0:c79e1f29f029 87 NOTE_Ab7 = NOTE_Gs7,
cfavreau 0:c79e1f29f029 88 NOTE_A7 = 3520,
cfavreau 0:c79e1f29f029 89 NOTE_As7 = 3729,
cfavreau 0:c79e1f29f029 90 NOTE_Bb7 = NOTE_As7,
cfavreau 0:c79e1f29f029 91 NOTE_B7 = 3951,
cfavreau 0:c79e1f29f029 92 NOTE_C8 = 4186
cfavreau 0:c79e1f29f029 93 };
cfavreau 0:c79e1f29f029 94
cfavreau 0:c79e1f29f029 95 #define SOUND_MAX_CHANNELS 4
cfavreau 0:c79e1f29f029 96
cfavreau 0:c79e1f29f029 97 enum SOUND_INST_WAVEFORM
cfavreau 0:c79e1f29f029 98 {
cfavreau 0:c79e1f29f029 99 SOUND_SQUARE,
cfavreau 0:c79e1f29f029 100 SOUND_SAW,
cfavreau 0:c79e1f29f029 101 SOUND_TRIANGLE,
cfavreau 0:c79e1f29f029 102 SOUND_SINE,
cfavreau 0:c79e1f29f029 103 SOUND_NOISE,
cfavreau 0:c79e1f29f029 104 };
cfavreau 0:c79e1f29f029 105
cfavreau 0:c79e1f29f029 106 struct SOUND_CHANNEL
cfavreau 0:c79e1f29f029 107 {
cfavreau 0:c79e1f29f029 108 bool active;
cfavreau 0:c79e1f29f029 109
cfavreau 0:c79e1f29f029 110 unsigned short orig_phase_inc;
cfavreau 0:c79e1f29f029 111 unsigned short phase_inc;
cfavreau 0:c79e1f29f029 112 unsigned short phase_acc;
cfavreau 0:c79e1f29f029 113 unsigned char volume;
cfavreau 0:c79e1f29f029 114
cfavreau 0:c79e1f29f029 115 unsigned char play_length; // 0 to 255 in 50Hz ticks
cfavreau 0:c79e1f29f029 116
cfavreau 0:c79e1f29f029 117 // Instrument parameters
cfavreau 0:c79e1f29f029 118 unsigned char vol_level; // Starting volume 0 to 64
cfavreau 0:c79e1f29f029 119 char waveform; // 0 = square, 1 = saw, 2 = triangle, 3 = sine, 4 = noise
cfavreau 0:c79e1f29f029 120 unsigned char decay_amount; // 0 to 255
cfavreau 0:c79e1f29f029 121 signed char slide; // +- 127
cfavreau 0:c79e1f29f029 122 unsigned short change_amount; // +-127
cfavreau 0:c79e1f29f029 123 char change_speed; // +-127
cfavreau 0:c79e1f29f029 124 unsigned char repeat_speed; // 0 to 255
cfavreau 0:c79e1f29f029 125 unsigned char vibrato_depth; // Amplitude of Vibrato => 0 to 255
cfavreau 0:c79e1f29f029 126 unsigned char vibrato_speed; // Frequency of the Vibrato
cfavreau 0:c79e1f29f029 127
cfavreau 0:c79e1f29f029 128 // Extra state stuff that makes the instrument do its thing
cfavreau 0:c79e1f29f029 129 bool use_noise;
cfavreau 0:c79e1f29f029 130 unsigned char *pWaveform;
cfavreau 0:c79e1f29f029 131
cfavreau 0:c79e1f29f029 132 unsigned char vibrato_phase;
cfavreau 0:c79e1f29f029 133 short int vibrato_inc;
cfavreau 0:c79e1f29f029 134 unsigned short repeat_wait;
cfavreau 0:c79e1f29f029 135 unsigned short change_wait;
cfavreau 0:c79e1f29f029 136 unsigned short change_inc;
cfavreau 0:c79e1f29f029 137 };
cfavreau 0:c79e1f29f029 138
cfavreau 0:c79e1f29f029 139 class Sound
cfavreau 0:c79e1f29f029 140 {
cfavreau 0:c79e1f29f029 141 public:
cfavreau 0:c79e1f29f029 142
cfavreau 0:c79e1f29f029 143 Sound();
cfavreau 0:c79e1f29f029 144 ~Sound();
cfavreau 0:c79e1f29f029 145
cfavreau 0:c79e1f29f029 146 void Init();
cfavreau 0:c79e1f29f029 147
cfavreau 0:c79e1f29f029 148 void PlaySong(char *pRTTTL, int iChannel = 0, int iBPM = 120, bool bLoop = true);
cfavreau 0:c79e1f29f029 149 void SetSongTempo(int iBPM);
cfavreau 0:c79e1f29f029 150 void TransposeSong(int iOffset);
cfavreau 0:c79e1f29f029 151 void StopSong(void);
cfavreau 0:c79e1f29f029 152 bool SongIsPlaying(void) { return bPlaySong; };
cfavreau 0:c79e1f29f029 153
cfavreau 0:c79e1f29f029 154 // TODO - create a set instrument that allows the parameters to be encoded
cfavreau 0:c79e1f29f029 155 // TODO - what else??? we have sound effects, we have songs... drums?
cfavreau 0:c79e1f29f029 156 void SetInstrument(int iChannel, int iWaveform, int iVolume, int iDecayTime, int iSlide, int iChangeAmount, int iChangeSpeed, int iRepeatSpeed, int iVibratoDepth, int iVibratoSpeed);
cfavreau 0:c79e1f29f029 157 void PlaySound(int iChannel, int iFreqHz, int iLength = 0);
cfavreau 0:c79e1f29f029 158 void StopSound(int iChannel);
cfavreau 0:c79e1f29f029 159 bool IsBusy(int iChannel);
cfavreau 0:c79e1f29f029 160
cfavreau 0:c79e1f29f029 161 void Mute(bool mute);
cfavreau 0:c79e1f29f029 162 bool IsMuted(void) { return bMuted; };
cfavreau 0:c79e1f29f029 163
cfavreau 0:c79e1f29f029 164 int GetCounter(void);
cfavreau 0:c79e1f29f029 165
cfavreau 0:c79e1f29f029 166 friend void TIMER32_0_IRQHandler(void);
cfavreau 0:c79e1f29f029 167
cfavreau 0:c79e1f29f029 168 protected:
cfavreau 0:c79e1f29f029 169
cfavreau 0:c79e1f29f029 170 void SetupDefaults(void);
cfavreau 0:c79e1f29f029 171 void DoEffects(void);
cfavreau 0:c79e1f29f029 172
cfavreau 0:c79e1f29f029 173 SOUND_CHANNEL channel[SOUND_MAX_CHANNELS];
cfavreau 0:c79e1f29f029 174
cfavreau 0:c79e1f29f029 175 unsigned short effect_wait;
cfavreau 0:c79e1f29f029 176
cfavreau 0:c79e1f29f029 177 // Sound Related variables
cfavreau 0:c79e1f29f029 178 bool bMuted;
cfavreau 0:c79e1f29f029 179
cfavreau 0:c79e1f29f029 180 // Song Related Variables and Functions
cfavreau 0:c79e1f29f029 181 bool bPlaySong;
cfavreau 0:c79e1f29f029 182 bool bLoopSong;
cfavreau 0:c79e1f29f029 183 int iSongChannel;
cfavreau 0:c79e1f29f029 184 char *m_pSong;
cfavreau 0:c79e1f29f029 185 char *m_pSongBuffer;
cfavreau 0:c79e1f29f029 186 int iSongBufferLen;
cfavreau 0:c79e1f29f029 187 int iSongNoteOffset;
cfavreau 0:c79e1f29f029 188 int iNoteCounter;
cfavreau 0:c79e1f29f029 189 int iTicksPerBeat;
cfavreau 0:c79e1f29f029 190 void DoSong(void);
cfavreau 0:c79e1f29f029 191 int SongGetFreq(char note, int octave, bool bSharp);
cfavreau 0:c79e1f29f029 192 };
cfavreau 0:c79e1f29f029 193
cfavreau 0:c79e1f29f029 194 #endif // __SOUND_H__