Cactus Jumper
Description
This project uses the uLCDD 144-G2 LCD along with a navigation switch to create an obstacle-dodging game. The player controls the character on-screen to avoid the obstacles (with randomly-generated positions) to try and earn a high score. The game ends when the player makes contact with one of the obstacles. If the player has earned a new high score, they will be taken to the initial input screen, and their score and initials will be saved to the SD card so that their score will be displayed at the start menu. The game has separate threads for handling user input and displaying the on-screen graphics. The images used for the obstacles and character are stored on the microSD card on the uLCD.
Components
uLCD 144-G2
5-way Tactile Navigation Switch Breakout Board
Hookup Guide
Navigation Switch
Mbed | NavSwitch |
---|---|
gnd | - |
p21 | R |
p22 | D |
p23 | L |
p24 | C |
p25 | U |
nc | + |
LCD Screen
Mbed | uLCD cable |
---|---|
gnd | GND |
VU | +5V |
p9 | TX |
p10 | RX |
p11 | RES |
Image
Video
Code
Import programCactusJumper
Mini game developed for ECE 4180 lab
main.cpp
// 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(); }
entity.cpp
#include "entity.h" void evalScreens(Screen **s) { if((*s[1]).pos > 127) { //delete screen, shift old screen 1 to screen 0, create new screen 1 delete s[1]; s[1] = s[0]; //s[0] = new Screen(0x780D, -127); s[0] = new Screen(0x780D, true,-127); } (*s[0]).decScreen(); (*s[1]).decScreen(); } void drawScreens(uLCD_4DGL *u, Screen **s) { //Only draw left-most screen objects if it is not in its initial position if((*s[0]).pos > -127) { //overwrite previous location of blocks with bg color for(int j = 0;j<=3;j++) { DrawCoverUp((*(*s[0]).obs[j]).row, (*(*s[0]).obs[j]).col - DELTA_X,(*(*s[0]).obs[j]).w - 1,(*(*s[0]).obs[j]).h - 1,u); } //draw obstacles in new positions DrawSliceBySlice((*s[0]).obs[0], u); DrawSliceBySlice((*s[0]).obs[1], u); DrawSliceBySlice((*s[0]).obs[2], u); DrawSliceBySlice((*s[0]).obs[3], u); } //Since s[1] is always on-screen, draw its objects and any necessary cover-up boxes for(int i = 0;i<=3;i++) { DrawCoverUp((*(*s[1]).obs[i]).row, (*(*s[1]).obs[i]).col - DELTA_X,(*(*s[1]).obs[i]).w - 1, (*(*s[1]).obs[i]).h - 1,u); } //draw blocks in new positions DrawSliceBySlice((*s[1]).obs[0], u); DrawSliceBySlice((*s[1]).obs[1], u); DrawSliceBySlice((*s[1]).obs[2], u); DrawSliceBySlice((*s[1]).obs[3], u); } void drawPlayer(uLCD_4DGL *u, Player *p) { //(*u).filled_rectangle((*p).col,(*p).row,(*p).col + 15,(*p).row + 31, (*p).color); if((*p).isJumping) { (*u).set_sector_address(0x001D, 0x78A5); //set jumping sector } else if((*p).isFalling) { (*u).set_sector_address(0x001D, 0x78A2); //set falling sector } else { (*u).set_sector_address(0x001D, 0x78A8); } //set neutral sector (*u).display_image((*p).col, (*p).row); } void drawPlayerCoverUp(uLCD_4DGL *u, Player *p) { //(*u).filled_rectangle((*p).col - (((*p).moveFlag & 2) >> 1) + ((*p).moveFlag & 1),(*p).row,(*p).col + 15,(*p).row + 31, 0x000000); (*u).filled_rectangle((*p).col - (DELTA_X_P * (((*p).moveFlag & 2) >> 1)) + (((*p).w * ((*p).moveFlag & 1)) + 0),(*p).row,(*p).col - (1 * (((*p).moveFlag & 2) >> 1)) + ((16 * ((*p).moveFlag & 1)) + (DELTA_X_P * ((*p).moveFlag & 1))),(*p).row + 31, COVER_COLOR); } void drawPlayerCoverUp(uLCD_4DGL *u, Player *p, int dir) { if((*p).moveFlag == MOVE_RIGHT) { (*u).filled_rectangle((*p).col - DELTA_X_P - 1,(*p).row,(*p).col - 1,(*p).row + (*p).h - 1,COVER_COLOR); } if((*p).moveFlag == MOVE_LEFT) { (*u).filled_rectangle((*p).col + (*p).w,(*p).row,(*p).col + (*p).w + DELTA_X_P + 1,(*p).row + (*p).h - 1,COVER_COLOR); } } /*void drawPlayerAirborneCoverUp(uLCD_4DGL *u, Player *p) { (*u).filled_rectangle((*p).col, (*p).row - (((*p).isFalling && ((*p).fallCounter >= 0)) ? DELTA_Y : 0) + (((*p).isJumping && ((*p).upCounter >= 0)) ? 32 : 0),(*p).col + 15, (*p).row - (((*p).isFalling && ((*p).fallCounter >= 0)) ? 1 : 0) + (((*p).isJumping && ((*p).upCounter >= 0)) ? 32 + DELTA_Y : 0), COVER_COLOR); }*/ void drawPlayerAirborneCoverUp(uLCD_4DGL *u, Player *p) { if((*p).isJumping) { //draw a cover-up box below the player (*u).filled_rectangle((*p).col,(*p).row + (*p).h,(*p).col + (*p).w - 1,(*p).row + (*p).h + DELTA_Y,COVER_COLOR); } if((*p).isFalling) { //draw a cover-up box above the player (*u).filled_rectangle((*p).col,(*p).row - DELTA_Y - 1, (*p).col + (*p).w - 1, (*p).row - 1,COVER_COLOR); } } void drawPlayerDiagCoverUp(uLCD_4DGL *u, Player *p) { if((*p).isJumping) { if((*p).moveFlag == MOVE_RIGHT) { (*u).filled_rectangle((*p).col - DELTA_X_P,(*p).row + (*p).h, (*p).col - 1, (*p).row + (*p).h +DELTA_Y - 1, COVER_COLOR); } if((*p).moveFlag == MOVE_LEFT) { (*u).filled_rectangle((*p).col + (*p).w,(*p).row + (*p).h, (*p).col + (*p).w + DELTA_X_P - 1, (*p).row + (*p).h + DELTA_Y - 1, COVER_COLOR); } } if((*p).isFalling) { if((*p).moveFlag == MOVE_RIGHT) { (*u).filled_rectangle((*p).col - DELTA_X_P,(*p).row - DELTA_Y,(*p).col - 1, (*p).row - 1,COVER_COLOR); } if((*p).moveFlag == MOVE_LEFT) { (*u).filled_rectangle((*p).col + (*p).w, (*p).row - DELTA_Y, (*p).col + (*p).w + DELTA_X_P - 1, (*p).row - 1, COVER_COLOR); } } } void DrawIfOnScreen(Obstacle *o, uLCD_4DGL *u) { if(((*o).col >= 0) || (((*o).col + (*o).w - 1) > 0)) { //If entity is on-screen if((*o).col < 0) { (*u).filled_rectangle(0,(*o).row,(*o).w - 1 + (*o).col,(*o).row + (*o).h - 1,(*o).color);//If left side is not on screen } else if(((*o).col + 15) > 127) { (*u).filled_rectangle((*o).col,(*o).row,127,(*o).row + (*o).h - 1,(*o).color);//Else if right side not on screen } else { (*u).filled_rectangle((*o).col,(*o).row,(*o).col + (*o).w - 1,(*o).row + (*o).h - 1,(*o).color); //Else all of the entity is on the screen } } } void DrawSliceBySlice(Obstacle *o, uLCD_4DGL *u) { /*for(int i = 0; i<=15;i++) { if((*o).col + i > 0 && (*o).col + i <= 127) { (*u).set_sector_address(0x001D, 0x788F + i); (*u).display_image((*o).col + i, (*o).row); } }*/ //(*u).set_sector_address(0x001D, 0x789F); //(*u).display_image((*o).col, (*o).row); if(((*o).col >= 0) || (((*o).col + (*o).w - 1) > 0)) { //If entity is on-screen if((*o).col < 0) { //If the left side is off-screen //set sector for particular slice if((*o).w + (*o).col - 2 < 8) { //+1 addition to pick sector (*u).set_sector_address(0x001D, 0x78AB + (*o).w + (*o).col - 2); } else { //+2 addition to pick sector (*u).set_sector_address(0x001D, 0x78B4 + ((((*o).w + (*o).col - 2) % 8) * 2)); } //draw the object (*u).display_image(0, (*o).row); } else if(((*o).col + 15) > 127) { //If the right side is off-screen if(127 - (*o).col < 8) { //-1 to pick sector (*u).set_sector_address(0x001D,0x78D8 - ((127 - (*o).col) % 8)); } else { //-2 to pick sector (*u).set_sector_address(0x001D,0x78D2 - (((127 - (*o).col) % 8) * 2)); } //draw the object (*u).display_image((*o).col, (*o).row); } else { //Otherwise the entire object is on-screen (*u).set_sector_address(0x001D, 0x789F); (*u).display_image((*o).col, (*o).row); } } } void DrawCoverUp(int row, int col, int w, int h, uLCD_4DGL *u) { if((col >= 0) || ((col + w) > 0)) { //If entity is on-screen if(col < 0) { //(*u).filled_rectangle(0,row,15+col,row + 15,0x000000);//If left side is not on screen } else if((col + w) > 127) { (*u).filled_rectangle(col,row,col + DELTA_X - 1,row + h,COVER_COLOR);//Else if right side not on screen } else { (*u).filled_rectangle(col,row,col + DELTA_X - 1,row + h,COVER_COLOR); //Else all of the entity is on the screen } } } void drawScenery(uLCD_4DGL *u) { (*u).filled_rectangle(0,0,127,7,0xf09860); (*u).filled_rectangle(0,8,127,15,0xf0a870); (*u).filled_rectangle(0,16,127,23,0xf0b880); (*u).filled_rectangle(0,24,127,31,0xf0c890); (*u).set_sector_address(0x001D,0x791A); (*u).display_image(0,0); } void drawScore(uLCD_4DGL *u, int score) { char scoreChar[15]; sprintf(scoreChar,"%d",score); (*u).textbackground_color(0xf09860); (*u).locate(11-strlen(scoreChar),0); (*u).printf("Score: %s",scoreChar); } //Collision detection functions void CollisionDetect(Screen **s, Player *p,bool *flag) { if((*s[0]).pos > -127) { //Check if the player has collided with any of s[0]'s objects for(int j = 0;j<=3;j++) { if(detectTR((*s[0]).obs[j],p) || detectBL((*s[0]).obs[j],p) || detectBR((*s[0]).obs[j],p) || detectTL((*s[0]).obs[j],p)) { //mark player as collided //(*p).color = 0xFF00FF; //mark block as collided //(*(*s[0]).obs[j]).color = 0x00FFFF; //set the collided flag to true *flag = true; } } } //Check if the player has collided with any of s[1]'s objects for(int i = 0;i<=3;i++) { if(detectTR((*s[1]).obs[i],p) || detectBL((*s[1]).obs[i],p) || detectBR((*s[1]).obs[i],p) || detectTL((*s[1]).obs[i],p)) { //mark player as collided //(*p).color = 0xFF00FF; //mark block as collided //(*(*s[1]).obs[i]).color = 0x00FFFF; //set the collided flag to true *flag = true; } } } bool detectTR(Obstacle *o,Player *p) { //return true if the top right corner of the player overlaps with an object return ((((*o).col + (*o).w - 1) >= (*p).col) && (((*o).col + (*o).w - 1) <= (*p).col + (*p).w - 1) && (((*o).row >= (*p).row) && ((*o).row <= ((*p).row + (*p).h - 1)))); } bool detectBL(Obstacle *o,Player *p) { //return true if the bottom left corner of the player overlaps with an object return ((((*o).col) >= (*p).col) && (((*o).col) <= (*p).col + (*p).w - 1) && (((*o).row + (*o).h - 1 >= (*p).row) && ((*o).row + (*o).h - 1 <= ((*p).row + (*p).h - 1)))); } bool detectBR(Obstacle *o,Player *p) { //return true if the bottom right corner of the player overlaps with an object return ((((*o).col + (*o).w - 1) >= (*p).col) && (((*o).col + (*o).w - 1) <= (*p).col + (*p).w - 1) && (((*o).row + (*o).h - 1 >= (*p).row) && ((*o).row + (*o).h - 1 <= ((*p).row + (*p).h - 1)))); } bool detectTL(Obstacle *o, Player *p) { //return true if the top left corner of the player overlaps with an object return ((((*o).col) >= (*p).col) && (((*o).col) <= (*p).col + (*p).w - 1) && (((*o).row >= (*p).row) && ((*o).row <= ((*p).row + (*p).h - 1)))); } /* //functions that belong to the Screen class */ void Screen::decScreen(void) { //increment screen position and object positions so that they can move off-screen pos+=DELTA_X; (*obs[0]).col+=DELTA_X; (*obs[1]).col+=DELTA_X; (*obs[2]).col+=DELTA_X; (*obs[3]).col+=DELTA_X; //decrement position of objects associated with screen } Screen::Screen(int bg, int initPos) { bgAddr = bg; pos = initPos; int j; for(j = 0;j<=3;j++) { obs[j] = new Obstacle(0x00FF00); (*obs[j]).col = initPos + (16*j) + j; (*obs[j]).row = 111; } } //new default constructor Screen::Screen(int bg, bool randomSpots, int initPos) { pos = initPos; for(int j = 0;j<=3;j++) { obs[j] = new Obstacle(0x0000FF); } //Pick random locations within the screen for the objects (*obs[0]).col = initPos + (rand() % 2) * 16; (*obs[1]).col = ((rand() % 2) * 16) + (*obs[0]).col; (*obs[2]).col = ((rand() % 2) * 16) + (*obs[1]).col; (*obs[3]).col = ((rand() % 2) * 16) + (*obs[2]).col; //set height to either 16 or 32 pixels for object for(int j = 0;j<=3;j++) { (*obs[j]).h = ((rand() % 2) == 1 ? H_32 : H_16); (*obs[j]).w = H_16; (*obs[j]).row = 127-(*obs[j]).h; } } Screen::~Screen(void) { //free the space for the deleted screen's obstacles in memory delete obs[0]; delete obs[1]; delete obs[2]; delete obs[3]; } /* //Functions that belong to the Obstacle class */ Obstacle::Obstacle(int c) { color = c; w = 16; h = 16; row = 0; col = 0; } /* //Function that belong to the Player class */ Player::Player(void) { //set default variables so that the player is in the bottom-right corner when the game begins w = H_16; h = H_32; color = 0xFF0000; //color is deprecated, since we're using images now col = 111; row = 95; hasMoved = false; moveFlag = 0; isFalling = false; isJumping = false; upCounter = -1; fallCounter = -1; } /* // Functions that belong to the cursor class */ Cursor::Cursor(void) { //set default cursor position so that the cursor is over 'A' on the high score screen row = 30; col = 5; s = 10; curChar = 'A'; delta_x = 14; delta_y = 16; hasMoved = false; letterPressed = false; c = 0; moveFlag = 0; } void Cursor::draw(uLCD_4DGL *u) { //draw the cursor rectangle at the current position (*u).rectangle(col,row,col + s,row + s,0xFF3300); } void Cursor::coverUp(uLCD_4DGL *u) { //draw a rectangle with the BG color at the previous cursor position to cover up the rectangle left behind by previous draw function (*u).rectangle(col + ((moveFlag & MOVE_LEFT) * ((delta_x - s) + s)) - (((moveFlag & MOVE_RIGHT) >> 1) * ((delta_x - s) + s)), row + (((moveFlag & MOVE_UP)>>2) * ((delta_y - s) + s)) - (((moveFlag & MOVE_DOWN)>>3) * ((delta_y - s) + s)), (col + s) + ((moveFlag & MOVE_LEFT)* ((delta_x - s) + s)) - (((moveFlag & MOVE_RIGHT) >> 1) * ((delta_x - s) + s)), row + s + (((moveFlag & MOVE_UP)>>2) * ((delta_y - s) + s)) - (((moveFlag & MOVE_DOWN)>>3) * ((delta_y - s) + s)), COVER_COLOR); }
entity.h
#include "mbed.h" #include "rtos.h" #include "uLCD_4DGL.h" #define DELTA_Y 3 #define DELTA_X 3 #define DELTA_X_P 2 #define COVER_COLOR 0xf0c890 #define H_32 32 #define H_16 16 #define STATE_START 0 #define STATE_GAME 1 #define STATE_LOSE 2 #define STATE_SCORE 4 #define MOVE_LEFT 1 #define MOVE_RIGHT 2 #define MOVE_UP 4 #define MOVE_DOWN 8 class Entity { private: public: //y position of an entity (in pixels) int row; //x position of an entity (in pixels) int col; }; class Cursor : public Entity { public: //size of the s by s square cursor int s; //space that the cursor will move when the joystick is pressed left or right int delta_x; //space that the cursor will move when the joystick is pressed up or down int delta_y; //buffer that will contain the initials for a new high score char initBuf[3]; int c; //flag to see if the user moved the cursor bool hasMoved; //flag to see if the user has pressed the fire button on the high score screen bool letterPressed; //numerical value assoicated with a particular movement int moveFlag; //the last letter that the cursor selected on letterPressed char curChar; //default no-arg constructor Cursor(void); //function to draw the cursor on screen void draw(uLCD_4DGL *u); //function to cover up the previous position of the cursor void coverUp(uLCD_4DGL *u); }; class Player : public Entity { public: //Width of the p;ayer in pixels int w; //Height of the player in pixels int h; //(deprecated) color of the player in RGB int color; //default no-arg constructor Player(void); //flag to see if the user has moved using the joystick bool hasMoved; //flag to see if the user is jumping bool isJumping; //flag to see if the user is falling bool isFalling; //Used to keep track of how long until the player reaches the apex of the jump int upCounter; //Used to check how long until the player lands int fallCounter; //value representing some movement of direction int moveFlag; }; class Obstacle : public Entity { public: //(deprecated) color of the obstacle in RGB int color; //width of the obstacle in pixels int w; //height of the obstacle in pixels int h; //default constructor; color input variable is deprecated Obstacle(int c); }; class Counter : public Entity { }; class Screen { private: public: //(deprecated) sector address of the screen's background int bgAddr; //current position, on or off-screen, in pixels int pos; // void drawScreen(void); //increase the position values of each object and screen, so that they appear to be moving void decScreen(void); //default constructor Screen(int bg, int initPos); //main constructor, though the boolean flag serves no purpose and should be removed Screen(int bg, bool randomSpots, int initPos); //the 4 cactus obstacles associated with this screen Obstacle *obs[4]; //Class destructor. Needed to delete both the screen and its associated obstacle objects ~Screen(void); }; //(Deprecated) draw the rectangles of the obstacles while also checking if they are on-screen void DrawIfOnScreen(Obstacle *o, uLCD_4DGL *u); //draw the cactus image for each obstacle, also checking if any part of the obstacle is off-screen, and drawing the appropriate image if so void DrawSliceBySlice(Obstacle *o, uLCD_4DGL *u); //Draw a filled rectangle with the background color to hide the pixels of the previous position of an object void DrawCoverUp(int row, int col, int w, int h, uLCD_4DGL *u); //Check if any screens are now past the player, and rearrange the screens if so void evalScreens(Screen **s); //draw all objects associated with a screen void drawScreens(uLCD_4DGL *u, Screen **s); //draw the player sprite void drawPlayer(uLCD_4DGL *u, Player *p); //(deprecated) draw the cover up rectangle for x-axis movement of the player void drawPlayerCoverUp(uLCD_4DGL *u, Player *p); //Draw the cover up rectangle for x-axis movement of the player void drawPlayerCoverUp(uLCD_4DGL *u, Player *p, int dir); //draw the cover up rectangle for y-axis movement of the player void drawPlayerAirborneCoverUp(uLCD_4DGL *u, Player *p); //Cover up the small square that occurs if the user moves diagonally void drawPlayerDiagCoverUp(uLCD_4DGL *u, Player *p); //Draw the sun and any other background objects void drawScenery(uLCD_4DGL *u); //Collision Detection //check a collision on the top-right corner of the player bool detectTR(Obstacle *o,Player *p); //check a collision on the bottom-left corner of the player bool detectBL(Obstacle *o,Player *p); //check a collision on the bottom-right corner of the player bool detectBR(Obstacle *o,Player *p); //check a collision on the top-left corner of the player bool detectTL(Obstacle *o, Player *p); //main function for collision detection; runs previous four functions and sets appropriate flags void CollisionDetect(Screen **s, Player *p,bool *flag); //draw the score counter on the right side of the screen void drawScore(uLCD_4DGL *u, int score); //Reset flags and other objects for a new game void initialize(Screen **s, Player *p, int *score, bool* initFlash, bool *scDrawn, bool *collide, int *c, int *r, Cursor *curs);
Please log in to post comments.