Chris Dick
/
Gameduino_Invaders_game
Invaders game for the Gameduino
graphics.cpp
- Committer:
- TheChrisyd
- Date:
- 2012-12-20
- Revision:
- 2:20a89dc286d5
- Parent:
- 1:f44175dd69fd
- Child:
- 4:e82f4a87df9e
File content as of revision 2:20a89dc286d5:
#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; extern GDClass GD; /*--------------------------------------------- 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; }