Space invaders with a nRF2401A wireless joypad

Dependencies:   Gameduino mbed nRF2401A

Fork of Gameduino_Invaders_game by Chris Dick

Gameduino and an nRF2401A hooked up to an mbed on an mbeduino:

/media/uploads/TheChrisyd/2014-03-08_22.53.54.jpg

Revision:
0:8a7c58553b44
Child:
1:f44175dd69fd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphics.cpp	Thu Jun 21 19:13:34 2012 +0000
@@ -0,0 +1,394 @@
+#include "game.h"
+
+SPI spigraphics(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk
+
+typedef prog_uint8_t char_data;
+typedef prog_uint16_t sprite_data;
+
+/*---------------------------------------------
+  Graphics - made by typing in the hex... :-)
+---------------------------------------------*/
+static PROGMEM sprite_data invaderT[] = {
+  0x0c00,  0x0c00,
+  0x1e00,  0x1e00,
+  0x3f00,  0x3f00,
+  0x6d80,  0x6d80,
+  0x7f80,  0x7f80,
+  0x1200,  0x2d00,
+  0x2d00,  0x4080,
+  0x5280,  0x2100
+};
+static PROGMEM sprite_data invaderM[] = {
+  0x2080,  0x2080,
+  0x9120,  0x1100,
+  0xbfa0,  0x3f80,
+  0xeee0,  0x6ec0,
+  0xffe0,  0xffe0,
+  0x7fc0,  0xbfa0,
+  0x2080,  0xa0a0,
+  0x4040,  0x1b00
+};
+static PROGMEM sprite_data invaderB[] = {
+  0x0f00,  0x0f00, 
+  0x7fe0,  0x7fe0,
+  0xfff0,  0xfff0,
+  0xe670,  0xe670,
+  0xfff0,  0xfff0,
+  0x1980,  0x1980,
+  0x36c0,  0x6660,
+  0xc030,  0x30c0
+};
+static PROGMEM sprite_data invader_explosion[] = {
+  0x0880,
+  0x4510,
+  0x2020,
+  0x1040,
+  0xc018,
+  0x1040,
+  0x2520,
+  0x4890
+};
+static PROGMEM sprite_data player[] = {
+  0x0200,  0x1004,  0x0200,
+  0x0700,  0x8219,  0x0010,
+  0x0700,  0x10c0,  0x02a0,
+  0x7ff0,  0x0202,  0x1200,
+  0xfff8,  0x4b31,  0x01b0,
+  0xfff8,  0x21c4,  0x45a8,
+  0xfff8,  0x1ff0,  0x1fe4,
+  0xfff8,  0x37f2,  0x3ff5
+};
+static PROGMEM sprite_data bullet[] = {
+  0x0200,
+  0x0200,
+  0x0200,
+  0x0200,
+  0x0000,
+  0x0000,
+  0x0000,
+  0x0000
+};
+static PROGMEM sprite_data bullet_blast[] = {
+  0x1120,
+  0x0440,
+  0x0fc0,
+  0x1fe0,
+  0x1fe0,
+  0x0fc0,
+  0x0480,
+  0x1220
+};
+static PROGMEM sprite_data saucer[] = {
+  0x0000,  0x1281,  0x4800,
+  0x07e0,  0x0806,  0x1000,
+  0x1ff8,  0x51e3,  0x0000,
+  0x3ffc,  0x03f9,  0xc800,
+  0x6db6,  0x0754,  0xe400,
+  0xffff,  0x11f1,  0x8000,
+  0x399c,  0x40a3,  0x1000,
+  0x1008,  0x1110,  0x8000
+};
+static PROGMEM sprite_data saucerScore[] = {
+  0x007c,  0x1038,  0x107c,  0x7c38,
+  0x0040,  0x3044,  0x3040,  0x0444,
+  0x0078,  0x104c,  0x1078,  0x084c,
+  0x0004,  0x1054,  0x1004,  0x1854,
+  0x0004,  0x1064,  0x1004,  0x0464,
+  0x0044,  0x1044,  0x1044,  0x4444,
+  0x0038,  0x3838,  0x3838,  0x3838,
+  0x0000,  0x0000,  0x0000,  0x0000
+};
+static PROGMEM sprite_data saucerZero[] = {
+  0x3800,
+  0x4400,
+  0x4c00,
+  0x5400,
+  0x6400,
+  0x4400,
+  0x3800,
+  0x0000
+};
+static PROGMEM sprite_data zigzagBomb[] = {
+  0x0200,  0x0400,  0x0200,  0x0100,
+  0x0400,  0x0300,  0x0100,  0x0200,
+  0x0200,  0x0100,  0x0200,  0x0400,
+  0x0100,  0x0200,  0x0400,  0x0200,
+  0x0200,  0x0400,  0x0200,  0x0100,
+  0x0400,  0x0200,  0x0100,  0x0200,
+  0x0100,  0x0100,  0x0200,  0x0400,
+  0x0000,  0x0000,  0x0000,  0x0000
+};
+static PROGMEM sprite_data barBomb[] = {
+  0x0200,  0x0200,  0x0200,  0x0700,
+  0x0200,  0x0200,  0x0200,  0x0200,
+  0x0200,  0x0200,  0x0700,  0x0200,
+  0x0200,  0x0700,  0x0200,  0x0200,
+  0x0200,  0x0200,  0x0200,  0x0200,
+  0x0700,  0x0200,  0x0200,  0x0200,
+  0x0000,  0x0000,  0x0000,  0x0000,
+  0x0000,  0x0000,  0x0000,  0x0000
+};
+static PROGMEM sprite_data diagBomb[] = {
+  0x0200,  0x0200,  0x0200,  0x0300,
+  0x0200,  0x0200,  0x0200,  0x0600,
+  0x0200,  0x0600,  0x0200,  0x0200,
+  0x0200,  0x0300,  0x0200,  0x0300,
+  0x0200,  0x0200,  0x0200,  0x0600,
+  0x0200,  0x0600,  0x0200,  0x0200,
+  0x0200,  0x0300,  0x0200,  0x0200,
+  0x0000,  0x0000,  0x0000,  0x0000
+};
+static PROGMEM sprite_data bomb_blast[] = {
+  0x0100,
+  0x0440,
+  0x01a0,
+  0x03c0,
+  0x05c0,
+  0x03e0,
+  0x05c0,
+  0x02a0
+};
+
+static PROGMEM sprite_data shield[] = {
+  0x0fff, 0xc000,
+  0x1fff, 0xe000,
+  0x3fff, 0xf000,
+  0x7fff, 0xf800,
+  0xffff, 0xfc00,
+  0xffff, 0xfc00,
+  0xffff, 0xfc00,
+  0xffff, 0xfc00,
+  0xffff, 0xfc00,
+  0xffff, 0xfc00,
+  0xffff, 0xfc00,
+  0xffff, 0xfc00,
+  0xfe03, 0xfc00,
+  0xfc01, 0xfc00,
+  0xf800, 0xfc00,
+  0xf800, 0xfc00
+};
+
+/*---------------------------------------------
+  Turn raw data into Gameduino sprites
+  
+  We're using four color sprites so each
+  sprite can contain four images. This
+  function interleaves the data...
+---------------------------------------------*/
+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)
+{
+  const unsigned int topBit = 0x8000;
+  unsigned int d1=0,d2=0,d3=0,d4=0;
+  unsigned int dest = RAM_SPRIMG+(index*256);
+  for (byte i=0; i<height; ++i) {              // Space invaders are only 8 pixels tall
+    d1 = *g1;                          g1 += s1;
+    if (g2) { d2 = *g2;  g2 += s2;  }
+    if (g3) { d3 = *g3;  g3 += s3;  }
+    if (g4) { d4 = *g4;  g4 += s4;  }
+    for (byte j=0; j<16; ++j) {
+      unsigned int m1 = (d1&topBit)>>15;
+      unsigned int m2 = (d2&topBit)>>13;
+      unsigned int m3 = (d3&topBit)>>11;
+      unsigned int m4 = (d4&topBit)>>9;
+      GD.wr(dest++,m1+m2+m3+m4);
+      d1 <<= 1;
+      d2 <<= 1;
+      d3 <<= 1;
+      d4 <<= 1;
+    }
+  }
+}
+void makeInvader(byte gr, const sprite_data *data)
+{
+  makeSprite(gr,8,data,2,data+1,2,invader_explosion,1);
+}
+void makeSp3(byte gr, const sprite_data *d)
+{
+  makeSprite(gr,8, d,3, d+1,3, d+2,3);
+}
+void makeSp4(byte gr, const sprite_data *d)
+{
+  makeSprite(gr,8, d,4, d+1,4, d+2,4, d+3,4);
+}
+
+/*---------------------------------------------
+  Char data
+---------------------------------------------*/
+static PROGMEM char_data floorChar[] = {
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0xff,
+  0x00
+};
+static PROGMEM char_data playerLeft[] = {
+  0x02,
+  0x07,
+  0x07,
+  0x7f,
+  0xff,
+  0xff,
+  0xff,
+  0xff
+};
+static PROGMEM char_data playerRight[] = {
+  0x00,
+  0x00,
+  0x00,
+  0xf0,
+  0xf8,
+  0xf8,
+  0xf8,
+  0xf8
+};
+
+/*---------------------------------------------
+  Make a character
+---------------------------------------------*/
+static PROGMEM prog_uint8_t stretch[16] = {
+  0x00, 0x03, 0x0c, 0x0f,
+  0x30, 0x33, 0x3c, 0x3f,
+  0xc0, 0xc3, 0xcc, 0xcf,
+  0xf0, 0xf3, 0xfc, 0xff
+};
+static void makeChar(byte index, const char_data *ch, unsigned int color)
+{
+  // Bitmap
+  GD.__wstart(RAM_CHR+(16*index));
+  for (int i=0; i<8; i++) {
+    byte b = *ch++;
+    spigraphics.write((*stretch+(b >> 4)));
+    spigraphics.write((*stretch+(b & 15)));
+  }
+  GD.__end();
+  // Colors
+  GD.setpal((4*index)+3, color);
+}
+
+/*---------------------------------------------
+  Make all the game sprites
+---------------------------------------------*/
+void makeGraphics()
+{
+  // Sprites
+  makeInvader(GR_INVADER_T,invaderT);
+  makeInvader(GR_INVADER_M,invaderM);
+  makeInvader(GR_INVADER_B,invaderB);
+  makeSp3(GR_PLAYER,player);
+  makeSprite(GR_BULLET,8,bullet,1,bullet_blast,1);
+  makeSprite(GR_BULLET,8,bullet,1,bullet_blast,1, saucerZero,1);
+  makeSp3(GR_SAUCER,saucer);
+  makeSp4(GR_BOMB_ZIGZAG,zigzagBomb);
+  makeSp4(GR_BOMB_BARS,  barBomb);
+  makeSp4(GR_BOMB_DIAG,  diagBomb);
+  makeSp4(GR_SAUCER_SCORE,saucerScore);
+  makeSprite(GR_BOMB_OTHER,8,bomb_blast,1);
+  GD.wr16(PALETTE4A+0,0x8000);  // Transparent
+  GD.wr16(PALETTE4A+2,0x7fff);  // White
+  // Charset
+  GD.ascii();
+  //const unsigned int red = 0x7c00;
+  const unsigned int green = 0x03e0;
+  makeChar(CH_FLOOR,floorChar,green);
+  makeChar(CH_PLAYERL,playerLeft,green);
+  makeChar(CH_PLAYERR,playerRight,green);
+}
+
+
+/*---------------------------------------------------
+  The shields are sprites but we use them as bitmaps
+  so we need to be able to shoot/bomb/rebuild them
+  on demand.
+---------------------------------------------------*/
+void remakeShields()
+{
+  for (int i=0; i<4; ++i) {
+    makeSprite(GR_SHIELD1+i,16,shield,2,shield+1,2);
+  }
+}
+
+int8 zapShield(int n, int8 x, bool withBullet)
+{
+  int y = 0;
+  if ((n >= 0) and (n <= 3)) {
+    n += GR_SHIELD1;
+    const unsigned int spriteMem = RAM_SPRIMG+(n*256);
+    int col = x+6;    // The pixels in the bullet are in column 6 of the graphic
+    if (col < 0 ) col = 0;
+    if (col > 31) col = 31;
+    // Scan the shield and find the top/bottom pixel in column 'x'
+    byte pixelMask = 0x03;
+    if (col > 15) {
+      pixelMask = 0x0c;
+      col &= 15;
+    }
+    unsigned int s = spriteMem+col;
+    const sprite_data *blastMap = bullet_blast;
+    if (withBullet) {
+      // Go from the top, find lowest pixel
+      for (int8 r=0; r<16; ++r) {
+        if ((GD.rd(s)&pixelMask)!=0) {
+          y = r;
+        }
+        s += 16;
+      }
+      x += 3;
+      y -= 5;
+    }
+    else {
+      // Go from the bottom, find highest pixel
+      y = 16;
+      s += 256;
+      int8 offset = 3;
+      for (int8 r=0; r<16; ++r) {
+        s -= 16;
+        // Bombs are wider...we check three columns
+        if ((GD.rd(s)&pixelMask)!=0) {
+          y = 15-r;
+          offset = 2;
+        }
+        else if ((col!=0) and ((GD.rd(s-1)&pixelMask)!=0)) {
+          y = 15-r;
+          offset = 1;
+        }
+        else if ((col!=31) and ((GD.rd(s+1)&pixelMask)!=0)) {
+          y = 15-r;
+          offset = 3;
+        }
+      }
+      x += offset;
+      y -= 4;
+      blastMap = bomb_blast;
+    }
+    // Blast a hole in it
+    for (int8 j=0; j<8; ++j) {  // 8 lines tall
+      const int py = y+j;
+      if ((py>=0) and (py<=15)) {
+        unsigned int blastMask = 0x1000;
+        unsigned int blastGraphic = pgm_read_word_near(blastMap);
+        for (int8 i=0; i<8; ++i) {    // 8 pixels wide...
+          if ((blastGraphic&blastMask)!=0) {
+            // Set shield pixel to 0 where there's a 1 in the source graphic
+            int px = x+i;
+            if ((px>=0) and (px<=31)) {
+              byte pixelMask = 0xfc;
+              if (px > 15) {
+                px &= 15;
+                pixelMask = 0xf3;
+              }
+              unsigned int s = spriteMem+(py*16)+px;
+              GD.wr(s,GD.rd(s)&pixelMask);
+            }
+          }
+          blastMask >>= 1;
+        }
+      }
+      ++blastMap;
+    }
+    
+  }
+  return y;
+}