Space invaders with a nRF2401A wireless joypad

Dependencies:   Gameduino mbed nRF2401A

Fork of Gameduino_Invaders_game by Chris Dick

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers graphics.cpp Source File

graphics.cpp

00001 #include "game.h"
00002 
00003 SPI spigraphics(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk
00004 
00005 typedef prog_uint8_t char_data;
00006 typedef prog_uint16_t sprite_data;
00007 
00008 extern GDClass GD;
00009 /*---------------------------------------------
00010   Graphics - made by typing in the hex... :-)
00011 ---------------------------------------------*/
00012 static PROGMEM sprite_data invaderT[] = {
00013   0x0c00,  0x0c00,
00014   0x1e00,  0x1e00,
00015   0x3f00,  0x3f00,
00016   0x6d80,  0x6d80,
00017   0x7f80,  0x7f80,
00018   0x1200,  0x2d00,
00019   0x2d00,  0x4080,
00020   0x5280,  0x2100
00021 };
00022 static PROGMEM sprite_data invaderM[] = {
00023   0x2080,  0x2080,
00024   0x9120,  0x1100,
00025   0xbfa0,  0x3f80,
00026   0xeee0,  0x6ec0,
00027   0xffe0,  0xffe0,
00028   0x7fc0,  0xbfa0,
00029   0x2080,  0xa0a0,
00030   0x4040,  0x1b00
00031 };
00032 static PROGMEM sprite_data invaderB[] = {
00033   0x0f00,  0x0f00, 
00034   0x7fe0,  0x7fe0,
00035   0xfff0,  0xfff0,
00036   0xe670,  0xe670,
00037   0xfff0,  0xfff0,
00038   0x1980,  0x1980,
00039   0x36c0,  0x6660,
00040   0xc030,  0x30c0
00041 };
00042 static PROGMEM sprite_data invader_explosion[] = {
00043   0x0880,
00044   0x4510,
00045   0x2020,
00046   0x1040,
00047   0xc018,
00048   0x1040,
00049   0x2520,
00050   0x4890
00051 };
00052 static PROGMEM sprite_data player[] = {
00053   0x0200,  0x1004,  0x0200,
00054   0x0700,  0x8219,  0x0010,
00055   0x0700,  0x10c0,  0x02a0,
00056   0x7ff0,  0x0202,  0x1200,
00057   0xfff8,  0x4b31,  0x01b0,
00058   0xfff8,  0x21c4,  0x45a8,
00059   0xfff8,  0x1ff0,  0x1fe4,
00060   0xfff8,  0x37f2,  0x3ff5
00061 };
00062 static PROGMEM sprite_data bullet[] = {
00063   0x0200,
00064   0x0200,
00065   0x0200,
00066   0x0200,
00067   0x0000,
00068   0x0000,
00069   0x0000,
00070   0x0000
00071 };
00072 static PROGMEM sprite_data bullet_blast[] = {
00073   0x1120,
00074   0x0440,
00075   0x0fc0,
00076   0x1fe0,
00077   0x1fe0,
00078   0x0fc0,
00079   0x0480,
00080   0x1220
00081 };
00082 static PROGMEM sprite_data saucer[] = {
00083   0x0000,  0x1281,  0x4800,
00084   0x07e0,  0x0806,  0x1000,
00085   0x1ff8,  0x51e3,  0x0000,
00086   0x3ffc,  0x03f9,  0xc800,
00087   0x6db6,  0x0754,  0xe400,
00088   0xffff,  0x11f1,  0x8000,
00089   0x399c,  0x40a3,  0x1000,
00090   0x1008,  0x1110,  0x8000
00091 };
00092 static PROGMEM sprite_data saucerScore[] = {
00093   0x007c,  0x1038,  0x107c,  0x7c38,
00094   0x0040,  0x3044,  0x3040,  0x0444,
00095   0x0078,  0x104c,  0x1078,  0x084c,
00096   0x0004,  0x1054,  0x1004,  0x1854,
00097   0x0004,  0x1064,  0x1004,  0x0464,
00098   0x0044,  0x1044,  0x1044,  0x4444,
00099   0x0038,  0x3838,  0x3838,  0x3838,
00100   0x0000,  0x0000,  0x0000,  0x0000
00101 };
00102 static PROGMEM sprite_data saucerZero[] = {
00103   0x3800,
00104   0x4400,
00105   0x4c00,
00106   0x5400,
00107   0x6400,
00108   0x4400,
00109   0x3800,
00110   0x0000
00111 };
00112 static PROGMEM sprite_data zigzagBomb[] = {
00113   0x0200,  0x0400,  0x0200,  0x0100,
00114   0x0400,  0x0300,  0x0100,  0x0200,
00115   0x0200,  0x0100,  0x0200,  0x0400,
00116   0x0100,  0x0200,  0x0400,  0x0200,
00117   0x0200,  0x0400,  0x0200,  0x0100,
00118   0x0400,  0x0200,  0x0100,  0x0200,
00119   0x0100,  0x0100,  0x0200,  0x0400,
00120   0x0000,  0x0000,  0x0000,  0x0000
00121 };
00122 static PROGMEM sprite_data barBomb[] = {
00123   0x0200,  0x0200,  0x0200,  0x0700,
00124   0x0200,  0x0200,  0x0200,  0x0200,
00125   0x0200,  0x0200,  0x0700,  0x0200,
00126   0x0200,  0x0700,  0x0200,  0x0200,
00127   0x0200,  0x0200,  0x0200,  0x0200,
00128   0x0700,  0x0200,  0x0200,  0x0200,
00129   0x0000,  0x0000,  0x0000,  0x0000,
00130   0x0000,  0x0000,  0x0000,  0x0000
00131 };
00132 static PROGMEM sprite_data diagBomb[] = {
00133   0x0200,  0x0200,  0x0200,  0x0300,
00134   0x0200,  0x0200,  0x0200,  0x0600,
00135   0x0200,  0x0600,  0x0200,  0x0200,
00136   0x0200,  0x0300,  0x0200,  0x0300,
00137   0x0200,  0x0200,  0x0200,  0x0600,
00138   0x0200,  0x0600,  0x0200,  0x0200,
00139   0x0200,  0x0300,  0x0200,  0x0200,
00140   0x0000,  0x0000,  0x0000,  0x0000
00141 };
00142 static PROGMEM sprite_data bomb_blast[] = {
00143   0x0100,
00144   0x0440,
00145   0x01a0,
00146   0x03c0,
00147   0x05c0,
00148   0x03e0,
00149   0x05c0,
00150   0x02a0
00151 };
00152 
00153 static PROGMEM sprite_data shield[] = {
00154   0x0fff, 0xc000,
00155   0x1fff, 0xe000,
00156   0x3fff, 0xf000,
00157   0x7fff, 0xf800,
00158   0xffff, 0xfc00,
00159   0xffff, 0xfc00,
00160   0xffff, 0xfc00,
00161   0xffff, 0xfc00,
00162   0xffff, 0xfc00,
00163   0xffff, 0xfc00,
00164   0xffff, 0xfc00,
00165   0xffff, 0xfc00,
00166   0xfe03, 0xfc00,
00167   0xfc01, 0xfc00,
00168   0xf800, 0xfc00,
00169   0xf800, 0xfc00
00170 };
00171 
00172 /*---------------------------------------------
00173   Turn raw data into Gameduino sprites
00174   
00175   We're using four color sprites so each
00176   sprite can contain four images. This
00177   function interleaves the data...
00178 ---------------------------------------------*/
00179 void makeSprite(byte index, byte height, const sprite_data* g1, byte s1=1,  const sprite_data* g2=0, byte s2=0,  const sprite_data* g3=0, byte s3=0,  const sprite_data* g4=0, byte s4=0)
00180 {
00181   const unsigned int topBit = 0x8000;
00182   unsigned int d1=0,d2=0,d3=0,d4=0;
00183   unsigned int dest = RAM_SPRIMG+(index*256);
00184   for (byte i=0; i<height; ++i) {              // Space invaders are only 8 pixels tall
00185     d1 = *g1;                          g1 += s1;
00186     if (g2) { d2 = *g2;  g2 += s2;  }
00187     if (g3) { d3 = *g3;  g3 += s3;  }
00188     if (g4) { d4 = *g4;  g4 += s4;  }
00189     for (byte j=0; j<16; ++j) {
00190       unsigned int m1 = (d1&topBit)>>15;
00191       unsigned int m2 = (d2&topBit)>>13;
00192       unsigned int m3 = (d3&topBit)>>11;
00193       unsigned int m4 = (d4&topBit)>>9;
00194       GD.wr(dest++,m1+m2+m3+m4);
00195       d1 <<= 1;
00196       d2 <<= 1;
00197       d3 <<= 1;
00198       d4 <<= 1;
00199     }
00200   }
00201 }
00202 void makeInvader(byte gr, const sprite_data *data)
00203 {
00204   makeSprite(gr,8,data,2,data+1,2,invader_explosion,1);
00205 }
00206 void makeSp3(byte gr, const sprite_data *d)
00207 {
00208   makeSprite(gr,8, d,3, d+1,3, d+2,3);
00209 }
00210 void makeSp4(byte gr, const sprite_data *d)
00211 {
00212   makeSprite(gr,8, d,4, d+1,4, d+2,4, d+3,4);
00213 }
00214 
00215 /*---------------------------------------------
00216   Char data
00217 ---------------------------------------------*/
00218 static PROGMEM char_data floorChar[] = {
00219   0x00,
00220   0x00,
00221   0x00,
00222   0x00,
00223   0x00,
00224   0x00,
00225   0xff,
00226   0x00
00227 };
00228 static PROGMEM char_data playerLeft[] = {
00229   0x02,
00230   0x07,
00231   0x07,
00232   0x7f,
00233   0xff,
00234   0xff,
00235   0xff,
00236   0xff
00237 };
00238 static PROGMEM char_data playerRight[] = {
00239   0x00,
00240   0x00,
00241   0x00,
00242   0xf0,
00243   0xf8,
00244   0xf8,
00245   0xf8,
00246   0xf8
00247 };
00248 
00249 /*---------------------------------------------
00250   Make a character
00251 ---------------------------------------------*/
00252 static PROGMEM prog_uint8_t stretch[16] = {
00253   0x00, 0x03, 0x0c, 0x0f,
00254   0x30, 0x33, 0x3c, 0x3f,
00255   0xc0, 0xc3, 0xcc, 0xcf,
00256   0xf0, 0xf3, 0xfc, 0xff
00257 };
00258 static void makeChar(byte index, const char_data *ch, unsigned int color)
00259 {
00260   // Bitmap
00261   GD.__wstart(RAM_CHR+(16*index));
00262   for (int i=0; i<8; i++) {
00263     byte b = *ch++;
00264     spigraphics.write((*stretch+(b >> 4)));
00265     spigraphics.write((*stretch+(b & 15)));
00266   }
00267   GD.__end();
00268   // Colors
00269   GD.setpal((4*index)+3, color);
00270 }
00271 
00272 /*---------------------------------------------
00273   Make all the game sprites
00274 ---------------------------------------------*/
00275 void makeGraphics()
00276 {
00277   // Sprites
00278   makeInvader(GR_INVADER_T,invaderT);
00279   makeInvader(GR_INVADER_M,invaderM);
00280   makeInvader(GR_INVADER_B,invaderB);
00281   makeSp3(GR_PLAYER,player);
00282   makeSprite(GR_BULLET,8,bullet,1,bullet_blast,1);
00283   makeSprite(GR_BULLET,8,bullet,1,bullet_blast,1, saucerZero,1);
00284   makeSp3(GR_SAUCER,saucer);
00285   makeSp4(GR_BOMB_ZIGZAG,zigzagBomb);
00286   makeSp4(GR_BOMB_BARS,  barBomb);
00287   makeSp4(GR_BOMB_DIAG,  diagBomb);
00288   makeSp4(GR_SAUCER_SCORE,saucerScore);
00289   makeSprite(GR_BOMB_OTHER,8,bomb_blast,1);
00290   GD.wr16(PALETTE4A+0,0x8000);  // Transparent
00291   GD.wr16(PALETTE4A+2,0x7fff);  // White
00292   // Charset
00293   GD.ascii();
00294   //const unsigned int red = 0x7c00;
00295   const unsigned int green = 0x03e0;
00296   makeChar(CH_FLOOR,floorChar,green);
00297   makeChar(CH_PLAYERL,playerLeft,green);
00298   makeChar(CH_PLAYERR,playerRight,green);
00299 }
00300 
00301 
00302 /*---------------------------------------------------
00303   The shields are sprites but we use them as bitmaps
00304   so we need to be able to shoot/bomb/rebuild them
00305   on demand.
00306 ---------------------------------------------------*/
00307 void remakeShields()
00308 {
00309   for (int i=0; i<4; ++i) {
00310     makeSprite(GR_SHIELD1+i,16,shield,2,shield+1,2);
00311   }
00312 }
00313 
00314 int8_t zapShield(int8_t n, int8_t x, bool withBullet)
00315 {
00316   int y = 0;
00317   if ((n >= 0) and (n <= 3)) {
00318     n += GR_SHIELD1;
00319     const unsigned int spriteMem = RAM_SPRIMG+(n*256);
00320     int col = x+6;    // The pixels in the bullet are in column 6 of the graphic
00321     if (col < 0 ) col = 0;
00322     if (col > 31) col = 31;
00323     // Scan the shield and find the top/bottom pixel in column 'x'
00324     byte pixelMask = 0x03;
00325     if (col > 15) {
00326       pixelMask = 0x0c;
00327       col &= 15;
00328     }
00329     unsigned int s = spriteMem+col;
00330     const sprite_data *blastMap = bullet_blast;
00331     if (withBullet) {
00332       // Go from the top, find lowest pixel
00333       for (int8_t r=0; r<16; ++r) {
00334         if ((GD.rd(s)&pixelMask)!=0) {
00335           y = r;
00336         }
00337         s += 16;
00338       }
00339       x += 3;
00340       y -= 5;
00341     }
00342     else {
00343       // Go from the bottom, find highest pixel
00344       y = 16;
00345       s += 256;
00346       int8_t offset = 3;
00347       for (int8_t r=0; r<16; ++r) {
00348         s -= 16;
00349         // Bombs are wider...we check three columns
00350         if ((GD.rd(s)&pixelMask)!=0) {
00351           y = 15-r;
00352           offset = 2;
00353         }
00354         else if ((col!=0) and ((GD.rd(s-1)&pixelMask)!=0)) {
00355           y = 15-r;
00356           offset = 1;
00357         }
00358         else if ((col!=31) and ((GD.rd(s+1)&pixelMask)!=0)) {
00359           y = 15-r;
00360           offset = 3;
00361         }
00362       }
00363       x += offset;
00364       y -= 4;
00365       blastMap = bomb_blast;
00366     }
00367     // Blast a hole in it
00368     for (int8_t j=0; j<8; ++j) {  // 8 lines tall
00369       const int py = y+j;
00370       if ((py>=0) and (py<=15)) {
00371         unsigned int blastMask = 0x1000;
00372         unsigned int blastGraphic = pgm_read_word_near(blastMap);
00373         for (int8_t i=0; i<8; ++i) {    // 8 pixels wide...
00374           if ((blastGraphic&blastMask)!=0) {
00375             // Set shield pixel to 0 where there's a 1 in the source graphic
00376             int px = x+i;
00377             if ((px>=0) and (px<=31)) {
00378               byte pixelMask = 0xfc;
00379               if (px > 15) {
00380                 px &= 15;
00381                 pixelMask = 0xf3;
00382               }
00383               unsigned int s = spriteMem+(py*16)+px;
00384               GD.wr(s,GD.rd(s)&pixelMask);
00385             }
00386           }
00387           blastMask >>= 1;
00388         }
00389       }
00390       ++blastMap;
00391     }
00392     
00393   }
00394   return y;
00395 }