4180 Final Project
Dependencies: mbed uLCD_4D_Picaso mbed-rtos PinDetect
main.cpp
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 #include "SongPlayer.h" 00004 #include "Picaso_enums.h" 00005 #include "uLCD_4D_Picaso.h" 00006 00007 00008 00009 //////////////////////////////////////////////////////////////////////////////// 00010 // Variables 00011 //////////////////////////////////////////////////////////////////////////////// 00012 00013 // Hardware variables 00014 //---------------------------------------------------------------------- 00015 uLCD_4D_Picaso uLCD(p9, p10, p7); // serial tx, serial rx, reset pin; 00016 Mutex lcdMtx; // Mutex for the uLCD 00017 SongPlayer mySpeaker(p21); 00018 DigitalOut led(LED4); 00019 Ticker motion, scoreTicker; 00020 00021 // Screen and map dimensions 00022 //---------------------------------------------------------------------- 00023 // Dimensions 00024 const int sHeight = 240; 00025 const int sWidth = 320; 00026 const int marginH = 40; 00027 const int marginW = 40; 00028 const float mapHeight = 5.0; 00029 const float mapWidth = mapHeight*float(sWidth-marginW)/float(sHeight-2*marginH); 00030 // Sand 00031 volatile unsigned int sandY[80]= {203,205,205,203,205,203,205,203,203,205,203,205 00032 ,205,203,205,203,205,203,203,205,203,205,205,203, 00033 205,203,205,203,203,205,203,205,205,203,205,203, 00034 205,203,203,205,203,205,205,203,205,203,205,203, 00035 203,205,203,205,205,203,205,203,205,203,203,205, 00036 203,205,205,203,205,203,205,203,203,205,203,205, 00037 205,203,205,203,203,205,203,205}; 00038 volatile unsigned int sandX[80]= {1,2,3,4,5,16,17,18,19,20,46,47,48,49,50,61,62, 00039 63,64,65,76,92,93,94,95,106,107,108,109,110,111, 00040 127,128,129,130,141,142,143,144,145,156,173,174, 00041 175,186,187,188,189,190,201,202,218,219,220,231, 00042 232,233,234,235,246,247,263,264,265,276,277,278, 00043 279,280,291,292,293,308,309,310,311,312,313,314,315}; 00044 00045 00046 // Game variables 00047 //---------------------------------------------------------------------- 00048 // Trex 00049 volatile float zTrex; 00050 volatile float old_zTrex; 00051 float vzTrex; 00052 float massTrex = 1.5; 00053 float rTrex = 0.5; 00054 float maxHeightTrex = mapHeight-2.5*rTrex; 00055 // Obstacle 00056 volatile float xObstacle; 00057 volatile float old_xObstacle; 00058 float vxObstacle; 00059 // Motion 00060 float gravity = 20.0; 00061 float dt_move = 0.01; // in seconds 00062 float dt_disp = 0.1; // in seconds 00063 volatile bool collision; 00064 // Score 00065 volatile int score; 00066 // Sounds 00067 float trexJump[2] = {515.0, 0.0}; 00068 float trexJump_duration[2] = {0.07, 0.0}; 00069 float trexLvlPass[3] = {515.0, 780, 0.0}; 00070 float trexLvlPass_duration[3] = {0.075, 0.175, 0.0}; 00071 float trexGameOver[4] = {63.0, 0.0, 63.0, 0.0}; 00072 float trexGameOver_duration[4] = {0.07, 0.01, 0.07, 0.0}; 00073 // Cloud 00074 volatile float xCloud; 00075 volatile float old_xCloud; 00076 volatile float zCloud = 4.0; 00077 // Restart 00078 volatile bool restart = true; 00079 00080 00081 //////////////////////////////////////////////////////////////////////////////// 00082 // GRAPHICS FOR THE T-REX AND THE CACTUS 00083 //////////////////////////////////////////////////////////////////////////////// 00084 00085 //--------------------------------------------------------------------------------------------------------------- 00086 enum Status { COLLISION = 0, JUMP = 1, RUNNING_FRONT = 2, RUNNING_BACK = 3 }; 00087 00088 // T-rex body offsets 00089 uint16_t dino_x_base_offset[28] = {0, 0, 10, 22, 22, 26, 28, 28, 30, 00090 30, 32, 32, 28, 28, 36, 36, 30, 30, 40, 40, 38, 38, 22, 20, 20, 10, 6, 2}; 00091 uint16_t dino_y_base_offset[28] = {14, 24, 32, 32, 30, 26, 26, 20, 00092 20, 22, 22, 18, 18, 14, 14, 12, 12, 10, 10, 2, 2, 0, 0, 2, 14, 22, 22, 14}; 00093 // T-rex eyes offsets 00094 uint16_t dino_x_eye_1_offset[4] = {24, 24, 26, 26}; 00095 uint16_t dino_y_eye_1_offset[4] = {4, 6, 6, 4}; 00096 uint16_t dino_x_eye_2_offset[4] = {23, 23, 27, 27}; 00097 uint16_t dino_y_eye_2_offset[4] = {3, 7, 7, 3}; 00098 00099 // Running animation coordinates offset 00100 uint16_t dino_x_leg_offset[15] = {10, 10, 14, 14, 12, 12, 16, 18, 20, 20, 24, 24, 22, 22, 10}; 00101 uint16_t dino_y_leg_offset[15] = {32, 40, 40, 38, 38, 36, 32, 32, 34, 40, 40, 38, 38, 30, 32}; 00102 00103 uint16_t dino_x_leg_front_offset[14] = {10, 10, 14, 14, 12, 12, 16, 18, 20, 20, 26, 26, 22, 22}; 00104 uint16_t dino_y_leg_front_offset[14] = {32, 40, 40, 38, 38, 36, 32, 32, 34, 36, 36, 34, 34, 32}; 00105 00106 uint16_t dino_x_leg_back_offset[15] = {10, 10, 12, 12, 16, 16, 14, 14, 18, 20, 20, 24, 24, 22, 22}; 00107 uint16_t dino_y_leg_back_offset[15] = {32, 34, 34, 36, 36, 34, 34, 32, 32, 34, 40, 40, 38, 38, 30}; 00108 00109 // Cactus offsets 00110 uint16_t cactus_x_offset[28] = {0, 0, 10, 10, 18, 18, 28, 28, 26, 26, 24, 24, 22, 22, 00111 18, 18, 16, 16, 12, 12, 10, 10, 6, 6, 4, 4, 2, 2}; 00112 uint16_t cactus_y_offset[28] = {10, 30, 30 ,40, 40, 30, 30, 10, 10, 8, 8, 10, 10, 24, 00113 24, 2, 2, 0, 0, 2, 2, 24, 24, 10, 10, 8, 8, 10}; 00114 //--------------------------------------------------------------------------------------------------------------- 00115 00116 // status can be 0 (jumps or collisions), 1 (running animation 1), or 2 (running animation 2) 00117 void drawDino(uint16_t x, uint16_t y, Picaso::Color Color, Status status) 00118 { 00119 uint16_t dino_x[28]; 00120 uint16_t dino_y[28]; 00121 uint16_t eye_1_x[4]; 00122 uint16_t eye_1_y[4]; 00123 uint16_t eye_2_x[4]; 00124 uint16_t eye_2_y[4]; 00125 00126 // draw the base t-rex sprite 00127 for (int i = 0; i < 28; i++) 00128 { 00129 dino_x[i] = x + dino_x_base_offset[i]; 00130 dino_y[i] = y + dino_y_base_offset[i]; 00131 if (i < 4) 00132 { 00133 eye_1_x[i] = x + dino_x_eye_1_offset[i]; 00134 eye_1_y[i] = y + dino_y_eye_1_offset[i]; 00135 eye_2_x[i] = x + dino_x_eye_2_offset[i]; 00136 eye_2_y[i] = y + dino_y_eye_2_offset[i]; 00137 } 00138 } 00139 00140 uLCD.gfx_PolygonFilled(28, dino_x, dino_y, Color); 00141 00142 if (status == COLLISION) 00143 { 00144 uLCD.gfx_PolygonFilled(4, eye_2_x, eye_2_y, Picaso::WHITE); 00145 uLCD.gfx_PolygonFilled(4, eye_1_x, eye_1_y, Picaso::BLACK); 00146 } 00147 else 00148 { 00149 uLCD.gfx_PolygonFilled(4, eye_1_x, eye_1_y, Picaso::WHITE); 00150 } 00151 // if t-rex is jumping 00152 if (status == JUMP || status == COLLISION) 00153 { 00154 uint16_t dino_leg_base_x[14]; 00155 uint16_t dino_leg_base_y[14]; 00156 00157 for (int i = 0; i < 14; i++) 00158 { 00159 dino_leg_base_x[i] = x + dino_x_leg_offset[i]; 00160 dino_leg_base_y[i] = y + dino_y_leg_offset[i]; 00161 } 00162 00163 uLCD.gfx_PolygonFilled(14, dino_leg_base_x, dino_leg_base_y, Color); 00164 } 00165 // if t-rex is in running animation 1 00166 else if (status == RUNNING_FRONT) 00167 { 00168 uint16_t dino_leg_front_x[14]; 00169 uint16_t dino_leg_front_y[14]; 00170 00171 for (int i = 0; i < 14; i++) 00172 { 00173 dino_leg_front_x[i] = x + dino_x_leg_front_offset[i]; 00174 dino_leg_front_y[i] = y + dino_y_leg_front_offset[i]; 00175 } 00176 00177 uLCD.gfx_PolygonFilled(14, dino_leg_front_x, dino_leg_front_y, Color); 00178 } 00179 // if t-rex is in running animation 2 00180 else if (status == RUNNING_BACK) 00181 { 00182 uint16_t dino_leg_back_x[15]; 00183 uint16_t dino_leg_back_y[15]; 00184 00185 for (int i = 0; i < 15; i++) 00186 { 00187 dino_leg_back_x[i] = x + dino_x_leg_back_offset[i]; 00188 dino_leg_back_y[i] = y + dino_y_leg_back_offset[i]; 00189 } 00190 00191 uLCD.gfx_PolygonFilled(15, dino_leg_back_x, dino_leg_back_y, Color); 00192 } 00193 } 00194 00195 void drawCactus(uint16_t x, uint16_t y, Picaso::Color color) 00196 { 00197 uint16_t cactus_x[28]; 00198 uint16_t cactus_y[28]; 00199 00200 for (int i = 0; i < 28; i++) 00201 { 00202 cactus_x[i] = x + cactus_x_offset[i]; 00203 cactus_y[i] = y + cactus_y_offset[i]; 00204 } 00205 00206 uLCD.gfx_PolygonFilled(28, cactus_x, cactus_y, color); 00207 } 00208 00209 //////////////////////////////////////////////////////////////////////////////// 00210 // Functions 00211 //////////////////////////////////////////////////////////////////////////////// 00212 00213 // These functions convert physical distances to pixel 00214 //---------------------------------------------------------------------- 00215 int toPixz(float z) 00216 { 00217 return sHeight - int(float(marginH) + z*float(sHeight - 2*marginH)/float(mapHeight)); 00218 } 00219 int toPixx(float x) 00220 { 00221 return marginW + int(x*float(sWidth - marginW)/float(mapWidth)); 00222 } 00223 int toPix(float r) 00224 { 00225 return int(r*float(sHeight-2*marginH)/mapHeight); 00226 } 00227 00228 // This function initializes all the variables when game starts 00229 //---------------------------------------------------------------------- 00230 void init() 00231 { 00232 // Trex 00233 zTrex = 0; 00234 old_zTrex = -1.5; 00235 vzTrex = 0; 00236 // Obstacle 00237 xObstacle = mapWidth; 00238 old_xObstacle = xObstacle+1; 00239 vxObstacle = 5; 00240 // Motion 00241 collision = false; 00242 // Score 00243 score = 0; 00244 // Cloud 00245 xCloud = 7.5; 00246 old_xCloud = 7.0; 00247 // Restart 00248 restart = false; 00249 00250 // Screen 00251 //--------------------------- 00252 lcdMtx.lock(); 00253 uLCD.setbaudWait(Picaso::BAUD_600000); 00254 uLCD.gfx_ScreenMode(Picaso::LANDSCAPE); 00255 uLCD.touch_Set(0); 00256 uLCD.txt_BGcolour(Picaso::WHITE); 00257 uLCD.txt_FGcolour(Picaso::BLACK); 00258 uLCD.gfx_RectangleFilled(0, 0, sWidth, sHeight, Picaso::WHITE); 00259 uLCD.gfx_Line(0, toPixz(0)+1, sWidth, toPixz(0)+1, Picaso::BLACK); 00260 uLCD.gfx_Line(0, toPixz(mapHeight)-1, sWidth, toPixz(mapHeight)-1, Picaso::BLACK); 00261 lcdMtx.unlock(); 00262 } 00263 00264 // This function displays the score 00265 //---------------------------------------------------------------------- 00266 void updateScore() 00267 { 00268 score++; 00269 if (score%10 == 0) 00270 { 00271 vxObstacle += 0.5; 00272 mySpeaker.PlaySong(trexLvlPass, trexLvlPass_duration); 00273 } 00274 } 00275 00276 // This function updates the location of Trex and Obstacle every dt_move 00277 //----------------------------------------------------------------------- 00278 void updateLocations() 00279 { 00280 // Trex 00281 zTrex += vzTrex*dt_move - 0.5*gravity*dt_move*dt_move ; 00282 vzTrex += -gravity*dt_move; 00283 if (zTrex<0) 00284 { 00285 zTrex = 0; 00286 vzTrex = 0; 00287 } 00288 if (zTrex>maxHeightTrex) zTrex = maxHeightTrex; 00289 00290 // Obstacle 00291 xObstacle -= vxObstacle*dt_move; 00292 if (xObstacle < -2) xObstacle = mapWidth; 00293 00294 // Check collision 00295 if (((zTrex)*(zTrex) + (xObstacle)*(xObstacle)) < 1) collision = true; 00296 00297 // Clouds 00298 xCloud -= 0.2*vxObstacle*dt_move; 00299 if (xCloud < 2.5) xCloud = 7.5; 00300 } 00301 00302 // This function is called when jump button is hit 00303 //---------------------------------------------------------------------- 00304 void jump() 00305 { 00306 while(1) 00307 { 00308 lcdMtx.lock(); 00309 if (uLCD.touch_Get(0) & vzTrex>=0 & zTrex != maxHeightTrex) 00310 { 00311 vzTrex = 8.0; 00312 mySpeaker.PlaySong(trexJump, trexJump_duration); 00313 } 00314 lcdMtx.unlock(); 00315 } 00316 } 00317 00318 // This function displays the Trex 00319 //---------------------------------------------------------------------- 00320 void displayTrex() 00321 { 00322 float tmp; 00323 Status status = RUNNING_BACK; 00324 int countStatus = 0; 00325 while(1) 00326 { 00327 countStatus = (++countStatus)%2; 00328 tmp = old_zTrex; 00329 old_zTrex = zTrex; 00330 if (collision) status = COLLISION; 00331 else 00332 { 00333 if (old_zTrex > 0) status = JUMP; 00334 else if (countStatus == 0) status = RUNNING_BACK; 00335 else status = RUNNING_FRONT; 00336 } 00337 00338 // Mask the Trex at old position 00339 lcdMtx.lock(); 00340 uLCD.gfx_RectangleFilled(marginW, toPixz(tmp) - marginH, 2*marginW, toPixz(0), Picaso::WHITE); 00341 // lcdMtx.unlock(); 00342 00343 // Draw the Trex at new position 00344 // lcdMtx.lock(); 00345 drawDino(marginW, toPixz(old_zTrex) - marginH, Picaso::BLACK, status); 00346 lcdMtx.unlock(); 00347 00348 // Wait a little 00349 Thread::wait(dt_disp*1000); 00350 } 00351 } 00352 00353 // This function displays the Obstacle 00354 //---------------------------------------------------------------------- 00355 void displayObstacle() 00356 { 00357 float tmp; 00358 while(1) 00359 { 00360 tmp = old_xObstacle; 00361 old_xObstacle = xObstacle; 00362 00363 // Mask the Obstacle at old position 00364 lcdMtx.lock(); 00365 drawCactus(toPixx(tmp), sHeight-2*marginH, Picaso::WHITE); 00366 //lcdMtx.unlock(); 00367 00368 // Draw the Obstacle at new position 00369 //lcdMtx.lock(); 00370 drawCactus(toPixx(old_xObstacle), sHeight-2*marginH, Picaso::BLACK); 00371 lcdMtx.unlock(); 00372 00373 // Wait a little 00374 Thread::wait(dt_disp*1000); 00375 } 00376 } 00377 00378 // This function displays the sand 00379 //---------------------------------------------------------------------- 00380 void displayGround() 00381 { 00382 while(1) 00383 { 00384 // Delete the sand 00385 lcdMtx.lock(); 00386 uLCD.gfx_RectangleFilled(0, 202, sWidth, 210, Picaso::WHITE); 00387 lcdMtx.unlock(); 00388 00389 // Update positions 00390 int dx = toPix(vxObstacle*dt_disp); 00391 for (int i = 0; i < 80; ++i) 00392 { 00393 sandX[i] = (sandX[i] - dx)%320 + 1; 00394 lcdMtx.lock(); 00395 uLCD.gfx_PutPixel(sandX[i], sandY[i], Picaso::BLACK); 00396 lcdMtx.unlock(); 00397 } 00398 00399 // Wait a little 00400 Thread::wait(dt_disp*1000); 00401 } 00402 } 00403 00404 // This function displays the clouds 00405 //---------------------------------------------------------------------- 00406 void displayCloud() 00407 { 00408 float tmp; 00409 while(1) 00410 { 00411 tmp = old_xCloud; 00412 old_xCloud = xCloud; 00413 // Mask previous clouds 00414 lcdMtx.lock(); 00415 uLCD.gfx_CircleFilled(toPixx(tmp), toPixz(zCloud), 10, Picaso::WHITE); 00416 uLCD.gfx_CircleFilled(toPixx(tmp+0.5), toPixz(zCloud+0.3), 15, Picaso::WHITE); 00417 //lcdMtx.unlock(); 00418 00419 // Draw current clouds 00420 //lcdMtx.lock(); 00421 uLCD.gfx_CircleFilled(toPixx(old_xCloud), toPixz(zCloud), 10, Picaso::LIGHTGREY); 00422 uLCD.gfx_CircleFilled(toPixx(old_xCloud+0.5), toPixz(zCloud+0.3), 15, Picaso::LIGHTGREY); 00423 lcdMtx.unlock(); 00424 00425 // Wait a little 00426 Thread::wait(dt_disp*1000); 00427 } 00428 } 00429 00430 // This function displays score 00431 //---------------------------------------------------------------------- 00432 void displayScore() 00433 { 00434 char str[50]; 00435 while(1) 00436 { 00437 sprintf(str, "\n\n Score: %d\0", score); 00438 lcdMtx.lock(); 00439 uLCD.txt_MoveCursor(0, 0); 00440 uLCD.putStr(str); 00441 lcdMtx.unlock(); 00442 Thread::wait(1000); 00443 } 00444 } 00445 00446 // This function tells the player that he lost 00447 //---------------------------------------------------------------------- 00448 void gameOver() 00449 { 00450 mySpeaker.PlaySong(trexGameOver, trexGameOver_duration); 00451 lcdMtx.lock(); 00452 uLCD.gfx_Cls(); 00453 uLCD.gfx_RectangleFilled(0, 0, sWidth, sHeight, Picaso::BLACK); 00454 uLCD.txt_BGcolour(Picaso::BLACK); 00455 uLCD.txt_FGcolour(Picaso::WHITE); 00456 uLCD.putStr("\n\n\0"); 00457 uLCD.txt_Height(3.25); 00458 uLCD.txt_Width(3.25); 00459 uLCD.putStr("\n\n GAME OVER\0"); 00460 uLCD.txt_Height(1); 00461 uLCD.txt_Width(1); 00462 uLCD.putStr("\n\n\n Touch the screen to restart ! \0"); 00463 lcdMtx.unlock(); 00464 while (1) 00465 { 00466 if (uLCD.touch_Get(0)) 00467 { 00468 restart = true; 00469 break; 00470 } 00471 } 00472 } 00473 00474 //////////////////////////////////////////////////////////////////////////////// 00475 // MAIN FUNCTION 00476 //////////////////////////////////////////////////////////////////////////////// 00477 00478 int main() { 00479 00480 while(restart) 00481 { 00482 // Initializations 00483 //----------------------------------------- 00484 init(); 00485 //----------------------------------------- 00486 00487 // Laucnch thread and tickers 00488 //----------------------------------------- 00489 motion.attach(&updateLocations, dt_move); 00490 scoreTicker.attach(&updateScore, 1); 00491 Thread Jump(jump); 00492 Thread Trex(displayTrex); 00493 Thread Obstacle(displayObstacle); 00494 Thread Sand(displayGround); 00495 Thread Cloud(displayCloud); 00496 Thread Score(displayScore); 00497 00498 // Main loop 00499 //----------------------------------------- 00500 while(!collision) {} 00501 00502 // Terminate threads and detach tickers 00503 //----------------------------------------- 00504 motion.detach(); 00505 scoreTicker.detach(); 00506 Jump.terminate(); 00507 wait(0.5); // Wait for the right positions to appear on screen 00508 Trex.terminate(); 00509 Obstacle.terminate(); 00510 Sand.terminate(); 00511 Cloud.terminate(); 00512 Score.terminate(); 00513 wait(0.5); // Wait for the uLCD to be free ? 00514 00515 // Game Over 00516 //----------------------------------------- 00517 gameOver(); 00518 } 00519 } 00520
Generated on Fri Jul 15 2022 13:25:46 by 1.7.2