Subversion Repositories Kolibri OS

Rev

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