Subversion Repositories Kolibri OS

Rev

Rev 9011 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <kosSyst.h>
  2. #include <kosFile.h>
  3. #include "images.hpp"
  4.  
  5. //Global const strings
  6. const char HEADER_STRING[] = "Flappy bird";
  7. const char CONTROL_STRING[] = "SPACEBAR TO JUMP";
  8. const char GAMEOVER_STRING[] = "GAMEOVER";
  9. const char ANY_KEY_STRING[] = "Press any key for restart";
  10. const char SELECT_SPEED_STRING[] = "select the speed of the game";
  11. const char FAST_STRING[] = "1 FAST";
  12. const char SLOW_STRING[] = "2 SLOW";
  13.  
  14. //Global const variables
  15. const int WINDOW_WIDTH = 400;
  16. const int WINDOW_HEIGHT = 400;
  17. const int BORDER_TOP = 24;
  18. const int BORDER_LEFT = 5;
  19. const int BORDER_RIGHT = 5;
  20. const int BORDER_DOWN = 5;
  21.  
  22. enum GameState
  23. {
  24.         GAMESTATE_MENU,
  25.         GAMESTATE_STARTED,
  26.         GAMESTATE_GAMEOVER
  27. };
  28.  
  29. struct ScreenSize
  30. {
  31.         int width;
  32.         int height;
  33. };
  34.  
  35. class Bird
  36. {
  37. public:
  38.         static const int sizeX = 19;
  39.         static const int sizeY = 20;
  40.         static const int x = 100;
  41.         int prev_y;
  42.         int y;
  43.         int acceleration;
  44.  
  45.         inline void initialize()
  46.         {
  47.                 y = WINDOW_HEIGHT / 2;
  48.                 acceleration = 0;
  49.         }
  50.  
  51.         inline void move()
  52.         {
  53.                 if (acceleration <= 30)
  54.                         acceleration += 2;
  55.                 prev_y = y;
  56.                 y += acceleration / 10;
  57.         }
  58.  
  59.         inline void jump()
  60.         {
  61.                 acceleration = -50;
  62.         }
  63.  
  64.         inline void draw()
  65.         {
  66.                 kos_PutImage(birdImage, sizeX, sizeY, x, y);
  67.         }
  68. };
  69.  
  70. class Tube
  71. {
  72. public:
  73.         static const int width = 50;
  74.         static const int gapHeight = 100;
  75.         static const int headHeight = 18;
  76.         int x;
  77.         int gapY;
  78.  
  79.         inline void randomize()
  80.         {
  81.                 x = WINDOW_WIDTH + 1;
  82.                 gapY = rtlRand() % 200 + 50;
  83.         }
  84.  
  85.         inline void move()
  86.         {
  87.                 x -= 2;
  88.                 if (x < -width - 2)
  89.                         randomize();
  90.         }
  91.  
  92.         void draw()
  93.         {
  94.                 //cleanup
  95.                 int pixels = (WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1)) - (x + width + 2);
  96.                 if (pixels >= -1)
  97.                 {
  98.                         pixels = (pixels == -1) ? 1 : 2;
  99.                         kos_DrawBar(x + width, gapY - headHeight, pixels, headHeight, 0x00FFFF);
  100.                         kos_DrawBar(x + width, gapY + gapHeight, pixels, headHeight, 0x00FFFF);
  101.                 }
  102.  
  103.                 int offset = x >= 0 ? 0 : -x;
  104.                 int trim = x + width >= WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1) ? WINDOW_WIDTH - x - width - (BORDER_LEFT + BORDER_RIGHT - 1) : 0;
  105.                 int trimHead = x + width >= WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1) ? WINDOW_WIDTH - x - width - (BORDER_LEFT + BORDER_RIGHT - 1) : 0;
  106.  
  107.                 //top
  108.                 for (int y = 0; y < gapY - headHeight; ++y)
  109.                         kos_PutImage(tubeBodyImage + offset, width - offset + trim, 1, x + offset, y);
  110.                 //head top
  111.                 for (int y = gapY - headHeight; y < gapY; ++y)
  112.                         kos_PutImage(tubeHeadImage + width * (y - (gapY - headHeight)) + offset, width - offset + trimHead, 1, x + offset, y);
  113.                 //head down
  114.                 for (int y = gapY + gapHeight; y < gapY + gapHeight + headHeight; ++y)
  115.                         kos_PutImage(tubeHeadImage + width * (y - (gapY + gapHeight)) + offset, width - offset + trimHead, 1, x + offset, y);
  116.                 //down
  117.                 for (int y = gapY + gapHeight + headHeight; y < WINDOW_HEIGHT - (BORDER_TOP + BORDER_DOWN - 1); ++y)
  118.                         kos_PutImage(tubeBodyImage + offset, width - offset + trim, 1, x + offset, y);
  119.  
  120.         }
  121. };
  122.  
  123. //Global variables
  124. int loopDelay;
  125. GameState gameState;
  126. char scoreString[] = "Score:    ";
  127. bool scoreChanged;
  128. int score;
  129. Bird bird;
  130. int tubeNumber;
  131. Tube tubes[3];
  132. int windowX;
  133. int windowY;
  134.  
  135. //Function prototypes
  136. void kos_Main();
  137. void startGame();
  138. ScreenSize getScreenSize();
  139. void updateScoreString();
  140. void WriteBorderedText(Word x, Word y, Byte fontType, Dword textColor, const char* textPtr, Dword textLen, Dword borderColor, int borderSize);
  141. inline bool checkAddScore(Tube tube);
  142. inline bool checkCollision(Tube tube);
  143.  
  144. void drawMenuWindow();
  145. void drawGameWindow();
  146. void redrawGameWindow();
  147. void drawGameoverWindow();
  148.  
  149. //Functions
  150.  
  151. void startGame()
  152. {
  153.         kos_SetMaskForEvents(0x7); /// 111 in binary
  154.  
  155.         bird.initialize();
  156.  
  157.         score = 0;
  158.         memset((Byte*)scoreString + 6, ' ', 3);
  159.         updateScoreString();
  160.  
  161.         tubeNumber = 1;
  162.         tubes[0].randomize();
  163.  
  164.         gameState = GAMESTATE_STARTED;
  165.         drawGameWindow();
  166. }
  167.  
  168. ScreenSize getScreenSize()
  169. {
  170.         Dword result;
  171.         __asm {
  172.                 push 14         //System function 14
  173.                 pop eax
  174.                 int 0x40
  175.                 mov result, eax
  176.         }
  177.         ScreenSize screenSize;
  178.         screenSize.height = (result & 0xFFFF) + 1;      //last two bytes
  179.         screenSize.width = (result >> 16) + 1;          //first two bytes
  180.         return screenSize;
  181. }
  182.  
  183. void kos_Main()
  184. {
  185.         rtlSrand( kos_GetSystemClock() );
  186.  
  187.         //Centring window
  188.         ScreenSize screenSize = getScreenSize();
  189.         windowX = (screenSize.width - WINDOW_WIDTH) / 2;
  190.         windowY = (screenSize.height - WINDOW_HEIGHT) / 2;
  191.  
  192.         gameState = GAMESTATE_MENU;
  193.  
  194.         kos_SetMaskForEvents(0x27); // 100111 in binary
  195.  
  196.         while( true )
  197.         {
  198.                 switch (gameState)
  199.                 {
  200.                 case GAMESTATE_STARTED:
  201.                         kos_Pause(loopDelay);
  202.  
  203.                         bird.move();
  204.  
  205.                         //Adding new tubes
  206.                         if ((tubeNumber == 1 || tubeNumber == 2) && (tubes[tubeNumber - 1].x < (WINDOW_WIDTH - WINDOW_WIDTH / 3)))
  207.                                 tubes[tubeNumber++].randomize();
  208.  
  209.                         //Processing all tubes
  210.                         scoreChanged = false;
  211.                         for (int i = 0; i < tubeNumber; ++i)
  212.                         {
  213.                                 //Adding score
  214.                                 if (checkAddScore(tubes[i]))
  215.                                 {
  216.                                         ++score;
  217.                                         scoreChanged = true;
  218.                                 }
  219.  
  220.                                 //Check collision with bird
  221.                                 if (checkCollision(tubes[i]))
  222.                                 {
  223.                                         gameState = GAMESTATE_GAMEOVER;
  224.                                         continue;
  225.                                 }
  226.  
  227.                                 //Move tube
  228.                                 tubes[i].move();
  229.                         }
  230.  
  231.                         if (scoreChanged)
  232.                                 updateScoreString();
  233.  
  234.                         //Cheking the bird is too high or low
  235.                         if (bird.y + bird.sizeY > WINDOW_HEIGHT - (BORDER_TOP + BORDER_DOWN - 1) || bird.y < 0)
  236.                         {
  237.                                 gameState = GAMESTATE_GAMEOVER;
  238.                                 continue;
  239.                         }
  240.  
  241.                         redrawGameWindow();
  242.  
  243.                         switch (kos_CheckForEvent())
  244.                         {
  245.                         case 1:
  246.                                 drawGameWindow();
  247.                                 break;
  248.  
  249.                         case 2: // key pressed
  250.                                 Byte keyCode;
  251.                                 kos_GetKey(keyCode);
  252.                                 if (keyCode == 32) //if pressed key is spacebar
  253.                                         bird.jump();
  254.                                 break;
  255.  
  256.                         case 3: // button pressed; we have only one button, close
  257.                                 kos_ExitApp();
  258.                         }
  259.                         break;
  260.  
  261.                 case GAMESTATE_GAMEOVER:
  262.                         drawGameoverWindow();
  263.  
  264.                         switch (kos_WaitForEvent())
  265.                         {
  266.                         case 1:
  267.                                 drawGameoverWindow();
  268.                                 break;
  269.  
  270.                         case 2:
  271.                                 startGame();
  272.                                 break;
  273.  
  274.                         case 3:
  275.                                 kos_ExitApp();
  276.                         }
  277.                         break;
  278.  
  279.                 case GAMESTATE_MENU:
  280.                         switch (kos_WaitForEvent())
  281.                         {
  282.                         case 1:
  283.                                 drawMenuWindow();
  284.                                 break;
  285.  
  286.                         case 2:
  287.                                 Byte keyCode;
  288.                                 kos_GetKey(keyCode);
  289.                                 if (keyCode == 0x31 || keyCode == 0x61) //1 or NumPad1
  290.                                 {
  291.                                         loopDelay = 1;
  292.                                         startGame();
  293.                                 }
  294.                                 else if (keyCode == 0x32 || keyCode == 0x62) //2 or NumPad2
  295.                                 {
  296.                                         loopDelay = 2;
  297.                                         startGame();
  298.                                 }
  299.                                 break;
  300.  
  301.                         case 3:
  302.                                 kos_ExitApp();
  303.  
  304.                         case 6:
  305.                                 Dword result;
  306.                                 __asm {
  307.                                         push 37 //Function 37 - work with mouse
  308.                                         pop eax
  309.                                         mov ebx, 3 //Subfunction 3 - states and events of the mouse buttons
  310.                                         int 0x40
  311.                                         mov result, eax
  312.                                 }
  313.                                 result &= 0x100; //bit 8 is set = left button is pressed
  314.                                 if ( result )
  315.                                 {
  316.                                         Dword coordinates;
  317.                                         __asm {
  318.                                                 push 37 //Function 37 - work with mouse
  319.                                                 pop eax
  320.                                                 mov ebx, 1 //Subfunction 1 - coordinates of the mouse relative to the window
  321.                                                 int             0x40
  322.                                                 mov coordinates, eax
  323.                                         }
  324.                                         int clickX = coordinates >> 16;
  325.                                         int clickY = coordinates & 0xFFFF;
  326.                                         if (clickX >= 100 && clickX < 390 && clickY >= 170 && clickY < 230)
  327.                                         {
  328.                                                 loopDelay = 1;
  329.                                                 startGame();
  330.                                         }
  331.                                         else if (clickX >= 100 && clickX < 390 && clickY >= 270 && clickY < 330)
  332.                                         {
  333.                                                 loopDelay = 2;
  334.                                                 startGame();
  335.                                         }
  336.                                 }
  337.                                 break;
  338.                         }
  339.                         break;
  340.                 }
  341.         }
  342. }
  343.  
  344. void drawGameWindow()
  345. {
  346.         kos_DefineAndDrawWindow(windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT, 0x33, 0x00FFFF, 0, 0, (Dword)HEADER_STRING);
  347.         bird.draw();
  348.         for (int i = 0; i < tubeNumber; ++i)
  349.                 tubes[i].draw();
  350.         kos_WriteTextToWindow(10, 10, 0x81, 0x000000, scoreString, 0);
  351.         kos_WriteTextToWindow(10, 30, 0x81, 0x000000, CONTROL_STRING, 0);
  352. }
  353. void redrawGameWindow()
  354. {
  355.         //cleaning the screen
  356.         if (scoreChanged)
  357.                 kos_DrawBar(80, 10, 50, 15, 0x00FFFF);
  358.         if (bird.y > bird.prev_y)
  359.                 kos_DrawBar(bird.x, bird.prev_y, bird.sizeX, bird.y - bird.prev_y, 0x00FFFF);
  360.         else
  361.                 kos_DrawBar(bird.x, bird.y + bird.sizeY, bird.sizeX, bird.prev_y - bird.y, 0x00FFFF);
  362.  
  363.         bird.draw();
  364.         for (int i = 0; i < tubeNumber; ++i)
  365.                 tubes[i].draw();
  366.  
  367.         kos_WriteTextToWindow(10, 10, 0x81, 0x000000, scoreString, 0);
  368.         kos_WriteTextToWindow(10, 30, 0x81, 0x000000, CONTROL_STRING, 0);
  369. }
  370.  
  371. void drawGameoverWindow()
  372. {
  373.         kos_DefineAndDrawWindow(windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT, 0x33, 0x000000, 0, 0, (Dword)HEADER_STRING);
  374.         kos_WriteTextToWindow(125, 50, 0x82, 0xFFFFFF, GAMEOVER_STRING, 0);
  375.         kos_WriteTextToWindow(135, 100, 0x81, 0xFFFFFF, scoreString, 0);
  376.         kos_WriteTextToWindow(50, 150, 0x81, 0xFFFFFF, ANY_KEY_STRING, 0);
  377. }
  378.  
  379. void WriteBorderedText(Word x, Word y, Byte fontType, Dword textColor, const char *textPtr, Dword textLen, Dword borderColor, int borderSize)
  380. {
  381.         kos_WriteTextToWindow(x - borderSize, y - borderSize, fontType, borderColor, textPtr, textLen);
  382.         kos_WriteTextToWindow(x - borderSize, y + borderSize, fontType, borderColor, textPtr, textLen);
  383.         kos_WriteTextToWindow(x + borderSize, y - borderSize, fontType, borderColor, textPtr, textLen);
  384.         kos_WriteTextToWindow(x + borderSize, y + borderSize, fontType, borderColor, textPtr, textLen);
  385.         kos_WriteTextToWindow(x, y, fontType, textColor, textPtr, textLen);
  386. }
  387.  
  388. void drawMenuWindow()
  389. {
  390.         kos_DefineAndDrawWindow(windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT, 0x33, 0x00FFFF, 0, 0, (Dword)HEADER_STRING);
  391.        
  392.         WriteBorderedText(85, 40, 0x4, 0xFFFFFF, HEADER_STRING, 6, 0x000000, 2);
  393.         WriteBorderedText(185, 80, 0x84, 0xFFFFFF, HEADER_STRING + 7, 0, 0x000000, 2);
  394.  
  395.         RGB* pos = &tubeHeadImage[0];
  396.         for (int x = 100 - 1; x >= 100 - Tube::headHeight; --x)
  397.                 for (int y = 170; y < 170 + Tube::width; ++y)
  398.                 {
  399.                         kos_PutPixel(x, y, (pos->r << 16) + (pos->g << 8) + (pos->b));  //first tube
  400.                         kos_PutPixel(x, y+100, (pos->r << 16) + (pos->g << 8) + (pos->b)); //second tube
  401.                         ++pos;
  402.                 }
  403.  
  404.         //First button
  405.         for(int x = 100; x < WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1); ++x)
  406.                 kos_PutImage(tubeBodyImage, 1, Tube::width, x, 170);
  407.         WriteBorderedText(140, 185, 0x82, 0x000000, FAST_STRING, 0, 0xFFFFFF, 1);
  408.        
  409.         //Second button
  410.         for (int x = 100; x < WINDOW_WIDTH - (BORDER_LEFT + BORDER_RIGHT - 1); ++x)
  411.                 kos_PutImage(tubeBodyImage, 1, Tube::width, x, 270);
  412.         WriteBorderedText(140, 285, 0x82, 0x000000, SLOW_STRING, 0, 0xFFFFFF, 1);
  413. }
  414.  
  415. inline bool checkCollision(Tube tube)
  416. {
  417.         return ((tube.x <= (bird.x + bird.sizeX) && tube.x + tube.width >= bird.x)
  418.                 && (bird.y <= tube.gapY || bird.y + bird.sizeY >= tube.gapY + tube.gapHeight));
  419. }
  420.  
  421. inline bool checkAddScore(Tube tube)
  422. {
  423.         //int diff = bird.x - (tube.x + tube.width);
  424.         //return diff == 0 || diff == 1;
  425.         return ((bird.x - (tube.x + tube.width)) >> 1) == 0;
  426. }
  427.  
  428. void updateScoreString()
  429. {
  430.         int temp = score;
  431.         int index = 9;
  432.         do {
  433.                 scoreString[index--] = temp % 10 + '0';
  434.                 temp /= 10;
  435.         } while (temp > 0);
  436. }