![](/media/cache/group/default_image.jpg.50x50_q85.jpg)
Updated Space Invaders on the mbed. Improved upon Michael Son's "Mbed Space Invaders" at https://os.mbed.com/users/michaeljson/notebook/mbed-space-invaders/.
Dependencies: mbed wave_player mbed-rtos 4DGL-uLCD-SE SparkfunAnalogJoystick SDFileSystem LSM9DS1_Library_cal_updated
Fork of Two-PlayerSpaceInvaders by
test
Diff: main.cpp
- Revision:
- 0:3817adfaeb06
- Child:
- 1:618aa2c4ca6a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Mar 15 19:09:51 2016 +0000 @@ -0,0 +1,698 @@ +#include "mbed.h" +#include "SDFileSystem.h" +#include "wave_player.h" +#include "enemy.h" +#include "player.h" +#include "missile.h" +#include "globals.h" +#include "rtos.h" +#include <string> + +/* ==== Navigation Switch ===== */ +class Nav_Switch +{ +public: + Nav_Switch(PinName up,PinName down,PinName left,PinName right,PinName fire); + int read(); +//boolean functions to test each switch + bool up(); + bool down(); + bool left(); + bool right(); + bool fire(); +//automatic read on RHS + operator int (); +//index to any switch array style + bool operator[](int index) { + return _pins[index]; + }; +private: + BusIn _pins; + +}; +Nav_Switch::Nav_Switch (PinName up,PinName down,PinName left,PinName right,PinName fire): + _pins(up, down, left, right, fire) +{ + _pins.mode(PullUp); //needed if pullups not on board or a bare nav switch is used - delete otherwise + wait(0.001); //delays just a bit for pullups to pull inputs high +} +inline bool Nav_Switch::up() +{ + return !(_pins[0]); +} +inline bool Nav_Switch::down() +{ + return !(_pins[1]); +} +inline bool Nav_Switch::left() +{ + return !(_pins[2]); +} +inline bool Nav_Switch::right() +{ + return !(_pins[3]); +} +inline bool Nav_Switch::fire() +{ + return !(_pins[4]); +} +inline int Nav_Switch::read() +{ + return _pins.read(); +} +inline Nav_Switch::operator int () +{ + return _pins.read(); +} + +// Platform initialization +uLCD_4DGL uLCD(p28,p27,p29); // LCD (serial tx, serial rx, reset pin;) +AnalogOut DACout(p18); // speaker +wave_player waver(&DACout); // wav player +SDFileSystem sd(p5, p6, p7, p8, "sd"); // SD card and filesystem (mosi, miso, sck, cs) +Nav_Switch myNav(p13, p10, p11, p9, p12); //pin order on Sparkfun breakout +DigitalIn pb(p15); // push button for player misisle fire + +// Initialize all global enemy objects +enemy_t enemy_1; +enemy_t enemy_2; +enemy_t enemy_3; +enemy_t enemy_4; +enemy_t enemy_5; +enemy_t enemy_6; +enemy_t enemy_7; +enemy_t enemy_8; +enemy_t enemy_9; +enemy_t enemy_10; +enemy_t enemy_11; +enemy_t enemy_12; +enemy_t enemy_13; +enemy_t enemy_14; +enemy_t enemy_15; + +// Initialize variables +int numOfEnemies = 0; +int ENEMY_MOVE = 1; +int MOVE_DOWN = 0; +int DIRECTION = 1; +int firing_col = 0; +int hit_player = 0; +bool lose = false; +int lives = 3; +bool game_menu = false; +bool begin_game = false; +bool gameover = false; + +// Initialize global player object +player_t player; + +// Intialize global player and enemy missile +missile_t missile; // player missile +missile_t enemy_missile; // enemy missile + +// Array of enemy objects +enemy_t * enemyArray[15]; + +// Function Prototypes +void move_enemy_down(); +void playstart(void const *args); + +// Draws the enemies at the initial starting location +void draw_enemies_level() +{ + // Initialize local variables + unsigned int start_x_pos = 12; + unsigned int start_enemy_y_pos = 20; + numOfEnemies = 15; + + // First Row of Enemies + enemy_init(&enemy_1,start_x_pos,start_enemy_y_pos,WHITE); // initialize x-pos and y-pos and color of enemy + enemy_show(&enemy_1); // displays the enemy on uLCD + + enemy_init(&enemy_2,start_x_pos+15,start_enemy_y_pos,WHITE); + enemy_show(&enemy_2); + + enemy_init(&enemy_3,start_x_pos+30,start_enemy_y_pos,WHITE); + enemy_show(&enemy_3); + + enemy_init(&enemy_4,start_x_pos+45,start_enemy_y_pos,WHITE); + enemy_show(&enemy_4); + + enemy_init(&enemy_5,start_x_pos+60,start_enemy_y_pos,WHITE); + enemy_show(&enemy_5); + + // Second Row of Enemies + enemy_init(&enemy_6,start_x_pos,start_enemy_y_pos+12,WHITE); + enemy_show(&enemy_6); + + enemy_init(&enemy_7,start_x_pos+15,start_enemy_y_pos+12,WHITE); + enemy_show(&enemy_7); + + enemy_init(&enemy_8,start_x_pos+30,start_enemy_y_pos+12,WHITE); + enemy_show(&enemy_8); + + enemy_init(&enemy_9,start_x_pos+45,start_enemy_y_pos+12,WHITE); + enemy_show(&enemy_9); + + enemy_init(&enemy_10,start_x_pos+60,start_enemy_y_pos+12,WHITE); + enemy_show(&enemy_10); + + // Third Row of Enemies + enemy_init(&enemy_11,start_x_pos,start_enemy_y_pos+24,WHITE); + enemy_show(&enemy_11); + + enemy_init(&enemy_12,start_x_pos+15,start_enemy_y_pos+24,WHITE); + enemy_show(&enemy_12); + + enemy_init(&enemy_13,start_x_pos+30,start_enemy_y_pos+24,WHITE); + enemy_show(&enemy_13); + + enemy_init(&enemy_14,start_x_pos+45,start_enemy_y_pos+24,WHITE); + enemy_show(&enemy_14); + + enemy_init(&enemy_15,start_x_pos+60,start_enemy_y_pos+24,WHITE); + enemy_show(&enemy_15); + + // Put enemy objects into array + enemyArray[0] = &enemy_1; + enemyArray[1] = &enemy_2; + enemyArray[2] = &enemy_3; + enemyArray[3] = &enemy_4; + enemyArray[4] = &enemy_5; + enemyArray[5] = &enemy_6; + enemyArray[6] = &enemy_7; + enemyArray[7] = &enemy_8; + enemyArray[8] = &enemy_9; + enemyArray[9] = &enemy_10; + enemyArray[10] = &enemy_11; + enemyArray[11] = &enemy_12; + enemyArray[12] = &enemy_13; + enemyArray[13] = &enemy_14; + enemyArray[14] = &enemy_15; +} + +// Draws the player at the initial starting location +void draw_initial_player() +{ + int start_x_pos = 59; + int start_y_pos = 110; + + player_init(&player,start_x_pos,start_y_pos,WHITE); // intialize x-pos and y-pos and color of player + player_show(&player); // display player on uLCD +} + +// Checks all enemies in row 1 +void check_hit_enemy_row1() +{ + int hit_enemy; + + // First Row of Enemies + hit_enemy = check_enemy(&enemy_1, &missile); // checks if the missile hits the enemy and returns 1 if hit, 0 if not hit + numOfEnemies = numOfEnemies - hit_enemy; // updates the number of enemies left + hit_enemy = check_enemy(&enemy_2, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_3, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_4, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_5, &missile); + numOfEnemies = numOfEnemies - hit_enemy; +} + +// Same as check_hit_enemy_row1, but checks enemies at row 2 +void check_hit_enemy_row2() +{ + int hit_enemy; + + // Second Row of Enemies + hit_enemy = check_enemy(&enemy_6, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_7, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_8, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_9, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_10, &missile); + numOfEnemies = numOfEnemies - hit_enemy; +} + +// Same as check_hit_enemy_row1, but checks enemies at row 3 +void check_hit_enemy_row3() +{ + int hit_enemy; + + // Third Row of Enemies + hit_enemy = check_enemy(&enemy_11, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_12, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_13, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_14, &missile); + numOfEnemies = numOfEnemies - hit_enemy; + hit_enemy = check_enemy(&enemy_15, &missile); + numOfEnemies = numOfEnemies - hit_enemy; +} + +// Checks if player is hit +void check_player_hit() +{ + hit_player = check_player(&player, &enemy_missile); // checks if the missile hits the player and returns 1 if hit, 0 if not hit +} + +// Randomly selects an enemy to fire and updates the position of where the missile will fire from +void random_attack_gen() +{ + firing_col = rand() % 5; // selects a random column + + // first checks if the 3rd row closest to the player is alive + if (enemyArray[firing_col+10]->status == ENEMY_ALIVE) + { + // If alive, the enemy missile position is updated to the center of the enemy + enemy_missile.missile_blk_x = enemyArray[firing_col+10]->enemy_blk_x + (enemyArray[firing_col+10]->enemy_width/2); + enemy_missile.missile_blk_y = enemyArray[firing_col+10]->enemy_blk_y + enemyArray[firing_col+10]->enemy_height + 1; + enemy_missile.status = ENEMY_MISSILE_ACTIVE; // sets the enemy missile as active + } + // if enemy at 3rd row is dead, checks the enemy in the 2nd row + else if (enemyArray[firing_col+5]->status == ENEMY_ALIVE) + { + // If alive, the enemy missile position is updated to the center of the enemy + enemy_missile.missile_blk_x = enemyArray[firing_col+5]->enemy_blk_x + (enemyArray[firing_col+5]->enemy_width/2); + enemy_missile.missile_blk_y = enemyArray[firing_col+5]->enemy_blk_y + enemyArray[firing_col+5]->enemy_height + 1; + enemy_missile.status = ENEMY_MISSILE_ACTIVE; + } + // if enemy at 2nd and 3rd row is dead, checks the enemy in the 1st row + else if (enemyArray[firing_col]->status == ENEMY_ALIVE) + { + // If alive, the enemy missile position is updated to the center of the enemy + enemy_missile.missile_blk_x = enemyArray[firing_col]->enemy_blk_x + (enemyArray[firing_col]->enemy_width/2); + enemy_missile.missile_blk_y = enemyArray[firing_col]->enemy_blk_y + enemyArray[firing_col]->enemy_height + 1; + enemy_missile.status = ENEMY_MISSILE_ACTIVE; + } +} + +// moves the enemy +void enemy_motion() +{ + // will move the enemy every 6 loops + if (ENEMY_MOVE % 6 == 0) + { + // FIrst Row of Enemies + MOVE_DOWN = move_enemy(&enemy_1, MOVE_DOWN, DIRECTION); // moves the enemy based on the DIRECTION passed in and also sends global MOVE_DOWN to update in enemy.cpp + MOVE_DOWN = move_enemy(&enemy_2, MOVE_DOWN, DIRECTION); // MOVE_DOWN will be 1 enemies reach the left or right edge of the screen + MOVE_DOWN = move_enemy(&enemy_3, MOVE_DOWN, DIRECTION); // MOVE_DOWN will be 2 if enemies reach the player, otherwise 0 + MOVE_DOWN = move_enemy(&enemy_4, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_5, MOVE_DOWN, DIRECTION); + + // Second Row of Enemies + MOVE_DOWN = move_enemy(&enemy_6, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_7, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_8, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_9, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_10, MOVE_DOWN, DIRECTION); + + // Third Row of Enemies + MOVE_DOWN = move_enemy(&enemy_11, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_12, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_13, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_14, MOVE_DOWN, DIRECTION); + MOVE_DOWN = move_enemy(&enemy_15, MOVE_DOWN, DIRECTION); + + // if MOVE_DOWN is 2, then the enemies have reached the player + if (MOVE_DOWN == 2) + { + lose = true; // set global lose to true to go to gameover screen + } + + // if MOVE_DOWN is 1, update the y-pos of the enemies + if (MOVE_DOWN == 1) + { + move_enemy_down(); // updates the y-pos of the enemies + + // Flips the direction when the enemy moves down + if (DIRECTION == 1) + { + DIRECTION = 2; + } + else + { + DIRECTION = 1; + } + MOVE_DOWN = 0; // sets MOVE_DOWN back to 0 to stop down movement until + } + + ENEMY_MOVE += 1; + } + else + { + ENEMY_MOVE += 1; + } +} + +// moves all the enemies down in the y-direction +void move_enemy_down() +{ + // First Row of Enemies + enemy_erase(&enemy_1); + enemy_erase(&enemy_2); + enemy_erase(&enemy_3); + enemy_erase(&enemy_4); + enemy_erase(&enemy_5); + + enemy_1.enemy_blk_y += enemy_1.enemy_height+4; + enemy_2.enemy_blk_y += enemy_2.enemy_height+4; + enemy_3.enemy_blk_y += enemy_3.enemy_height+4; + enemy_4.enemy_blk_y += enemy_4.enemy_height+4; + enemy_5.enemy_blk_y += enemy_5.enemy_height+4; + + // Second Row of Enemies + enemy_erase(&enemy_6); + enemy_erase(&enemy_7); + enemy_erase(&enemy_8); + enemy_erase(&enemy_9); + enemy_erase(&enemy_10); + + enemy_6.enemy_blk_y += enemy_6.enemy_height+4; + enemy_7.enemy_blk_y += enemy_7.enemy_height+4; + enemy_8.enemy_blk_y += enemy_8.enemy_height+4; + enemy_9.enemy_blk_y += enemy_9.enemy_height+4; + enemy_10.enemy_blk_y += enemy_10.enemy_height+4; + + // Third Row of Enemies + enemy_erase(&enemy_11); + enemy_erase(&enemy_12); + enemy_erase(&enemy_13); + enemy_erase(&enemy_14); + enemy_erase(&enemy_15); + + enemy_11.enemy_blk_y += enemy_11.enemy_height+4; + enemy_12.enemy_blk_y += enemy_12.enemy_height+4; + enemy_13.enemy_blk_y += enemy_13.enemy_height+4; + enemy_14.enemy_blk_y += enemy_14.enemy_height+4; + enemy_15.enemy_blk_y += enemy_15.enemy_height+4; +} + +// thread that plays sounds during game +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; + + // plays intro music during menu screen + while(game_menu) + { + wave_file=fopen("/sd/wavfiles/spacey_sound.wav","r"); + + waver.play(wave_file); + fclose(wave_file); + } + + // Checks in game sound conditions + while(begin_game) + { + // play firing sound when the player fires + if(!pb && missile.status == PLAYER_MISSILE_INACTIVE) { + + wave_file=fopen("/sd/wavfiles/4.wav","r"); + + + waver.play(wave_file); + fclose(wave_file); + } + + // if player hit, play hit sound + if (hit_player) + { + wave_file=fopen("/sd/wavfiles/1.wav","r"); + + waver.play(wave_file); + fclose(wave_file); + } + } + + // players gameover voice if player loses + while(gameover) + { + wave_file=fopen("/sd/wavfiles/game_over.wav","r"); + + waver.play(wave_file); + fclose(wave_file); + } + } +} + +int main() { + + // Initialization of Setup variables + int blk_x, blk_y; + pb.mode(PullUp); + + Thread thread(playstart); // intializes the thread to play sound + + uLCD.baudrate(500000); // set to 500000 to increase smooth gameplay + + // Initialization of Game Menu variables + const int title_x_pos = 2; // initial x-pos of title + const int title_y_pos = 3; // initial y-pos of title + int start_label_x_pos = 7; // start label x-pos + int start_label_y_pos = 7; // start label y-pos + int level_cursor_x_pos = 5; // level cursor x-position + int level_cursor_y_pos = 7; // level cursor y-position + int gameover_x_pos = 5; // gameover label x-position + int gameover_y_pos = 5; // gameover label y-position + int win_x_pos = 2; // congratulations label x-position + int win_y_pos = 5; // congratulations label y-position + int startover_x_pos = 3; // startover label x-position + int startover_y_pos = 8; // startover label y-position + + // intialize temporary score and current score + int temp = 0; + int score = 0; + + // Begin game loop + while(1) + { + // initialize all starting conditions for the beginning of the game + game_menu = true; // defaults to display menu screen + ENEMY_MOVE = true; // defaults to move enemy + DIRECTION = 1; // default to move right + hit_player = 0; // default to not player hit + MOVE_DOWN = 0; // default to not move down + lose = false; // default to not lose + lives = 3; // defaults to 3 lives + score = 0; // default to score of 0 + + uLCD.cls(); + + // Implementation of Game Menu + while(game_menu) + { + uLCD.locate(level_cursor_x_pos,level_cursor_y_pos); // draws cursor next to "START" label + uLCD.printf("->"); + + uLCD.locate(title_x_pos,title_y_pos); // "SPACE INVADERS" title position + uLCD.printf("SPACE INVADERS"); // Title + + uLCD.locate(start_label_x_pos,start_label_y_pos); // "START" label position + uLCD.printf("START"); + + // if pushbutton is pressed, game menu is exited and game begins + if(!pb) + { + game_menu = false; + wait(0.5); + } + } + + begin_game = true; // defaults begin_game to true + + uLCD.cls(); + + // Draw the enemies + draw_enemies_level(); + + // Draw the player + draw_initial_player(); + + // sets the initial position of player missile and enemy missile (later updated) + blk_x = player.player_blk_x+(player.player_width/2); + blk_y = player.player_blk_y; + missile_init(&missile, blk_x, blk_y, WHITE); + enemy_missile_init(&enemy_missile, blk_x, blk_y, WHITE); + + // prints lives + uLCD.locate(0,0); + uLCD.printf("Lives:%i", lives); + + // prints score + uLCD.locate(9,0); + uLCD.printf("Score:%i", score); + + // game play loop + while(begin_game) + { + // updates score + temp = score; + score = (15-numOfEnemies)*15; + + // prints score if score changes + if (score != temp) + { + uLCD.locate(9,0); + uLCD.printf("Score:%i", score); + } + + // move enemy + enemy_motion(); + + // checks if player missile passes y-pos of row1 + if (missile.missile_blk_y+1-missile.missile_height <= enemy_1.enemy_blk_y + && missile.missile_blk_y+1-missile.missile_height >= enemy_1.enemy_blk_y-enemy_1.enemy_height) + { + check_hit_enemy_row1(); + } + + // checks if player missile passes y-pos of row2 + if (missile.missile_blk_y+1-missile.missile_height <= enemy_6.enemy_blk_y + && missile.missile_blk_y+1-missile.missile_height >= enemy_6.enemy_blk_y-enemy_6.enemy_height) + { + check_hit_enemy_row2(); + } + + // checks if player missile passes y-pos of row3 + if (missile.missile_blk_y+1-missile.missile_height <= enemy_11.enemy_blk_y + && missile.missile_blk_y+1-missile.missile_height >= enemy_11.enemy_blk_y-enemy_11.enemy_height) + { + check_hit_enemy_row3(); + } + + // Random Enemy Fire + if (enemy_missile.status == ENEMY_MISSILE_INACTIVE) + { + random_attack_gen(); + } + + // checks if enemy missile passes y-pos of player + if (enemy_missile.missile_blk_y >= player.player_blk_y + && enemy_missile.missile_blk_y <= player.player_blk_y+player.player_height) + { + check_player_hit(); + } + + update_missile_pos(&missile); // updates player missile position + update_enemy_missile_pos(&enemy_missile); // updates enemy missile position + + // Player Movement checked with navigation switch + if (myNav.left() && ((player.player_blk_x-3) > 0)) + { + player_erase(&player); + player.player_blk_x -= 3; + player_show(&player); + } + else if (myNav.right() && ((player.player_blk_x+3) < (128-player.player_width))) + { + player_erase(&player); + player.player_blk_x += 3; + player_show(&player); + } + + // Player Fire + if (pb == 0 && missile.status == PLAYER_MISSILE_INACTIVE) + { + missile.missile_blk_x = player.player_blk_x+(player.player_width/2); + missile.missile_blk_y = player.player_blk_y; + missile.status = PLAYER_MISSILE_ACTIVE; + } + + // checks if player destroyed all enemies + if (numOfEnemies == 0) + { + uLCD.cls(); + + bool win = true; // sets win to true, for win screen + begin_game = false; + + // displays video clip + uLCD.cls(); + uLCD.media_init(); + uLCD.set_sector_address(0x00, 0x00); + uLCD.display_video(0,0); + wait(1); + + uLCD.cls(); + + // prints "Congratulations" on uLCD + uLCD.locate(win_x_pos,win_y_pos); + uLCD.printf("CONGRATULATIONS!"); + + // prints "Play Again?" and "Press pb..." + uLCD.locate(startover_x_pos, startover_y_pos); + uLCD.printf("Play Again?"); + uLCD.locate(startover_x_pos, startover_y_pos+1); + uLCD.printf("Press pb..."); + + // waits at win screen until pushbutton is pressed + while (win) + { + // if pb is pressed, reset game to start menu + if (!pb) + { + win = false; + wait(0.5); + } + } + + } + + // checks if player was hit + if (hit_player) + { + // updates lives + lives -= 1; + wait(0.5); + hit_player = 0; + player_show(&player); + player.status = PLAYER_ALIVE; + + // prints updated lives number + uLCD.locate(0,0); + uLCD.printf("Lives:%i", lives); + } + + // if player loses all lives or enemy reaches the player + if (lose || lives == 0) + { + begin_game = false; // set to false to end game + uLCD.cls(); + + gameover = true; // set to go to display gameover screen + + // prints "GAMEOVER" to uLCD + uLCD.locate(gameover_x_pos, gameover_y_pos); + uLCD.printf("GAMEOVER"); + wait(1); + + // prints "Play Again?" and "Press pb..." + uLCD.locate(startover_x_pos, startover_y_pos); + uLCD.printf("Play Again?"); + uLCD.locate(startover_x_pos, startover_y_pos+1); + uLCD.printf("Press pb..."); + + // stays in gameover screen until pb is pressed + while (gameover) + { + // if pb is pressed, game is reset to the game menu screen + if (!pb) + { + gameover = false; + game_menu = true; + wait(0.5); + } + } + } + + } + } +} \ No newline at end of file