Space invaders with a nRF2401A wireless joypad
Dependencies: Gameduino mbed nRF2401A
Fork of Gameduino_Invaders_game by
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 }
Generated on Fri Jul 15 2022 06:07:12 by 1.7.2