Mini game developed for ECE 4180 lab
Dependencies: 4DGL-uLCD-SE mbed-rtos mbed
main.cpp
- Committer:
- slandry8
- Date:
- 2016-03-14
- Revision:
- 0:a358215f57b7
File content as of revision 0:a358215f57b7:
// Cactus Jumper video game // #include "mbed.h" #include "rtos.h" #include "uLCD_4DGL.h" #include "entity.h" uLCD_4DGL uLCD(p9,p10,p11); // serial tx, serial rx, reset pin; Mutex posMutex; int state = STATE_START; int score; int k; char *scCompBuf; char *writtenScore; char *scoreStr; bool initialFlash = false; bool scoreDrawn = false; bool collided = false; bool newHighScore = false; bool titleDrawn = false; char readchar = ' '; 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 //Thread::wait(1); //delays just a bit for pullups to pull inputs high wait(0.001); } 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(); } Nav_Switch myNav( p25, p22, p23, p21, p24); int i = 111; //variable used for horizontal player movement int j = 96; //variable used for vertical player movement //initialize player and cursor Player *player = new Player(); Cursor *curs = new Cursor(); //thread for player input detection void fire_thread(void const *args) { while(true) { //if player moves to the right during gameplay if(myNav.right() && state == STATE_GAME) { posMutex.lock(); i = ((i > 110) ? 110 : i + DELTA_X_P); (*player).col = i; (*player).hasMoved = true; (*player).moveFlag = 2; posMutex.unlock(); Thread::wait(35); } //if player moves to the left during gameplay if(myNav.left() && state == STATE_GAME) { posMutex.lock(); i = ((i < 2) ? 2 : i - DELTA_X_P); (*player).col = i; (*player).hasMoved = true; (*player).moveFlag = 1; posMutex.unlock(); Thread::wait(35); } posMutex.lock(); //if player jumps during gameplay and is not already in the jumping or falling state if((myNav.up() && !((*player).isJumping || (*player).isFalling)) && state == STATE_GAME) { (*player).isJumping = true; (*player).upCounter = 48; (*player).fallCounter = 48; } posMutex.unlock(); //if fire is pressed on start screen, begin game if(myNav.fire() && state != STATE_GAME && state != STATE_SCORE && state != STATE_LOSE) { state = STATE_GAME; Thread::wait(35); } //Go to either start screen or new height screen when fire is pressed on game over screen if(myNav.fire() && state == STATE_LOSE) { if(!newHighScore) { titleDrawn = false; state = STATE_START; } else { state = STATE_SCORE; } Thread::wait(500); } //Navigation controls for high score screen //if fire is pressed on the new high score screen if(myNav.fire() && state == STATE_SCORE) { //check whether to enter an initial or begin writing initials to file if((*curs).curChar >= 'A' && (*curs).curChar <= 'Z') { (*curs).initBuf[(*curs).c] = (*curs).curChar; } (*curs).letterPressed = true; Thread::wait(200); } //If up is pressed on the new high score screen if(myNav.up() && state == STATE_SCORE) { //make sure cursor would not go out of bounds if moved if(!((*curs).curChar - 8 < 'A')) { (*curs).row -= (*curs).delta_y; (*curs).hasMoved = true; (*curs).moveFlag = 4; (*curs).curChar-=8; } Thread::wait(100); } //If down is pressed on the new high score screen if(myNav.down() && state == STATE_SCORE) { //make sure cursor would not go out of boudns if moved if(!((*curs).curChar + 8 > '[')) { (*curs).row += (*curs).delta_y; (*curs).hasMoved = true; (*curs).moveFlag = 8; (*curs).curChar+=8; } Thread::wait(100); } //If left is pressed on the new high score screen if(myNav.left() && state == STATE_SCORE) { //make sure cursor would not go out of boudns if moved if(!((*curs).curChar == 'A') && !((*curs).curChar == 'I') && !((*curs).curChar == 'Q') && !((*curs).curChar == 'Y')) { (*curs).col -= (*curs).delta_x; (*curs).hasMoved = true; (*curs).moveFlag = 1; (*curs).curChar--; } Thread::wait(100); } //If right is pressed on the new high score screen if(myNav.right() && state == STATE_SCORE) { //make sure cursor would not go out of boudns if moved if(!((*curs).curChar == 'H') && !((*curs).curChar == 'P') && !((*curs).curChar == 'X') && !((*curs).curChar == '[')) { (*curs).col += (*curs).delta_x; (*curs).hasMoved = true; (*curs).moveFlag = 2; (*curs).curChar++; } Thread::wait(100); } } } int main() { //create thread for handling user input Thread thread(fire_thread); //initialize screen pointer array; allocate screen objects in memory Screen *screenP[2]; screenP[0] = new Screen(0x780D,true,-127); screenP[1] = new Screen(0x780D,true,0); //set baud rate & initialize media on uLCD uLCD.baudrate(3000000); uLCD.media_init(); while(true) { if(!(state | STATE_START)) { //start screen if(!titleDrawn) { //we want to only draw this information once newHighScore = false; //initialize game information initialize(screenP, player, &score, &initialFlash, &scoreDrawn, &collided, &i, &j, curs); //draw title screen and text uLCD.set_sector_address(0x001D, 0x78D9); uLCD.display_image(0,0); uLCD.textbackground_color(0x8f7738); uLCD.locate(3,12); uLCD.color(RED); uLCD.printf("Press fire"); uLCD.locate(4,13); uLCD.printf("to start"); uLCD.background_color(COVER_COLOR); //read in high score to display uLCD.set_sector_address(0x001D, 0x8700); uLCD.locate(3,15); readchar = ' '; while(readchar != '\xFF') { readchar = uLCD.read_byte(); uLCD.putc(readchar); } } titleDrawn = true; score = 0; //The remainder of this if() causes the "blinking" of the "Press fire to start" on the title screen Thread::wait(250); uLCD.locate(3,12); uLCD.color(0x8f7738); uLCD.printf("Press fire"); uLCD.locate(4,13); uLCD.printf("to start"); Thread::wait(250); uLCD.locate(3,12); uLCD.color(RED); uLCD.printf("Press fire"); uLCD.locate(4,13); uLCD.printf("to start"); } else if(state & STATE_GAME) { if(!initialFlash) { //we want to clear the screen and draw the background scenery only once when the game starts uLCD.filled_rectangle(0,0,127,127,COVER_COLOR); drawScenery(&uLCD); initialFlash = true; } //draw the obstacles drawScreens(&uLCD, screenP); posMutex.lock(); if((*player).isJumping || (*player).isFalling) { //check if end conditions for each state is currently met if(((*player).upCounter < 0) && ((*player).isJumping)) { //if the player has reached the top of their jump (*player).isJumping = false; } if(((*player).fallCounter < 0) && ((*player).isFalling)) { //if the player has stopped falling (*player).isFalling = false; } //check if the player can enter into a new state if(!(*player).isJumping && ((*player).fallCounter > 0) && (!(*player).isFalling)) { //set the falling condition for the player (*player).isFalling = true; } //decrement jumping or falling counters, if applicable if((*player).isFalling) { (*player).row+=DELTA_Y; (*player).fallCounter-=DELTA_Y; } if((*player).isJumping) { (*player).row-=DELTA_Y; (*player).upCounter-=DELTA_Y; } drawPlayerAirborneCoverUp(&uLCD, player); if((*player).hasMoved) { drawPlayerDiagCoverUp(&uLCD, player); } } if((*player).hasMoved) { //cover up residual pixels from previous location of the player if they have moved //drawPlayerCoverUp(&uLCD, player); drawPlayerCoverUp(&uLCD, player, (*player).moveFlag); } (*player).hasMoved = false; (*player).moveFlag = 0; //detect collision CollisionDetect(screenP,player,&collided); if(collided) { //player has lost if collision detected state = STATE_LOSE; } drawPlayer(&uLCD, player); drawScore(&uLCD, score); posMutex.unlock(); //Evaluate screens, delete old off-screen screens if necessary, and update the score evalScreens(screenP); score++; } else if((state & STATE_LOSE) >> 1) { //draw game over screen, plus NEW HIGH SCORE text if applicable uLCD.textbackground_color(0xf09860); uLCD.locate(6,0); uLCD.printf("GAME OVER "); uLCD.set_sector_address(0x001D, 0x9300); uLCD.locate(1,1); k = 0; if(scCompBuf != NULL) { //delete the previous score that was checked if the game has run once before delete scCompBuf; } scCompBuf = new char[15]; readchar = ' '; //read in the score from the memory location on the SD card while(readchar != '\xFF') { readchar = uLCD.read_byte(); if(readchar >= '0' && readchar <= '9') { scCompBuf[k] = readchar; } k++; } //determine if player should go to high score or title screen on fire if(score > atoi(scCompBuf)) { //new high score newHighScore = true; uLCD.locate(3,3); uLCD.textbackground_color(COVER_COLOR); uLCD.printf("NEW HIGH SCORE"); } } else if((state & STATE_SCORE) >> 2) { //name entry for new high score if(!scoreDrawn) { //Only draw background pieces once uLCD.filled_rectangle(0,0,127,127,COVER_COLOR); uLCD.locate(0,0); uLCD.textbackground_color(COVER_COLOR); uLCD.printf("HIGH SCORE: %d\n\n", score); uLCD.printf("Initials:\n\n"); uLCD.locate(0,4); //Letter select for initials uLCD.printf(" A B C D E F G H \n\n"); uLCD.printf(" I J K L M N O P \n\n"); uLCD.printf(" Q R S T U V W X \n\n"); uLCD.printf(" Y Z "); uLCD.filled_rectangle(36,81,40,85,0x000000); (*curs).draw(&uLCD); scoreDrawn = true; } if((*curs).letterPressed) { //draw initials if((*curs).curChar >= 'A' && (*curs).curChar <= 'Z') { //If selected character is not the END character //pick correct location on screen to draw initial uLCD.locate(10+(*curs).c,2); uLCD.printf("%c",(*curs).initBuf[(*curs).c]); (*curs).c = (((*curs).c < 2) ? (*curs).c + 1 : 2); (*curs).letterPressed = false; } else { //write score to file if(writtenScore == NULL) { //allocate array writtenScore = new char[4 + 15]; } else { delete writtenScore; writtenScore = new char[4 + 15]; } if(scoreStr != NULL) { //delete any previous string representation of score delete scoreStr; } scoreStr = new char[15]; //write score to display into a character array sprintf(writtenScore,"%s %d",(*curs).initBuf,score); //overwrite 0 that would appear after initials on score screen with blank space writtenScore[3] = ' '; //set location of title screen display score uLCD.set_sector_address(0x001D, 0x8700); uLCD.locate(0,12); uLCD.printf("\n\nStoring score..."); for (int i=0; i<strlen(writtenScore); i++) { uLCD.write_byte(writtenScore[i]); //write a byte to SD card } uLCD.flush_media(); //set location for only the score uLCD.set_sector_address(0x001D, 0x9300); //read in score to character array sprintf(scoreStr,"%d",score); for (int i=0; i<strlen(scoreStr); i++) { uLCD.write_byte(scoreStr[i]); //write a byte to SD card } //Reset game once score has been saved titleDrawn = false; state = STATE_START; } } if((*curs).hasMoved) { //cover up old cursor (*curs).coverUp(&uLCD); //draw new cursor (*curs).draw(&uLCD); (*curs).hasMoved = false; (*curs).moveFlag = 0; } } } } void initialize(Screen **s, Player *p, int *score, bool* initFlash, bool *scDrawn, bool *collide, int *c, int *r, Cursor *curs) { //initialize screen (only delete if the screen pointer is not a null pointer if(s[0] != NULL) { delete s[0]; } if(s[1] != NULL) { delete s[1]; } s[0] = new Screen(0x780D,true,-127); s[1] = new Screen(0x780D,true,0); //Initialize or re-initialize player if(p != NULL) { delete p; } p = new Player(); *score = 0; //Initialize or re-initialize flags used during gameplay *initFlash = false; *scDrawn = false; *collide = false; *c = 111; *r = 96; //Initialize or re-initialize the cursor if(curs != NULL) { delete curs; } curs = new Cursor(); }