Andrew Reed / Mbed OS CITY1082-i2c_master_wifi_mqtt
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MainTask_SpaceEvader.c Source File

MainTask_SpaceEvader.c

00001 /*********************************************************************
00002 *                SEGGER Microcontroller GmbH                         *
00003 *        Solutions for real time microcontroller applications        *
00004 **********************************************************************
00005 *                                                                    *
00006 *        (c) 1996 - 2018  SEGGER Microcontroller GmbH                *
00007 *                                                                    *
00008 *        Internet: www.segger.com    Support:  support@segger.com    *
00009 *                                                                    *
00010 **********************************************************************
00011 
00012 ** emWin V5.48 - Graphical user interface for embedded applications **
00013 All  Intellectual Property rights  in the Software belongs to  SEGGER.
00014 emWin is protected by  international copyright laws.  Knowledge of the
00015 source code may not be used to write a similar product.  This file may
00016 only be used in accordance with the following terms:
00017 
00018 The software  has been licensed to  Cypress Semiconductor Corporation,
00019 whose registered  office is situated  at 198 Champion Ct. San Jose, CA 
00020 95134 USA  solely for the  purposes of creating  libraries for Cypress
00021 PSoC3 and  PSoC5 processor-based devices,  sublicensed and distributed
00022 under  the  terms  and  conditions  of  the  Cypress  End User License
00023 Agreement.
00024 Full source code is available at: www.segger.com
00025 
00026 We appreciate your understanding and fairness.
00027 ----------------------------------------------------------------------
00028 Licensing information
00029 Licensor:                 SEGGER Microcontroller Systems LLC
00030 Licensed to:              Cypress Semiconductor Corp, 198 Champion Ct., San Jose, CA 95134, USA
00031 Licensed SEGGER software: emWin
00032 License number:           GUI-00319
00033 License model:            Services and License Agreement, signed June 10th, 2009
00034 Licensed platform:        Any Cypress platform (Initial targets are: PSoC3, PSoC5)
00035 ----------------------------------------------------------------------
00036 Support and Update Agreement (SUA)
00037 SUA period:               2009-06-12 - 2022-07-27
00038 Contact to extend SUA:    sales@segger.com
00039 ----------------------------------------------------------------------
00040 File        : MainTask_SpaceEvader.c
00041 Purpose     : Spaceship game, evade the asteroids.
00042 ---------------------------END-OF-HEADER------------------------------
00043 */
00044 
00045 #include "GUI.h"
00046 #include "GUI_Private.h"
00047 #include "WM.h"
00048 
00049 #include "stdlib.h"
00050 
00051 /*********************************************************************
00052 *
00053 *       External dependencies
00054 *
00055 **********************************************************************
00056 */
00057 extern GUI_CONST_STORAGE GUI_BITMAP bmSpaceShipTop_Small;
00058 extern GUI_CONST_STORAGE GUI_BITMAP bmSpaceShipLeft_Small;
00059 extern GUI_CONST_STORAGE GUI_BITMAP bmSpaceShipRight_Small;
00060 extern GUI_CONST_STORAGE GUI_BITMAP bmSpaceShipBottom_Small;
00061 extern GUI_CONST_STORAGE GUI_BITMAP bmSpaceShip;
00062 extern GUI_CONST_STORAGE GUI_BITMAP bmAsteroid;
00063 extern GUI_CONST_STORAGE GUI_BITMAP bmBang;
00064 
00065 /*********************************************************************
00066 *
00067 *       Defines
00068 *
00069 **********************************************************************
00070 */
00071 
00072 #define XSIZE_DISPLAY LCD_GetXSize()
00073 #define YSIZE_DISPLAY LCD_GetYSize()
00074 
00075 #define PERIOD_GAME  20000
00076 #define PERIOD_INTRO  2000
00077 
00078 #define YSIZE_BAR 12
00079 
00080 #define DIR_NONE   0
00081 #define DIR_LEFT   1
00082 #define DIR_RIGHT  2
00083 
00084 #define CONTROL_TYPE_PID 0
00085 #define CONTROL_TYPE_JOY 1
00086 #define CONTROL_TYPE     CONTROL_TYPE_PID
00087 
00088 /*********************************************************************
00089 *
00090 *       Types
00091 *
00092 **********************************************************************
00093 */
00094 typedef struct {
00095   int xPos;
00096   int yPos;
00097   GUI_CONST_STORAGE GUI_BITMAP * pBitmap;
00098 } SHIP;
00099 
00100 typedef struct {
00101   int xPos;
00102   int yPos;
00103 } ASTEROID;
00104 
00105 /*********************************************************************
00106 *
00107 *       Static code
00108 *
00109 **********************************************************************
00110 */
00111 /*********************************************************************
00112 *
00113 *       _GetDirection()
00114 *
00115 *  Function description:
00116 *    This function returns the direction the space ship should fly.
00117 *    It might be necessary to adapt this function depending on the
00118 *    hardware used.
00119 *
00120 *    CONTROL_TYPE_PID:
00121 *      Use the PID input to move the ship left or right. The ship
00122 *      will move to the left if clicked left of the ship and to the
00123 *      right if clicked right of it.
00124 *
00125 *    CONTROL_TYPE_JOY:
00126 *      Use this if the pid buffer gets filled by a joystick.
00127 *      If State.x is bigger than 0 the stick is pushed to the right.
00128 *      If State.x is smaler than 0 the stick is pushed to the left.
00129 *      This was originally for the SEGGER emPower evaluation board.
00130 */
00131 static int _GetDirection(SHIP * pShip) {
00132 #if (CONTROL_TYPE == CONTROL_TYPE_PID)
00133   //
00134   // CONTROL_TYPE_PID
00135   //
00136   GUI_PID_STATE State;
00137   int           Direction;
00138   int           Center;
00139   
00140   GUI_PID_GetState(&State);                              // Get the current PID state
00141   Direction = DIR_NONE;
00142   if (pShip) {                                           // If we have a ship
00143     if (State.Pressed) {                                 // Check if it is pressed
00144       Center = pShip->xPos + pShip->pBitmap->XSize / 2;  // If pressed get the center of the ship
00145       if (State.x > Center) {                            // Pressed right of the ship
00146         Direction = DIR_RIGHT;
00147       } else if (State.x < Center) {                     // Pressed left of the ship
00148         Direction = DIR_LEFT;
00149       }
00150     }
00151   } else {                                               // We have no ship
00152     if (State.Pressed == 1) {                            // Anyway, if pressed return a value
00153       Direction = DIR_LEFT;
00154     }
00155   }
00156   return Direction;
00157 #elif (CONTROL_TYPE == CONTROL_TYPE_JOY)
00158   //
00159   // CONTROL_TYPE_KEY
00160   //
00161   GUI_PID_STATE State;
00162   int           Direction;
00163   
00164   GUI_PID_GetState(&State);    // Get the current PID state
00165   if (pShip) {                 // If we have a ship
00166     if (State.x > 0) {         // Pressed right of the ship
00167       Direction = DIR_RIGHT;
00168     } else if (State.x < 0) {  // Pressed left of the ship
00169       Direction = DIR_LEFT;
00170     } else {
00171       Direction = DIR_NONE;    // No pressed state
00172     }
00173   } else {                     // We have no ship
00174     if (State.x != 0) {        // Anyway, if pressed return a value
00175       Direction = DIR_LEFT;
00176     } else {
00177       Direction = DIR_NONE;
00178     }
00179   }
00180   return Direction;
00181 #endif
00182 }
00183 
00184 /*********************************************************************
00185 *
00186 *       _Game()
00187 */
00188 static void _Game(SHIP * pShip) {
00189   int Direction;
00190   //
00191   // Clear previous shape
00192   //
00193   GUI_ClearRect(pShip->xPos, pShip->yPos, pShip->xPos + pShip->pBitmap->XSize - 1, pShip->yPos + pShip->pBitmap->YSize - 1);
00194   //
00195   // Check which direction
00196   //
00197   Direction = _GetDirection(pShip);
00198   switch (Direction) {
00199   case DIR_RIGHT:
00200     //
00201     // Set the proper bitmap
00202     //
00203     pShip->pBitmap = &bmSpaceShipRight_Small;
00204     //
00205     // Clear a rectangle left of the bitmap
00206     //
00207     GUI_ClearRect(pShip->xPos,     pShip->yPos,
00208                   pShip->xPos + 5, pShip->yPos + bmSpaceShipTop_Small.YSize);
00209     //
00210     // Set new x-position
00211     //
00212     pShip->xPos += (pShip->xPos + 5 < LCD_GetXSize() - bmSpaceShipTop_Small.XSize) ? 5 : 0;
00213     break;
00214   case DIR_LEFT:
00215     //
00216     // Set the proper bitmap
00217     //
00218     pShip->pBitmap = &bmSpaceShipLeft_Small;
00219     //
00220     // Clear a rectangle left of the bitmap
00221     //
00222     GUI_ClearRect(pShip->xPos + bmSpaceShipTop_Small.XSize - 5, pShip->yPos,
00223                   pShip->xPos + bmSpaceShipTop_Small.XSize,     pShip->yPos + bmSpaceShipTop_Small.YSize);
00224     //
00225     // Set new x-position
00226     //
00227     pShip->xPos -= (pShip->xPos - 5 > 0) ? 5 : 0;
00228     break;
00229   default:
00230     //
00231     // No button is pressed, set the default bitmap
00232     //
00233     pShip->pBitmap = &bmSpaceShipTop_Small;
00234     break;
00235   }
00236   //
00237   // Draw bitmap
00238   //
00239   GUI_DrawBitmap(pShip->pBitmap, pShip->xPos, pShip->yPos);
00240 }
00241 
00242 /*********************************************************************
00243 *
00244 *       _Asteroid()
00245 */
00246 static void _Asteroid(ASTEROID * pAsteroid) {
00247   //
00248   // Clear a rectangle above the bitmap
00249   //
00250   GUI_ClearRect(pAsteroid->xPos,                    pAsteroid->yPos,
00251                 pAsteroid->xPos + bmAsteroid.XSize, pAsteroid->yPos + 10);
00252   //
00253   // Set a new y-position
00254   //
00255   pAsteroid->yPos += 5;
00256   //
00257   // Draw the bitmap
00258   //
00259   GUI_DrawBitmap(&bmAsteroid, pAsteroid->xPos, pAsteroid->yPos);
00260   //
00261   // If the bitmap is no longer visible, set a new x- and y-position
00262   //
00263   if (pAsteroid->yPos >= LCD_GetYSize()) {
00264     pAsteroid->xPos = rand() % (XSIZE_DISPLAY - bmAsteroid.XSize);
00265     pAsteroid->yPos = -((int)bmAsteroid.YSize);
00266   }
00267 }
00268 
00269 /*********************************************************************
00270 *
00271 *       _CheckCollision()
00272 */
00273 static int _CheckCollision(ASTEROID * pAsteroid, ASTEROID * pAsteroid2, SHIP * pShip) {
00274   GUI_RECT RectShip, RectAsteroid;
00275   int xPos, yPos;
00276   int i, r;
00277   LCD_PIXELINDEX Index;
00278 
00279   r = 0;
00280   RectShip.x0 = pShip->xPos;
00281   RectShip.y0 = pShip->yPos;
00282   RectShip.x1 = RectShip.x0 + pShip->pBitmap->XSize - 1;
00283   RectShip.y1 = RectShip.y0 + pShip->pBitmap->YSize - 1;
00284   RectAsteroid.x0 = pAsteroid->xPos;
00285   RectAsteroid.y0 = pAsteroid->yPos;
00286   RectAsteroid.x1 = RectAsteroid.x0 + bmAsteroid.XSize - 1;
00287   RectAsteroid.y1 = RectAsteroid.y0 + bmAsteroid.YSize - 1;
00288   //
00289   // First a simple check if rectangles of bitmaps overlap
00290   //
00291   if (GUI_RectsIntersect(&RectShip, &RectAsteroid)) {
00292     //
00293     // Check if lower row of asteroid collides with plane
00294     //
00295     yPos = RectAsteroid.y0 - RectShip.y0 + bmAsteroid.YSize - 1;
00296     if (yPos < pShip->pBitmap->XSize) {
00297       for (i = 0; i < bmAsteroid.XSize; i++) {
00298         xPos = RectAsteroid.x0 - RectShip.x0 + i;
00299         if ((xPos >= 0) && (xPos < pShip->pBitmap->XSize)) {
00300           Index = GUI_GetBitmapPixelIndex(pShip->pBitmap, xPos, yPos);
00301           if ((Index > 0) && (Index < 255))  {
00302             GUI_Clear();
00303             GUI_DrawBitmap(&bmBang, 0, 20);
00304             LCD_ControlCache(LCD_CC_UNLOCK);
00305             LCD_ControlCache(LCD_CC_LOCK);
00306             GUI_Delay(1000);
00307             GUI_Clear();
00308             pAsteroid->yPos = pAsteroid2->yPos - YSIZE_DISPLAY / 2;
00309             r = 1;
00310             break;
00311           }
00312         }
00313       }
00314     }
00315   }
00316   return r;
00317 }
00318 
00319 /*********************************************************************
00320 *
00321 *       _ShowTitle
00322 */
00323 static void _ShowTitle(void) {
00324   GUI_Clear();
00325   GUI_DispStringHCenterAt("emWin Space Evader", XSIZE_DISPLAY / 2, 2);
00326   GUI_DrawHLine(YSIZE_BAR - 1, 0, XSIZE_DISPLAY - 1);
00327 }
00328 
00329 /*********************************************************************
00330 *
00331 *       _Intro()
00332 */
00333 static void _Intro(void) {
00334   int t0, tEnd, tNow, tUsed;
00335   int yPos;
00336 
00337   _ShowTitle();
00338   t0 = GUI_GetTime();
00339   tEnd = t0 + PERIOD_INTRO;
00340   do {
00341     tNow = GUI_GetTime();
00342     tUsed = tNow - t0;
00343     tUsed = (tUsed > PERIOD_INTRO) ? PERIOD_INTRO : tUsed;
00344     yPos = YSIZE_DISPLAY - (tUsed * (YSIZE_DISPLAY - YSIZE_BAR)) / PERIOD_INTRO;
00345     GUI_DrawBitmap(&bmSpaceShip, (XSIZE_DISPLAY - bmSpaceShip.XSize) / 2, yPos);
00346   } while (tNow < tEnd);
00347   GUI_Delay(1000);
00348   GUI_Clear();
00349 }
00350 
00351 /*********************************************************************
00352 *
00353 *       _Explain()
00354 */
00355 static void _Explain(void) {
00356   int yPos, ySizeFont;
00357   unsigned i;
00358   const char * apText[] = {
00359     "Use buttons PB0",
00360     "and PB1 for moving",
00361     "the starship.",
00362     "",
00363     "Remaining time is",
00364     "shown in the the",
00365     "lower right edge",
00366     "of the display.",
00367   };
00368   int Direction;
00369 
00370   _ShowTitle();
00371   ySizeFont = GUI_GetFontSizeY() + 2;
00372   yPos = (YSIZE_DISPLAY - ySizeFont * GUI_COUNTOF(apText)) / 2;
00373   for (i = 0; i < GUI_COUNTOF(apText); i++) {
00374     GUI_DispStringHCenterAt(apText[i], XSIZE_DISPLAY / 2, yPos);
00375     yPos += ySizeFont;
00376   }
00377   GUI_DispStringHCenterAt("PRESS BUTTON TO START", XSIZE_DISPLAY / 2, YSIZE_DISPLAY - 10);
00378   do {
00379     Direction = _GetDirection(NULL);
00380     if (Direction) {
00381       break;
00382     }
00383     GUI_X_Delay(10);
00384   } while (1);
00385   GUI_Clear();
00386   GUI_DispStringHCenterAt("Good luck...", XSIZE_DISPLAY / 2, YSIZE_DISPLAY / 2 - 4);
00387   GUI_Delay(1000);
00388   GUI_Clear();
00389 }
00390 
00391 /*********************************************************************
00392 *
00393 *       _ShowResult
00394 */
00395 static void _ShowResult(unsigned Cnt) {
00396   _ShowTitle();
00397   if (Cnt) {
00398     GUI_DispStringHCenterAt("Ships lost in space:\n\n", XSIZE_DISPLAY / 2, YSIZE_DISPLAY / 2 - 10);
00399     GUI_GotoXY(XSIZE_DISPLAY / 2 - 4, YSIZE_DISPLAY / 2);
00400     GUI_DispDecMin(Cnt);
00401   } else {
00402     GUI_DispStringHCenterAt("CONGRATULATIONS\n\nNo ship lost", XSIZE_DISPLAY / 2, YSIZE_DISPLAY / 2 - 10);
00403   }
00404   GUI_Delay(2000);
00405 }
00406 
00407 /*********************************************************************
00408 *
00409 *       Public code
00410 *
00411 **********************************************************************
00412 */
00413 /*********************************************************************
00414 *
00415 *       MainTask()
00416 */
00417 void MainTask(void) {
00418   SHIP Ship;
00419   ASTEROID aAsteroid[2];
00420   unsigned i, Cnt;
00421   GUI_TIMER_TIME t0, tEnd, tNow;
00422 
00423   //
00424   // Initialize GUI
00425   //
00426   GUI_Init();
00427   //
00428   // Set foreground color to black
00429   //
00430   GUI_SetColor(GUI_BLACK);
00431   GUI_SetBkColor(GUI_WHITE);
00432   //
00433   // Explanation
00434   //
00435   _Explain();
00436   //
00437   // Run forever...
00438   //
00439   while (1) {
00440     //
00441     // Initialize some structures
00442     //
00443     Ship.xPos = (XSIZE_DISPLAY - bmSpaceShipTop_Small.XSize) / 2;
00444     Ship.yPos = YSIZE_DISPLAY - bmSpaceShipTop_Small.YSize - 5;
00445     Ship.pBitmap = &bmSpaceShipTop_Small;
00446     for (i = 0; i < GUI_COUNTOF(aAsteroid); i++) {
00447       aAsteroid[i].xPos = rand() % (XSIZE_DISPLAY - bmAsteroid.XSize);
00448       aAsteroid[i].yPos = -((int)bmAsteroid.YSize) - i * 64;
00449     }
00450     //
00451     // Intro
00452     //
00453     _Intro();
00454     //
00455     // The game
00456     //
00457     t0 = GUI_GetTime();
00458     tEnd = t0 + PERIOD_GAME;
00459     Cnt = 0;
00460     do {
00461       //
00462       // Lock cache, output is written to cache only
00463       //
00464       LCD_ControlCache(LCD_CC_LOCK);
00465       //
00466       // Handle drawing of the ship
00467       //
00468       _Game(&Ship);
00469       //
00470       // Handle drawing of the asteroid
00471       //
00472       for (i = 0; i < GUI_COUNTOF(aAsteroid); i++) {
00473         _Asteroid(&aAsteroid[i]);
00474         //
00475         // Check collision
00476         //
00477         if (_CheckCollision(&aAsteroid[i], &aAsteroid[1 - i], &Ship)) {
00478           Cnt++;
00479         }
00480       }
00481       tNow = GUI_GetTime();
00482       //
00483       // Show remaining time
00484       //
00485       GUI_GotoXY(XSIZE_DISPLAY - 12 - 1, YSIZE_DISPLAY - 8 - 1);
00486       GUI_DispDecSpace((tEnd - tNow + 1000) / 1000, 2);
00487       //
00488       // Show content of cache
00489       //
00490       LCD_ControlCache(LCD_CC_UNLOCK);
00491       //
00492       // Wait a while...
00493       //
00494       GUI_Delay(50);
00495     } while (GUI_GetTime() < tEnd);
00496     //
00497     // Show result
00498     //
00499     _ShowResult(Cnt);
00500   }
00501 }
00502 
00503 /****** End of File *************************************************/