![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
A simple game
Dependencies: 4DGL-uLCD-SE mbed-rtos mbed
Fork of rtos_signals by
main.cpp
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 #include <mpr121.h> 00004 #include "uLCD_4DGL.h" 00005 #include "Speaker.h" 00006 00007 uLCD_4DGL uLCD(p9,p10,p11); 00008 int curr_x_u, curr_y_u, old_x_u, old_y_u; //user's current and old x,y coordinates 00009 int curr_x_e, curr_y_e, old_x_e, old_y_e; //enemy's current and old x,y coordinates 00010 float dx_e, dy_e, fx_e, fy_e; //x,y velocity of enemy and floating point representation of x,y coordinates 00011 int curr_x_b, curr_y_b, old_x_b, old_y_b; //payload's current and old x,y coordinates 00012 int curr_x_p, curr_y_p, old_x_p, old_y_p; //portal's current and old x,y coordinates 00013 Mutex lcd_mutex; 00014 00015 Thread box; //handles user-payload collision logic 00016 Thread portal; //handles portal logic 00017 00018 Speaker amp(p21); 00019 00020 Serial pc(USBTX, USBRX); //debugging 00021 00022 InterruptIn interrupt(p26); 00023 I2C i2c(p28, p27); 00024 Mpr121 mpr121(&i2c, Mpr121::ADD_VSS); 00025 00026 int score = 0; 00027 int oldscore = 0; 00028 00029 volatile int key = -1; //key pressed from keypad; set via interrupts -> volatile so compiler doesn't optimize out value reads 00030 00031 enum State { START, LIVE, PAUSE, DEAD }; //game status 00032 volatile State s = START; 00033 00034 //interrupt method that runs when keypad has a new value 00035 void fallInterrupt() { 00036 int key_code=0; 00037 int i=0; 00038 int value=mpr121.read(0x00); 00039 value +=mpr121.read(0x01)<<8; 00040 i=0; 00041 for (i=0; i<12; i++) { 00042 if (((value>>i)&0x01)==1) key_code=i+1; 00043 } 00044 key = key_code; 00045 } 00046 00047 //handles portal logic 00048 void portal_thread() { 00049 while(s == LIVE || s == PAUSE) { 00050 while(s == PAUSE); 00051 //if payload and portal collide, score a point and randomize portal location 00052 if (((curr_x_p-3 <= curr_x_b+3 && curr_x_p >= curr_x_b) || (curr_x_p+3 >= curr_x_b-3 && curr_x_p <= curr_x_b)) && ((curr_y_p+3 >= curr_y_b-3 && curr_y_p <= curr_y_b) || (curr_y_p-3 <= curr_y_b+3 && curr_y_p >= curr_y_b))) { 00053 score++; 00054 curr_x_p = (rand() % 106) + 10; 00055 curr_y_p = (rand() % 106) + 10; 00056 } else if (((curr_y_p-3 <= curr_y_b+3 && curr_y_p >= curr_y_b) || (curr_y_p+3 >= curr_y_b-3 && curr_y_p <= curr_y_b)) && ((curr_x_p+3 >= curr_x_b-3 && curr_x_p <= curr_x_b) || (curr_x_p-3 <= curr_x_b+3 && curr_x_p >= curr_x_b))) { 00057 score++; 00058 curr_x_p = (rand() % 106) + 10; 00059 curr_y_p = (rand() % 106) + 10; 00060 } 00061 lcd_mutex.lock(); 00062 //redraw portal and play note if score has changed 00063 uLCD.rectangle(curr_x_p-5, curr_y_p-5, curr_x_p+5, curr_y_p+5, BLUE); 00064 if (score != oldscore) { 00065 amp.PlayNote(1000.0,0.025,0.5); 00066 oldscore = score; 00067 uLCD.rectangle(old_x_p-5, old_y_p-5, old_x_p+5, old_y_p+5, BLACK); 00068 old_x_p = curr_x_p; 00069 old_y_p = curr_y_p; 00070 } 00071 //print score 00072 uLCD.locate(1,15); 00073 uLCD.color(0xFF00FF); 00074 uLCD.printf("%d", score); 00075 lcd_mutex.unlock(); 00076 } 00077 } 00078 00079 //handles user-payload collisions 00080 void box_thread() { 00081 while(s == LIVE) { 00082 old_x_u = curr_x_u; 00083 old_y_u = curr_y_u; 00084 old_x_b = curr_x_b; 00085 old_y_b = curr_y_b; 00086 //if 3 pressed, then go into pause state 00087 if (key==3+1) { 00088 s = PAUSE; 00089 lcd_mutex.lock(); 00090 uLCD.locate(1, 2); 00091 uLCD.color(0xFFFF00); 00092 uLCD.printf("PAUSE"); 00093 //wait until 3 is unpressed 00094 while(key==3+1); 00095 //wait until 3 is pressed 00096 while(key!=3+1); 00097 //wait until 3 is unpressed 00098 while(key==3+1); 00099 uLCD.locate(1, 2); 00100 uLCD.color(BLACK); 00101 uLCD.printf("PAUSE"); 00102 uLCD.color(WHITE); 00103 //countdown from 3 00104 for (int i=3; i>=1; i--) { 00105 uLCD.locate(1, 2); 00106 uLCD.printf("%2D", i); 00107 amp.PlayNote(800.0,0.025,0.5); 00108 wait(1); 00109 } 00110 uLCD.locate(1,2); 00111 uLCD.color(BLACK); 00112 uLCD.printf(" "); 00113 lcd_mutex.unlock(); 00114 //play on 00115 s = LIVE; 00116 } 00117 //really complicated collision logic 00118 //basically checks each way the boxes could be colliding based on which key is pressed (which direction user is moving) 00119 if (key==0+1) { 00120 00121 if ((curr_x_b+6 > curr_x_u-6 && curr_x_u > curr_x_b) && ((curr_y_u+6 > curr_y_b-6 && curr_y_u <= curr_y_b) || (curr_y_u-6 < curr_y_b+6 && curr_y_u >= curr_y_b))) { 00122 curr_x_b-=1; 00123 curr_x_u = curr_x_b+12; 00124 if (curr_x_b < 7) { 00125 curr_x_b = 25; 00126 curr_y_b = 63; 00127 } 00128 } else { 00129 curr_x_u-=1; 00130 } 00131 if (curr_x_u < 7) curr_x_u = 7; 00132 } else if (key==8+1) { 00133 00134 if ((curr_x_b-6 < curr_x_u+6 && curr_x_u < curr_x_b) && ((curr_y_u+6 > curr_y_b-6 && curr_y_u <= curr_y_b) || (curr_y_u-6 < curr_y_b+6 && curr_y_u >= curr_y_b))) { 00135 curr_x_b+=1; 00136 curr_x_u = curr_x_b-12; 00137 if (curr_x_b > 120) { 00138 curr_x_b = 25; 00139 curr_y_b = 63; 00140 } 00141 } else { 00142 curr_x_u+=1; 00143 } 00144 if (curr_x_u > 120) curr_x_u = 120; 00145 } else if (key==4+1) { 00146 00147 if ((curr_y_b-6 < curr_y_u+6 && curr_y_u < curr_y_b) && ((curr_x_u+6 > curr_x_b-6 && curr_x_u <= curr_x_b) || (curr_x_u-6 < curr_x_b+6 && curr_x_u >= curr_x_b))) { 00148 curr_y_b+=1; 00149 curr_y_u = curr_y_b-12; 00150 if (curr_y_b > 120) { 00151 curr_x_b = 25; 00152 curr_y_b = 63; 00153 } 00154 } else { 00155 curr_y_u+=1; 00156 } 00157 if (curr_y_u > 120) curr_y_u = 120; 00158 } else if (key==5+1) { 00159 00160 if ((curr_y_b+6 > curr_y_u-6 && curr_y_u > curr_y_b) && ((curr_x_u+6 > curr_x_b-6 && curr_x_u <= curr_x_b) || (curr_x_u-6 < curr_x_b+6 && curr_x_u >= curr_x_b))) { 00161 curr_y_b-=1; 00162 curr_y_u = curr_y_b+12; 00163 if (curr_y_b < 7) { 00164 curr_x_b = 25; 00165 curr_y_b = 63; 00166 } 00167 } else { 00168 curr_y_u-=1; 00169 } 00170 if (curr_y_u < 7) curr_y_u = 7; 00171 } 00172 //redraw user and payload 00173 lcd_mutex.lock(); 00174 uLCD.rectangle(20, 58, 30, 68, WHITE); 00175 uLCD.filled_rectangle(old_x_u-5, old_y_u-5, old_x_u+5, old_y_u+5, BLACK); 00176 uLCD.filled_rectangle(curr_x_u-5, curr_y_u-5, curr_x_u+5, curr_y_u+5, GREEN); 00177 uLCD.filled_rectangle(old_x_b-5, old_y_b-5, old_x_b+5, old_y_b+5, BLACK); 00178 uLCD.filled_rectangle(curr_x_b-5, curr_y_b-5, curr_x_b+5, curr_y_b+5, DGREY); 00179 lcd_mutex.unlock(); 00180 } 00181 } 00182 00183 //main thread handles setup of game, angry ball collision logic, gameover, and game resets 00184 int main() { 00185 //setup keypad interrupts 00186 interrupt.fall(&fallInterrupt); 00187 interrupt.mode(PullUp); 00188 uLCD.baudrate(3000000); 00189 //load in Angry Balls image from SD 00190 uLCD.media_init(); 00191 uLCD.set_sector_address(0x003B, 0xD400); 00192 uLCD.display_image(0,0); 00193 //wait 3 seconds to allow keypad time to set up while player can look at the pretty image 00194 wait(3); 00195 uLCD.textbackground_color(WHITE); 00196 uLCD.text_width(1); 00197 uLCD.text_height(1); 00198 uLCD.color(RED); 00199 uLCD.locate(0, 0); 00200 uLCD.printf("Angry Balls!"); 00201 uLCD.locate(0, 1); 00202 uLCD.color(BLACK); 00203 uLCD.printf("Press 3 to play"); 00204 //start tone 00205 amp.PlayNote(700.0,0.2,0.5); 00206 amp.PlayNote(1000.0,0.2,0.0); 00207 amp.PlayNote(600.0,0.1,0.5); 00208 amp.PlayNote(1000.0,0.1,0.0); 00209 amp.PlayNote(700.0,0.5,0.5); 00210 //wait until 3 is pressed 00211 while(key != 3+1); 00212 //wait until 3 is unpressed 00213 while(key == 3+1); 00214 //clear screen 00215 uLCD.cls(); 00216 uLCD.textbackground_color(BLACK); 00217 uLCD.background_color(BLACK); 00218 //setup initial state for every object 00219 curr_x_u = 9; 00220 curr_y_u = 63; 00221 curr_x_b = 25; 00222 curr_y_b = 63; 00223 curr_x_e = 75; 00224 curr_y_e = 75; 00225 dx_e = -0.75; 00226 dy_e = 0.75; 00227 curr_x_p = 110; 00228 curr_y_p = 15; 00229 old_x_p = curr_x_p; 00230 old_y_p = curr_y_p; 00231 //draw everything 00232 uLCD.filled_rectangle(curr_x_u-5, curr_y_u-5, curr_x_u+5, curr_y_u+5, GREEN); 00233 uLCD.filled_rectangle(curr_x_b-5, curr_y_b-5, curr_x_b+5, curr_y_b+5, DGREY); 00234 uLCD.filled_circle(curr_x_e, curr_y_e, 6, RED); 00235 uLCD.rectangle(curr_x_p-5, curr_y_p-5, curr_x_p+5, curr_y_p+5, BLUE); 00236 uLCD.color(WHITE); 00237 uLCD.locate(1,2); 00238 uLCD.printf("Place ball!"); 00239 //logic for placing ball before game starts based on key presses; prevents ball from going through walls & middle boundary 00240 while(key != 3+1) { 00241 old_x_e = curr_x_e; 00242 old_y_e = curr_y_e; 00243 if (key==0+1) { 00244 curr_x_e-=2; 00245 if (curr_x_e < 71) curr_x_e = 71; 00246 } 00247 if (key==8+1) { 00248 curr_x_e+=2; 00249 if (curr_x_e > 120) curr_x_e = 120; 00250 } 00251 if (key==4+1) { 00252 curr_y_e+=2; 00253 if (curr_y_e > 120) curr_y_e = 120; 00254 } 00255 if (key==5+1) { 00256 curr_y_e-=2; 00257 if (curr_y_e < 7) curr_y_e = 7; 00258 } 00259 //draw ball 00260 uLCD.locate(1,2); 00261 uLCD.printf("Place ball!"); 00262 uLCD.rectangle(curr_x_p-5, curr_y_p-5, curr_x_p+5, curr_y_p+5, BLUE); 00263 uLCD.filled_circle(old_x_e, old_y_e, 6, BLACK); 00264 uLCD.filled_circle(curr_x_e, curr_y_e, 6, RED); 00265 } 00266 //wait until 3 is unpressed 00267 while(key==3+1); 00268 uLCD.locate(1,2); 00269 uLCD.color(BLACK); 00270 uLCD.printf("Place ball!"); 00271 fx_e = curr_x_e; 00272 fy_e = curr_y_e; 00273 uLCD.color(WHITE); 00274 //countdown til start 00275 for (int i=3; i>=1; i--) { 00276 uLCD.locate(1, 2); 00277 uLCD.printf("%2D", i); 00278 amp.PlayNote(800.0,0.025,0.5); 00279 wait(1); 00280 } 00281 uLCD.locate(1,2); 00282 uLCD.color(BLACK); 00283 uLCD.printf(" "); 00284 //game is live, start other two threads 00285 s = LIVE; 00286 box.start(box_thread); 00287 portal.start(portal_thread); 00288 //collision logic for angry ball 00289 //check if ball has collided with a wall, the user, or the payload (gameover) 00290 while(s == LIVE || s == PAUSE) { 00291 while (s==PAUSE); 00292 old_x_e = curr_x_e; 00293 old_y_e = curr_y_e; 00294 if (curr_x_e < 7) { 00295 curr_x_e = 7; 00296 dx_e = -dx_e; 00297 } else if (curr_x_e > 120) { 00298 curr_x_e = 120; 00299 dx_e = -dx_e; 00300 } else if (curr_y_e > 120) { 00301 curr_y_e = 120; 00302 dy_e = -dy_e; 00303 } else if (curr_y_e < 7) { 00304 curr_y_e = 7; 00305 dy_e = -dy_e; 00306 } else if (((dx_e < 0 && curr_x_e-6 < curr_x_u+6 && curr_x_e > curr_x_u) || (dx_e > 0 && curr_x_e+6 > curr_x_u-6 && curr_x_e < curr_x_u)) && ((curr_y_e+6 > curr_y_u-6 && curr_y_e < curr_y_u) || (curr_y_e-6 < curr_y_u+6 && curr_y_e > curr_y_u))) { 00307 dx_e = -dx_e; 00308 } else if (((dy_e < 0 && curr_y_e-6 < curr_y_u+6 && curr_y_e > curr_y_u) || (dy_e > 0 && curr_y_e+6 > curr_y_u-6 && curr_y_e < curr_y_u)) && ((curr_x_e+6 > curr_x_u-6 && curr_x_e < curr_x_u) || (curr_x_e-6 < curr_x_u+6 && curr_x_e > curr_x_u))) { 00309 dy_e = -dy_e; 00310 } 00311 if (((dx_e < 0 && curr_x_e-6 < curr_x_b+6 && curr_x_e > curr_x_b) || (dx_e > 0 && curr_x_e+6 > curr_x_b-6 && curr_x_e < curr_x_b)) && ((curr_y_e+6 > curr_y_b-6 && curr_y_e < curr_y_b) || (curr_y_e-6 < curr_y_b+6 && curr_y_e > curr_y_b))) { 00312 s = DEAD; 00313 } else if (((dy_e < 0 && curr_y_e-6 < curr_y_b+6 && curr_y_e > curr_y_b) || (dy_e > 0 && curr_y_e+6 > curr_y_b-6 && curr_y_e < curr_y_b)) && ((curr_x_e+6 > curr_x_b-6 && curr_x_e < curr_x_b) || (curr_x_e-6 < curr_x_b+6 && curr_x_e > curr_x_b))) { 00314 s = DEAD; 00315 } 00316 //update floating point coordinates with velocity values 00317 fx_e += dx_e; 00318 fy_e += dy_e; 00319 //cast floating coordinates to integer coordinates 00320 curr_x_e = (int) fx_e; 00321 curr_y_e = (int) fy_e; 00322 //redraw ball 00323 lcd_mutex.lock(); 00324 uLCD.filled_circle(old_x_e, old_y_e, 6, BLACK); 00325 uLCD.filled_circle(curr_x_e, curr_y_e, 6, RED); 00326 lcd_mutex.unlock(); 00327 //if ball-payload collision has occurred, game is now dead 00328 if (s == DEAD) { 00329 //print gameover, score, instructions to start over, and play gameover sound 00330 lcd_mutex.lock(); 00331 uLCD.cls(); 00332 uLCD.locate(1,2); 00333 uLCD.color(RED); 00334 uLCD.printf("GAMEOVER"); 00335 uLCD.locate(1,4); 00336 uLCD.color(0x4B0082); 00337 uLCD.printf("Score:%d", score); 00338 uLCD.locate(1,8); 00339 uLCD.color(WHITE); 00340 uLCD.printf("Press 3 to retry"); 00341 amp.PlayNote(300.0,0.5,0.5); 00342 amp.PlayNote(300.0,0.05,0.0); 00343 amp.PlayNote(280.0,0.5,0.5); 00344 amp.PlayNote(300.0,0.05,0.0); 00345 amp.PlayNote(260.0,1.0,0.5); 00346 //wait until 3 is pressed 00347 while(key != 3+1); 00348 //wait until 3 is unpressed 00349 while(key == 3+1); 00350 //reinitialize game state for new game; same code as above 00351 uLCD.cls(); 00352 score = 0; 00353 oldscore = 0; 00354 curr_x_u = 9; 00355 curr_y_u = 63; 00356 curr_x_b = 25; 00357 curr_y_b = 63; 00358 curr_x_e = 75; 00359 curr_y_e = 75; 00360 dx_e = -0.75; 00361 dy_e = 0.75; 00362 curr_x_p = 110; 00363 curr_y_p = 15; 00364 old_x_p = curr_x_p; 00365 old_y_p = curr_y_p; 00366 uLCD.filled_rectangle(curr_x_u-5, curr_y_u-5, curr_x_u+5, curr_y_u+5, GREEN); 00367 uLCD.filled_rectangle(curr_x_b-5, curr_y_b-5, curr_x_b+5, curr_y_b+5, DGREY); 00368 uLCD.filled_circle(curr_x_e, curr_y_e, 6, RED); 00369 uLCD.rectangle(curr_x_p-5, curr_y_p-5, curr_x_p+5, curr_y_p+5, BLUE); 00370 uLCD.color(WHITE); 00371 uLCD.locate(1,2); 00372 uLCD.printf("Place ball!"); 00373 while(key != 3+1) { 00374 old_x_e = curr_x_e; 00375 old_y_e = curr_y_e; 00376 if (key==0+1) { 00377 curr_x_e-=2; 00378 if (curr_x_e < 71) curr_x_e = 71; 00379 } 00380 if (key==8+1) { 00381 curr_x_e+=2; 00382 if (curr_x_e > 120) curr_x_e = 120; 00383 } 00384 if (key==4+1) { 00385 curr_y_e+=2; 00386 if (curr_y_e > 120) curr_y_e = 120; 00387 } 00388 if (key==5+1) { 00389 curr_y_e-=2; 00390 if (curr_y_e < 7) curr_y_e = 7; 00391 } 00392 uLCD.locate(1,2); 00393 uLCD.printf("Place ball!"); 00394 uLCD.rectangle(curr_x_p-5, curr_y_p-5, curr_x_p+5, curr_y_p+5, BLUE); 00395 uLCD.filled_circle(old_x_e, old_y_e, 6, BLACK); 00396 uLCD.filled_circle(curr_x_e, curr_y_e, 6, RED); 00397 } 00398 while(key==3+1); 00399 uLCD.locate(1,2); 00400 uLCD.color(BLACK); 00401 uLCD.printf("Place ball!"); 00402 fx_e = curr_x_e; 00403 fy_e = curr_y_e; 00404 uLCD.color(WHITE); 00405 for (int i=3; i>=1; i--) { 00406 uLCD.locate(1, 2); 00407 uLCD.printf("%2D", i); 00408 amp.PlayNote(800.0,0.025,0.5); 00409 wait(1); 00410 } 00411 uLCD.locate(1,2); 00412 uLCD.color(BLACK); 00413 uLCD.printf(" "); 00414 lcd_mutex.unlock(); 00415 //game is live again 00416 //restart the other threads 00417 s = LIVE; 00418 box.start(box_thread); 00419 portal.start(portal_thread); 00420 } 00421 } 00422 }
Generated on Tue Jul 19 2022 10:03:28 by
![doxygen](doxygen.png)