Game entry for the Game Programming Contest sponsored by OutrageousCircuits.com (RETRO Game Console)
Fork of Official_RETRO by
Game.cpp
- Committer:
- Rogerup
- Date:
- 2015-03-01
- Revision:
- 4:2d41b942a823
- Parent:
- 3:7680307a02d7
File content as of revision 4:2d41b942a823:
#include "Game.h" #include <cstdarg> #define SOUNDWIN 1 unsigned short piececolor[5] = { 0, LGRAY, WHITE, WHITE, DGRAY }; Game::Game() : left(P0_14, PullUp), right(P0_11, PullUp), down(P0_12, PullUp), up(P0_13, PullUp), square(P0_16, PullUp), circle(P0_1, PullUp), led1(P0_9), led2(P0_8), pwm(P0_18), ain(P0_15), i2c(P0_5, P0_4) { this->initialize(); } void Game::showNumber(int y, int val) { char buf[8]; int len = sprintf(buf, "%d", val); disp.fillRect( 128, y+9, 32, 8, BLACK ); if( val < 1000 ) disp.drawString(145-len*3, y+9, buf, CYAN, BLACK); else disp.drawString(145-3*3, y+9, "...", CYAN, BLACK); } void Game::initialize() { disp.clear(); led1 = 0; led2 = 0; pwm = 0; pwm.period_ms(1); tickCounter = 1000; tickWin = 0; bamTicksLeft = 0; level = 0; oldLevel = -1; for( int lev=0; lev<L_LAST; lev++ ) your[lev] = 10000; initTable(); } void Game::tick() { tickCounter++; playSound(); if( levelCompleted ) { if( (tickCounter % 40) == 0 ) { led1 = 1; led2 = 0; } if( (tickCounter % 40) == 20 ) { led1 = 0; led2 = 1; } } checkButtons(); if( level != L_INTRO) showTable(); playBam(); wait_ms(25); } void Game::checkButtons() { bool kSquare = false, kCircle = false, kUp = false, kDown = false, kLeft = false, kRight = false; // // Repeat key after 16*25ms = 400ms // char noKey = 0; if( !square.read() ) kSquare = !lastKey; else noKey++; if( !circle.read() ) kCircle = !lastKey; else noKey++; if( !up.read() ) kUp = !lastKey; else noKey++; if( !down.read() ) kDown = !lastKey; else noKey++; if( !left.read() ) kLeft = !lastKey; else noKey++; if( !right.read() ) kRight = !lastKey; else noKey++; if( noKey < 6 ) { if( lastKey == 0 ) lastKey = 16; else lastKey--; } else lastKey = 0; // // Select level // if( kSquare ) if( ++level > L_LAST ) level = L_INTRO; if( kCircle ) if( --level < L_INTRO ) level = L_INTRO + 1; //L_LAST; if( kSquare || kCircle || (!up.read() && !left.read()) ) initTable(); // // Arrow keys to move // if( kUp ) moveTable( -1, 0, 1, TABH, 0, TABW ); if( kDown ) moveTable( 1, 0, TABH-2, -1, 0, TABW ); if( kLeft ) moveTable( 0, -1, 0, TABH, 1, TABW ); if( kRight ) moveTable( 0, 1, 0, TABH, TABW-2, -1 ); } void Game::fillTable(char i0, char j0, char h, char w, unsigned char v) { unsigned char nh = v & 0xF0; unsigned char nl = v & 0x0F; for( int i=i0; i<i0+h; i++ ) for( int j=j0; j<j0+w; j++ ) { if( v <= BONG ) { table[i][j] = v; } else { if( nh && table[i][j] <= BONG ) table[i][j] = FREE; if( nh ) table[i][j] = (table[i][j] & 0x0F) | nh; if( nl ) table[i][j] = (table[i][j] & 0xF0) | nl; } if( nl > MARK ) nl += 0x01; if( nh > BALL ) nh += 0x10; change[i] |= 1 << j; } } void Game::fillTableV( unsigned char v, ...) { unsigned short pos; va_list arguments; va_start ( arguments, v ); while( (pos = (unsigned short)va_arg ( arguments, int)) != 0 ) { unsigned char h = (pos & 0x00F0) >> 4; unsigned char w = (pos & 0x000F) >> 0; if( w == 0 ) w = 16; fillTable((pos&0xF000)>>12, (pos&0x0F00)>>8, h, w, v); if( (v&0x0F) > MARK ) v += h*w; if( v > BALL ) v += ((h*w) << 4); } va_end ( arguments ); } void Game::moveTable(int di, int dj, int i0, int i2, int j0, int j2 ) { if( level == L_INTRO || levelCompleted ) return; int ai = 1, aj = 1, mov = 0; if( i2 < i0 ) ai = -1; if( j2 < j0 ) aj = -1; // // Check BONG (RED) - If any ball hits BONG, no ball can move. // for( int i=i0; i!=i2; i+=ai ) for( int j=j0; j!=j2; j+=aj ) if( table[i][j] & 0xF0 ) if( (table[i+di][j+dj] & 0x0F) == BONG ) { showNumber( MOVY, ++moves ); bamX = (j+dj)*8; bamY = (i+di)*8; fillPieceV( BLACK, 0x0077, 0 ); fillPieceV( YELLOW, 0x1111, 0x5111, 0x1511, 0x5511, 0x3115, 0x1351, 0x2233, 0 ); disp.draw((unsigned short *)piece, bamX, bamY, 7, 7); bamTicksLeft = 5; return; } // // Move Balls // for( int i=i0; i!=i2; i+=ai ) { for( int j=j0; j!=j2; j+=aj ) { unsigned char ball = table[i][j] & 0xF0; if( !ball ) continue; if( table[i+di][j+dj] & 0xF0 ) continue; if( (table[i+di][j+dj] & 0x0F) == WALL ) continue; table[i+di][j+dj] |= ball; table[i][j] &= 0x0F; change[i+di] |= 1 << (j+dj); change[i] |= 1 << j; mov = 1; } } moves += mov; showNumber( MOVY, moves ); // // Check if Level is Completed // int balls = 0, marks = 0; for( int i=0; i<TABH; i++ ) { for( int j=0; j<TABW; j++ ) if( table[i][j] & 0xF0 ) { balls++; if( ((table[i][j] & 0x0F) - MARK + 1) == ((table[i][j] & 0xF0) >> 4) ) marks++; } } if( marks == balls ) { levelCompleted = true; if( moves < your[level] ) your[level] = moves; showNumber( YOUY, your[level] ); disp.drawString(8, 117, " LEVEL COMPLETED! ", RED, BLACK); led1 = 1; led2 = 1; #ifdef SOUNDWIN tickWin = tickCounter; #endif } } void Game::showTable() { for( int i=0; i<TABH; i++ ) for( int j=0; j<TABW; j++ ) showPiece(i,j); } void Game::showPiece(int i, int j) { if( !(change[i] & (1 << j)) ) return; change[i] &= ~(1 << j); unsigned char ball = table[i][j] >> 4; unsigned char base = table[i][j] & 0x0F; unsigned char basec = base; if( basec > MARK ) basec = MARK; fillPiece( 0, 0, 7, 7, piececolor[basec] ); if( base == WALL ) { fillPiece( 1, 1, 1, 1, 0 ); fillPiece( 1, 5, 1, 1, 0 ); fillPiece( 5, 1, 1, 1, 0 ); fillPiece( 5, 5, 1, 1, 0 ); } if( base == BONG ) { fillPiece( 1, 1, 5, 5, RED ); //fillPieceV( RED, 0x1111, 0x5111, 0x1511, 0x5511, 0x3115, 0x1351, 0x2233, 0 ); } if( base == MARK ) { fillPiece( 3, 3, 1, 1, WHITE ); } if( ball ) { fillPieceV( BLUE, 0x1051,0x0175, 0x1651, 0 ); //fillPieceV( WHITE 0x3311, 0 ); } disp.draw((unsigned short *)piece, j*8, i*8, 7, 7); if( base > MARK && !ball ) disp.drawNumber( j*8+2, i*8+1, base-MARK, WHITE, piececolor[MARK] ); if( ball > 1 ) disp.drawNumber( j*8+2, i*8+1, ball-1, WHITE, BLUE ); } void Game::fillPiece(int x0, int y0, int w, int h, unsigned short v) { for( int y=y0; y<y0+h; y++ ) for( int x=x0; x<x0+w; x++ ) piece[y][x] = v; } void Game::fillPieceV(unsigned short color, ...) { va_list arguments; va_start( arguments, color ); int pos; while( (pos = va_arg ( arguments, int)) != 0 ) fillPiece( (pos&0xF000)>>12, (pos&0x0F00)>>8, (pos & 0x00F0) >> 4, (pos & 0x000F) >> 0, color ); va_end( arguments ); } void Game::showImage( unsigned char x, unsigned char y, unsigned short back, unsigned short front, ... ) { fillPieceV( back, 0x0077, 0 ); va_list args; va_start( args, front ); int pos; while( (pos = va_arg ( args, int)) != 0 ) fillPiece( (pos&0xF000)>>12, (pos&0x0F00)>>8, (pos & 0x00F0) >> 4, (pos & 0x000F) >> 0, front ); va_end( args ); disp.draw( (unsigned short *)piece, x, y, 7, 7 ); } void Game::playBam() { if( bamTicksLeft == 0 ) return; if( --bamTicksLeft % 2 ) { led1 = 1; led2 = 1; } else { led1 = 0; led2 = 0; } //pwm.write(0.5); pwm.period_us(50); pwm.pulsewidth_us(50); if (bamTicksLeft == 0) { pwm.write(0.0); fillPieceV( WHITE, 0x0077, 0 ); fillPieceV( RED, 0x1111, 0x5111, 0x1511, 0x5511, 0x3115, 0x1351, 0x2233, 0 ); disp.draw((unsigned short *)piece, bamX, bamY, 7, 7); } } void Game::playSound() { if( tickCounter == tickWin + 1 ) { pwm = 0.02; pwm.period( 1.0 / 330.0 ); } if( tickCounter == tickWin + 9 ) { pwm = 0.02; pwm.period( 1.0 / 440.0 ); } if( tickCounter == tickWin + 25 ) { pwm = 0; pwm.period_ms(1); } }