A reproduction of the 70's classic. Enjoy!
Dependencies: NokiaLCD SDFileSystem SIgame mbed-rtos mbed wave_player
main.cpp
- Committer:
- zlee9
- Date:
- 2013-03-07
- Revision:
- 1:02e3c9b77580
- Parent:
- 0:fcfeec8463fa
File content as of revision 1:02e3c9b77580:
/***************************************************************/ /***************************************************************/ /*** ***/ /*** Space Invaders Simulator ***/ /*** ***/ /*** ECE 4180 Developer Team: Space Pirates ***/ /*** Members: David Gaspard, Zhe Cheng Lee ***/ /*** ***/ /***************************************************************/ /***************************************************************/ /***************************************************************/ /* */ /* Libaries */ /* */ /***************************************************************/ #include "mbed.h" #include "NokiaLCD.h" #include "SIgame.h" #include "rtos.h" #include "SDFileSystem.h" #include "wave_player.h" /***************************************************************/ /* */ /* Classes and Global Variables */ /* */ /***************************************************************/ NokiaLCD lcd(p5, p7, p8, p9, NokiaLCD::LCD6610); // mosi, sclk, cs, rst, type DigitalIn button(p20); // Pushbutton for firing laser AnalogIn horiz(p15); // From joystick for steering ship SDFileSystem sd(p11, p12, p13, p14, "sd"); //SD card AnalogOut DACout(p18);//Speaker out wave_player waver(&DACout);//Wave player int state; int doneski;//done playing start music? OBJECT wave[NUM_ALIEN_ROWS][NUM_ALIEN_COLS], wave_old[NUM_ALIEN_ROWS][NUM_ALIEN_COLS]; /***************************************************************/ /* */ /* Prototypes */ /* */ /***************************************************************/ void start(); int game(); void lose(); void win(); void updateScreen(OBJECT ship, OBJECT ship_old, POINT ylaser, POINT ylaser_old, POINT elaser[], POINT elaser_old[], int lives_rem); void playstart(void const *args); void startmusic(void const *args); /***************************************************************/ /* */ /* Main program */ /* */ /***************************************************************/ int main() { doneski=0;//Variable to declare that start screen music thread //was terminated Thread thread(playstart);//Satrt the sound effect thread Thread startmu(startmusic);//start the trigger fire thread state = START;//Begin the game button.mode(PullUp);//Pull up the pushbutton while (1) { // Game loop switch (state) { case START: start(); // Start game state = GAME; break; case GAME: startmu.terminate(); doneski=1; state = game(); // Actual game break; case LOSE: lose(); // Losing screen state = START; break; case WIN: win(); // Winning screen state = START; break; } } } /***************************************************************/ /* */ /* Game-State Procedures */ /* */ /***************************************************************/ void start() { /****** * start * Starts up game ******/ lcd.cls(); lcd.locate(0,4); lcd.printf("SPACE INVADERS"); lcd.locate(0,10); lcd.printf("PRESS BUTTON TO CONTINUE"); WAIT4FULLPUSH(button); } int game() { /****** * game * Handles the main gameplay. Prepares for win state if player destroys all * aliens and lose state if player loses all lives ******/ POINT ylaser, ylaser_old, elaser[ELASER_CAP], elaser_old[ELASER_CAP]; OBJECT ship, ship_old, *sh_alien, *frontline[NUM_ALIEN_COLS]; int time, lives_rem, als_rem, i; float hper; bool reach, left, lcancel; // Set display screen lcd.cls(); lcd.background(BLACK); // Initialize lives_rem = NUM_LIVES_START; als_rem = NUM_ALIENS_START; reach = left = lcancel = false; time = 0; summonWave(); // Starting locations of all alien memcpy(wave_old, wave, sizeof(wave)); // Make copy for aliens' old locations // Keep track of aliens in front of respective columns for (i = 0; i < NUM_ALIEN_COLS; i++) frontline[i] = &wave[NUM_ALIEN_ROWS][i]; // Set up laser structures elaser[0].collide = elaser[1].collide = elaser[2].collide = elaser_old[0].collide = elaser_old[1].collide = elaser_old[2].collide = ylaser.collide = ylaser_old.collide = true; // No lasers on screen yet // Enemy lasers are white elaser[0].color = elaser[1].color = elaser[2].color = WHITE; ylaser.color = GREEN; // Player's laser is green // Set up player's ship ship = startShip(); memcpy(&ship_old, &ship, sizeof(ship)); // Save copy for ship's old locations // Game goes on until player loses all lives, destroy all aliens, or allow // any alien to reach screen border on player's side while (!reach && lives_rem > 0 && als_rem > 0) { /* Laser Movement */ /******************/ // Player's laser is on screen if (!(ylaser.collide)) { if (ylaser.y >= 0) (ylaser.y)-= 3; // Laser travels up to aliens' side else ylaser.collide = true; // Laser vanishes at top of screen } // Enemy lasers is on screen for (i = 0; i < ELASER_CAP; i++) { if (elaser[i].y < SCREENHEIGHT) // Enemy lasers travel down to player's side (elaser[i].y)++; else // Enemy laser vanishes at bottom of screen elaser[i].collide = true; } /* Controls */ /******************/ // Player firing laser if (button && ylaser.collide) { // Initialize laser's locations according to ship's ylaser.y = ship.y - 1; ylaser.x = ship.x + (ship.width >> 1); // Can fire next laser after current hits top of screen or other objects ylaser.collide = false; } // Player steering ship hper = horiz; // Read joystick's horizontal position. if (GOLEFT(hper) && ship.x > 0) (ship.x)--; // Ship moves left/ if (GORIGHT(hper) && ship.x < SCREENWIDTH - 1) (ship.x)++; // Ship moves right /* Alien Activity */ /******************/ // Move wave of aliens. Update whether any alien reaches screen on // player's side reach = moveAlienWave(&left); // Enemy aliens firing lasers. Aliens fire lasers only after certain // time intervals or when one of their lasers canceled out with player's if (time >= RELOAD_TIME || lcancel) { // Choose random front alien to fire laser. Ignore any invalid ones // (those in columns that were completely wiped out have been set to // NULL) while ((sh_alien = frontline[rand() / (RAND_MAX/i + 1)]) == NULL); // Find enemy laser structure not in use for display if (elaser[0].collide) i = 0; else if (elaser[1].collide) i = 1; else i = 2; // Initialize laser's location according to chosen alien's elaser[i].y = sh_alien->y + 1; elaser[i].x = sh_alien->x + (ALIEN_WIDTH >> 1); elaser[i].collide = lcancel = false; time = 0; // Reset time for next enemy laser fire } /* Collisions */ /*******************/ // Cancel out player's laser and enemy laser should they connect lcancel = twoLasersCollide(&ylaser, elaser); // Kill alien if player's laser hits one destroyAlien(&als_rem, &ylaser, frontline); // Check for any enemy laser touching ship for (i = 0; i < ELASER_CAP; i++) { if (!(elaser[i].collide) && elaser[i].y >= ship.y && elaser[i].y <= ship.y + ship.height && elaser[i].x >= ship.x && elaser[i].x <= ship.x + ship.width) { // Plyaer loses life if hit by laser lives_rem--; ship.killed = elaser[i].collide = true; } } updateScreen(ship, ship_old, ylaser, ylaser_old, elaser, elaser_old, lives_rem); // Update gameplay screen ship.killed = false; time++; // Time passes // Update old locations to current memcpy(wave_old, wave, sizeof(wave)); memcpy(elaser_old, elaser, sizeof(elaser)); ylaser_old = ylaser; ship_old = ship; } // End of main gameplay loop // Game's outcomes if (als_rem) // Lost all lives or aliens reached your border return LOSE; else // Destroyed all aliens return WIN; } void win() { /****** * win * Displays congratulation screen and prompt player to replay ******/ // Congratulation screen lcd.cls(); lcd.locate(0,2); lcd.printf("WELL DONE"); lcd.locate(0,5); lcd.printf("EARTHLING"); lcd.locate(0,8); lcd.printf("THIS TIME YOU"); lcd.locate(0,11); lcd.printf("WIN"); wait(2); // Prompt player to play game again lcd.cls(); lcd.locate(0,11); lcd.printf("PRESS BUTTON TO PLAY AGAIN"); WAIT4FULLPUSH(button); } void lose() { /****** * lose * Displays game-over screen and prompts player to replay ******/ // Game-over screen lcd.cls(); lcd.locate(4,3); lcd.printf("YOU SUCK"); wait(2); // Prompt player to play game again lcd.locate(0,10); lcd.printf("PRESS BUTTON TO PLAY AGAIN"); WAIT4FULLPUSH(button); } /***************************************************************/ /* */ /* Game-Drawing Funntion */ /* */ /***************************************************************/ void updateScreen(OBJECT ship, OBJECT ship_old, POINT ylaser, POINT ylaser_old, POINT elaser[], POINT elaser_old[], int lives_rem) { /****** * updateScreen * Updates game display on Nokia LCD screen ******/ int r, c; // Old locations are drawn with black to erase previous images in display // when redrawing images wait(0.02); // Redraw surviving aliens from their positions for (c = 0; c < NUM_ALIEN_COLS; c++) { for (r = 0; r < NUM_ALIEN_ROWS; r++) { lcd.fill(wave_old[r][c].x, wave_old[r][c].y, wave_old[r][c].width, wave_old[r][c].height, BLACK); // Aliens as white rectangles if (!(wave[r][c].killed)) // Don't draw destroyed aliens lcd.fill(wave[r][c].x, wave[r][c].y, wave[r][c].width, wave[r][c].height, wave[r][c].color); } } // Redraw enemy lasers as single white pixels for (c = 0; c < ELASER_CAP; c++) { lcd.pixel(elaser_old[c].x, elaser_old[c].y, BLACK); lcd.pixel(elaser_old[c].x+1, elaser_old[c].y, BLACK); lcd.pixel(elaser_old[c].x, elaser_old[c].y+1, BLACK); lcd.pixel(elaser_old[c].x+1, elaser_old[c].y+1, BLACK); // Don't draw lasers that hit bottom screen border or other objects if (!(elaser[c].collide)) { lcd.pixel(elaser[c].x, elaser[c].y, elaser[c].color); lcd.pixel(elaser[c].x+1, elaser[c].y, elaser[c].color); lcd.pixel(elaser[c].x, elaser[c].y+1, elaser[c].color); lcd.pixel(elaser[c].x+1, elaser[c].y+1, elaser[c].color); } } // Redraw player's laser as single green pixel. Check that laser doesn't // hit top screen border or other objects lcd.pixel(ylaser_old.x, ylaser_old.y, BLACK); lcd.pixel(ylaser_old.x+1, ylaser_old.y, BLACK); lcd.pixel(ylaser_old.x, ylaser_old.y+1, BLACK); lcd.pixel(ylaser_old.x+1, ylaser_old.y+1, BLACK); if (!(ylaser.collide)) lcd.pixel(ylaser.x, ylaser.y, ylaser.color); lcd.pixel(ylaser.x+1, ylaser.y, ylaser.color); lcd.pixel(ylaser.x, ylaser.y+1, ylaser.color); lcd.pixel(ylaser.x+1, ylaser.y+1, ylaser.color); if (ship.killed) { // Ship is destroyed from being hit by laser lcd.locate(0,15); lcd.printf("LIVES: %d", lives_rem); wait(2); // Game pauses for few seconds before player uses next life lcd.cls(); // Clear lives message } // Redraw player's ship as green rectangle lcd.fill(ship_old.x, ship_old.y, ship_old.width, ship_old.height, BLACK); lcd.fill(ship.x, ship.y, ship.width, ship.height, ship.color); } /***************************************************************/ /* */ /* This function plays the lose/win screen music and generates */ /* the firing sound effect */ /* */ /***************************************************************/ void playstart(void const *args)//Th { //Depending on the state of the game, //queue either screen music or play sound effect upon fire while(true) { FILE *wave_file; //At the start screen, do nothing while(state==START) { Thread::wait(50); } //wait 500ms after start screen music has been cutoff before //continuing to avoid conflicts while(!doneski) { Thread::wait(500); } //While in the game, play firing sound when the player fires while(state==GAME) { if(button) { wave_file=fopen("/sd/mample4.wav","r"); waver.play(wave_file); fclose(wave_file); } } //Play losing screen music while(state==LOSE) { wave_file=fopen("/sd/mample3.wav","r"); waver.play(wave_file); fclose(wave_file); } //Play winning screen music while(state==WIN) { wave_file=fopen("/sd/mample3.wav","r"); waver.play(wave_file); fclose(wave_file); } } } /***************************************************************/ /* */ /* startmusic() plays the start screen music */ /* */ /***************************************************************/ void startmusic(void const *args) { FILE *wave_file; wave_file=fopen("/sd/mample2.wav","r"); waver.play(wave_file); fclose(wave_file); }