4180 Final Project

Dependencies:   mbed uLCD_4D_Picaso mbed-rtos PinDetect

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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