dmilicev

car_race_brick_game_v1.c

Apr 21st, 2021
576
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 18.53 KB
  1. /*
  2.     car_race_brick_game_v1.c         author: Dragan Milicev
  3.                                     https://www.facebook.com/dmilicev
  4.  
  5.     Program is tested on Windows 7 Ultimate.
  6.  
  7.     Car race, simplified graphics.
  8.     Use the left and right arrows to control the car.
  9.     Each wall passed brings 1 point.
  10.     In the beginning you have 3 lives.
  11.     You lose one life with every collision with the wall.
  12.     For every 10 points you get extra life.
  13.     The race starts slowly, at a speed of 50.
  14.     Every 25 points the speed increases by 10.
  15.     Press the space bar to pause.
  16.     Press the ESCAPE key to exit the game.
  17.     Good luck!
  18.  
  19.     Inspired from:
  20.     https://create.arduino.cc/projecthub/Homer/arduino-web-based-car-race-brick-game-cb1b30
  21.     Video:
  22.     https://youtu.be/BvSdFNwcyLY
  23.  
  24.     Source code:
  25.     https://mega.nz/file/G9RzVSKY#vgxKoEZf5EygomVuU0GJOPL2A2WPwZ8H_UbTKK299Qo
  26.  
  27.     Compiled exe file:
  28.     https://mega.nz/file/upBHDSSD#-w-bbZ2K_i4tPrZf4hCO5FP2NlQ8Bt5mxcVSExpq7Xw
  29.  
  30.     Zipped source and exe file:
  31.     https://mega.nz/file/mgBRiS5A#dgjXpF_TyqMJ-IT4gBQLiQdIo4raPhg25g032Zwttpw
  32.  
  33.  
  34.     You can find all my C programs at Dragan Milicev's pastebin:
  35.  
  36.     https://pastebin.com/u/dmilicev
  37.  
  38. */
  39.  
  40. #include <stdio.h>
  41. #include<stdlib.h>          // for rand()
  42. #include<time.h>            // for random number generator
  43. #include <windows.h>        // tracking cursor all the time, for cursor position functions
  44.                             // gotoxy(x,y) , wherex() , wherey(), showcursor(), hidecursor()
  45.  
  46. #define MAX_COLUMNS 80      // of the console window
  47. #define MAX_ROWS    80      // of the console window
  48. #define UP          72      // up arrow
  49. #define DOWN        80      // down arrow
  50. #define LEFT        75      // left arrow
  51. #define RIGHT       77      // right arrow
  52. #define SPACE       32      // Space key, to pause the game
  53. #define ESC         27      // Escape key to quit the game
  54.  
  55.  
  56. // ----------CURSOR CONTROL FUNCTIONS------------------------------------------
  57.  
  58. // make console cursor invisible
  59. void hidecursor()
  60. {
  61.    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  62.    CONSOLE_CURSOR_INFO info;
  63.    info.dwSize = 20;
  64.    info.bVisible = FALSE;
  65.    SetConsoleCursorInfo(consoleHandle, &info);
  66. }
  67.  
  68. // make console cursor invisible
  69. void showcursor()
  70. {
  71.    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  72.    CONSOLE_CURSOR_INFO info;
  73.    info.dwSize = 20;
  74.    info.bVisible = TRUE;
  75.    SetConsoleCursorInfo(consoleHandle, &info);
  76. }
  77.  
  78. // place cursor at position ( x, y ) = ( column, row )
  79. void gotoxy( int column, int row )
  80. {
  81.     COORD coord;
  82.  
  83.     coord.X = column;
  84.     coord.Y = row;
  85.  
  86.     SetConsoleCursorPosition( GetStdHandle(STD_OUTPUT_HANDLE), coord );
  87. }
  88.  
  89. // return x coordinate (column) of current cursor position
  90. // on failure return -1
  91. int wherex()
  92. {
  93.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  94.  
  95.     if (!GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &csbi ) )
  96.         return -1;
  97.  
  98.     return csbi.dwCursorPosition.X;
  99. }
  100.  
  101. // return y coordinate (row) of current cursor position
  102. // on failure return -1
  103. int wherey()
  104. {
  105.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  106.  
  107.     if (!GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi ) )
  108.         return -1;
  109.  
  110.     return csbi.dwCursorPosition.Y;
  111. }
  112.  
  113. // END OF-----CURSOR CONTROL FUNCTIONS------------------------------------------
  114.  
  115. // ----------TEXT AND BACKGROUND COLOR CONTROL FUNCTIONS------------------------
  116.  
  117. void ClearConsoleToColors(int ForgC, int BackC)
  118. {
  119.      WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);
  120.      ///Get the handle to the current output buffer...
  121.      HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  122.      ///This is used to reset the carat/cursor to the top left.
  123.      COORD coord = {0, 0};
  124.      ///A return value... indicating how many chars were written
  125.      ///   not used but we need to capture this since it will be
  126.      ///   written anyway (passing NULL causes an access violation).
  127.      DWORD count;
  128.      ///This is a structure containing all of the console info
  129.      /// it is used here to find the size of the console.
  130.      CONSOLE_SCREEN_BUFFER_INFO csbi;
  131.      ///Here we will set the current color
  132.      SetConsoleTextAttribute(hStdOut, wColor);
  133.      if(GetConsoleScreenBufferInfo(hStdOut, &csbi))
  134.      {
  135.           ///This fills the buffer with a given character (in this case 32=space).
  136.           FillConsoleOutputCharacter(hStdOut, (TCHAR) 32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
  137.           FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count );
  138.           ///This will set our cursor position for the next print statement.
  139.           SetConsoleCursorPosition(hStdOut, coord);
  140.      }
  141.      return;
  142. } //ClearConsoleToColors()
  143.  
  144. void SetColorAndBackground(int ForgC, int BackC)
  145. {
  146.      WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);;
  147.      SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor);
  148.      return;
  149. } //SetColorAndBackground()
  150.  
  151. // END OF----TEXT AND BACKGROUND COLOR CONTROL FUNCTIONS------------------------
  152.  
  153. // wait (do nothing) for time in milliseconds
  154. void wait( int milliseconds )
  155. {
  156.     clock_t start_time = clock();   // get start time
  157.  
  158.     // looping (do nothing) till required time is not acheived
  159.     while ( clock() < start_time + milliseconds )
  160.         ;                           // do nothing
  161. } // wait()
  162.  
  163. // generate and return random integer number between lower and upper, including them.
  164. int get_random_integer_from_lower_to_uppper(int lower, int upper)
  165. {
  166.     // generate and return random number between 0 and upper-1
  167.     //return( rand() % upper );
  168.  
  169.     // generate and return random number between 1 and upper
  170.     //return( rand() % upper + 1 );
  171.  
  172.     // generate and return random integer number between lower and upper
  173.     return( (rand() % (upper - lower + 1)) + lower );
  174. } // get_random_integer_from_lower_to_uppper()
  175.  
  176. // Deletes the car in place xc,yc
  177. void delete_car( int xc, int yc, int x, int y )
  178. {
  179.     gotoxy(x+xc,yc);                // delete car
  180.     putchar(32);                    // space, blanko
  181. } // print_car()
  182.  
  183. // Print the car in place xc,yc
  184. void print_car( int xc, int yc, int x, int y )
  185. {
  186.     gotoxy(x+xc,yc);                // print car
  187.     putchar(219);                   // 219, 176, 177, 178
  188. } // print_car()
  189.  
  190. // Makes an empty line, a wall without bricks.
  191. void make_empty_line( int BL[MAX_ROWS], int row, int column )
  192. {
  193.     int i;
  194.  
  195.     for(i=0;i<column;i++){          // we reset them all to zero
  196.         BL[i] = 0;
  197.     }
  198. } // make_empty_line()
  199.  
  200. // Makes one row (line) BL[] of Brik_Matrix BM[][]
  201. // with num_of_bricks randomly arranged in a line
  202. void make_Brik_Line( int BL[MAX_ROWS], int row, int column, int num_of_bricks )
  203. {
  204.     int r, c, counter=0;
  205.     int completed[MAX_COLUMNS];
  206.  
  207.     for(c=0;c<column;c++){          // we reset them all to zero
  208.         BL[c] = 0;
  209.         completed[c] = 0;
  210.     }
  211.  
  212.     while( counter < num_of_bricks ){
  213.         r = get_random_integer_from_lower_to_uppper(0,column-1);// a random number between 1 and column
  214.         if( !completed[r] ){        // if that has not already been processed
  215.             BL[r] = 1;              // there is a brick
  216.             completed[r] = 1;       // that is now processed
  217.             counter++;              // we increase the counter of bricks in line
  218.         }
  219.     }
  220. } // make_Brik_Line()
  221.  
  222. // Prints the entire matrix with bricks, BM with rows and columns
  223. // on place x,y
  224. void print_Brik_Matrix( int x, int y, int BM[MAX_ROWS][MAX_COLUMNS], int rows, int columns )
  225. {
  226.     int r, c, d, j, x_mem=x, y_mem=y;
  227.  
  228.     for(r=0;r<rows;r++){
  229.         gotoxy(x++,y);
  230.         putchar(179);               // '|'
  231.         for(c=0;c<columns;c++){
  232.             gotoxy(x++,y);
  233.             if( BM[r][c] == 1 )
  234.                 putchar(177);       // 176, 177, 178, 219, 254
  235.             else
  236.                 putchar(32);        // blanko space
  237.         }
  238.         gotoxy(x++,y);
  239.         putchar(179);               // '|'
  240.  
  241.         x = x_mem;                  // new line
  242.         y++;
  243.     }
  244. } // print_Brik_Matrix()
  245.  
  246. // Determine if the last row of the matrix BM contains bricks.
  247. // Returns 1 if last row of matrix BM contains bricks, otherwise returns 0
  248. int last_row_of_the_matrix_contains_bricks( int BM[MAX_ROWS][MAX_COLUMNS], int rows, int columns )
  249. {
  250.     int c, flag_contain_brick=0;
  251.  
  252.     for(c=0;c<columns;c++){
  253.         if( BM[rows-1][c] == 1 ) {
  254.             flag_contain_brick = 1;  // one brick was found
  255.             return 1;               // exit for loop and function
  256.         }
  257.     }
  258.     return 0;                       // last row of the matrix does not contain bricks
  259. }
  260.  
  261. // Scrolls the matrix with the bricks BM down one row.
  262. // Adds a new row to the top of the matrix.
  263. void scroll_Brik_Matrix( int x, int y,
  264.                          int BM[MAX_ROWS][MAX_COLUMNS], int rows, int columns,
  265.                          int distance )
  266. {
  267.     int r, c, d, j, flag_contain_brick, x_mem=x, y_mem=y;
  268.  
  269.     // determine if the last row of the matrix contains bricks
  270.     flag_contain_brick = last_row_of_the_matrix_contains_bricks( BM, rows, columns );
  271.  
  272.     // Lower the rows of the matrix by 1 row
  273.     for(r=rows-1;r>0;r--){
  274.         for(c=0;c<columns;c++){
  275.             BM[r][c] = BM[r-1][c];
  276.         }
  277.     }
  278.  
  279.     // make new random first line on top of matrix BM[][]
  280.     if( flag_contain_brick )
  281.         make_Brik_Line( BM[0], rows, columns, get_random_integer_from_lower_to_uppper(1,columns-1) );
  282.     else
  283.         make_empty_line( BM[0], rows, columns );
  284.  
  285.     print_Brik_Matrix( x, y, BM, rows, columns );
  286. } // scroll_Brik_Matrix()
  287.  
  288. // Make a BM matrix with bricks.
  289. // Leaves a distance between the rows of bricks
  290. void make_Brik_Matrix(  int BM[MAX_ROWS][MAX_COLUMNS],
  291.                         int rows, int columns,
  292.                         int num_of_bricks, int distance )
  293. {
  294.     int i=0, d;
  295.  
  296.     while( i<rows ){
  297.         // distance empty lines
  298.         for(d=0;d<distance;d++){
  299.             make_empty_line( BM[i++], rows, columns );
  300.         }
  301.         // line with bricks
  302.         make_Brik_Line( BM[i++], rows, columns, get_random_integer_from_lower_to_uppper(1,num_of_bricks) );
  303.     }
  304. } // make_Brik_Matrix()
  305.  
  306. // ----------FUNCTIONS TO MOVE CURSOR -----------------------------------------
  307.  
  308. // not used
  309. void move_up( )
  310. {
  311.  
  312. }
  313.  
  314. // not used
  315. void move_down( )
  316. {
  317.  
  318. }
  319.  
  320. // Move cursor left. The coordinates of the cursor are xc,yc.
  321. void move_left( int *xc, int *yc, int x, int y )
  322. {
  323.     if( *xc > 1 ){                      // if there is room to go left
  324.         delete_car( *xc, *yc, x, y );   // delete the old position of the car
  325.         (*xc)--;                        // new xc coordinate of the car position
  326.         print_car( *xc, *yc, x, y );    // print car in a new position
  327.     }
  328. }
  329.  
  330. // Move cursor right. The coordinates of the cursor are xc,yc.
  331. void move_right( int *xc, int *yc,  int x, int y, int columns )
  332. {
  333.     if( *xc < columns ){                // if there is room to go right
  334.         delete_car( *xc, *yc, x, y );   // delete the old position of the car
  335.         (*xc)++;                        // new xc coordinate of the car position
  336.         print_car( *xc, *yc, x, y );    // print car in a new position
  337.     }
  338. }
  339.  
  340. // END OF----FUNCTIONS TO MOVE CURSOR -----------------------------------------
  341.  
  342. // Prints statistics of results in place with coordinates x,y
  343. void print_scores( int x, int y,
  344.                    int number_of_lives,
  345.                    int number_of_passages_through_walls,
  346.                    int number_of_extra_lives,
  347.                    int number_of_lost_lives,
  348.                    int delay_time )
  349. {
  350.     gotoxy(x,y-9);
  351.     printf("speed           = %5d ", 250-delay_time);
  352.     gotoxy(x,y-7);
  353.     printf("lost lives      = %5d ", number_of_lost_lives);
  354.     gotoxy(x,y-5);
  355.     printf("extra lives     = %5d ", number_of_extra_lives);
  356.     gotoxy(x,y-3);
  357.     printf("number of wals  = %5d ", number_of_passages_through_walls);
  358.     gotoxy(x,y-1);
  359.     printf("number of lives = %5d ", number_of_lives);
  360. }
  361.  
  362. // Prints help screen
  363. void print_help()
  364. {
  365.     int x=1, y=2;
  366.  
  367.     // print title
  368.     gotoxy(x+15,y+=2);
  369.     printf("CAR RACE BRICK GAME");
  370.  
  371.     gotoxy(x,y+=5);
  372.     printf("Use the left and right arrows to control the car.");
  373.     gotoxy(x,y+=2);
  374.     printf("Each wall passed brings 1 point.");
  375.     gotoxy(x,y+=2);
  376.     printf("In the beginning you have 3 lives.");
  377.     gotoxy(x,y+=2);
  378.     printf("You lose 1 life with every collision with the wall.");
  379.     gotoxy(x,y+=2);
  380.     printf("For every 10 points you get extra life.");
  381.     gotoxy(x,y+=2);
  382.     printf("The race starts slowly, at a speed of 50.");
  383.     gotoxy(x,y+=2);
  384.     printf("Every 25 points the speed increases by 10.");
  385.     gotoxy(x,y+=2);
  386.     printf("Press the space bar to pause.");
  387.     gotoxy(x,y+=2);
  388.     printf("Press the ESCAPE key to exit the game.");
  389.     gotoxy(x,y+=3);
  390.     printf("Good luck!");
  391.  
  392.     gotoxy(x+17,y+=4);
  393.     printf("author Dragan Milicev");
  394.     gotoxy(x+17,y+=2);
  395.     printf("https://www.facebook.com/dmilicev");
  396.  
  397.     gotoxy(x,y+=5);
  398.     printf("Press any key to start race ...");
  399.  
  400.     _getch();                           // pause
  401.     system("CLS");
  402. }
  403.  
  404. // ----------KEYBOARD CONTROL--------------------------------------------------
  405.  
  406. /*
  407.     Keyboard control:
  408. UP          up arrow
  409. DOWN        down arrow
  410. LEFT        left arrow
  411. RIGHT       right arrow
  412. Key Space,  SPACE (32) for pause.
  413. Key Escape, ESC (27) for quit.
  414. */
  415. int keyboard_control( int x, int y,
  416.                       int BM[MAX_ROWS][MAX_COLUMNS], int rows, int columns,
  417.                       int distance )
  418. {
  419.     int xc, yc;                             // car coordinates
  420.     int choice;                             // for pressed key
  421.     int delay_time=200;                     // delay time for speed
  422.     int number_of_lives=3;
  423.     int number_of_passages_through_walls=0;
  424.     int number_of_extra_lives=0;
  425.     int number_of_lost_lives=0;
  426.     int tens=10;
  427.     int twenty_fives=25;
  428.  
  429.     xc = columns/2+1;                       // car coordinates
  430.     yc = rows-1;
  431.  
  432.     // print title
  433.     gotoxy(7,rows-27);
  434.     printf("CAR RACE BRICK GAME");
  435.     gotoxy(7,rows-23);
  436.     printf("author Dragan Milicev");
  437.  
  438.     while( 1 ) {                    // an infinite loop that exits with choice Ecsape, ESC (27)
  439.  
  440.         while( !_kbhit() ){                 // until a key is pressed
  441.             wait(delay_time);               // delay time for speed
  442.             scroll_Brik_Matrix( x, y, BM, rows, columns, distance );
  443.  
  444.             // determine if the last row of the matrix contains bricks
  445.             if( last_row_of_the_matrix_contains_bricks( BM, rows, columns ) )
  446.                 number_of_passages_through_walls++;     // count number_of_passages_through_walls
  447.  
  448.             if( number_of_passages_through_walls == tens ){
  449.                 number_of_extra_lives++;
  450.                 number_of_lives++;
  451.                 tens += 10;
  452.             }
  453.  
  454.             if( number_of_passages_through_walls == twenty_fives ){
  455.                 delay_time -= 10;
  456.                 twenty_fives += 25;
  457.             }
  458.  
  459.             // collision calculation, if the car is in the same place where the brick is in the last row
  460.             if( BM[rows-1][xc-1] == 1 ){
  461.                 gotoxy(x+xc,yc);
  462.                 putchar('X');               // replace car with X
  463.                 number_of_lives--;
  464.                 number_of_lost_lives++;
  465.                 print_scores( 6, rows,
  466.                               number_of_lives,
  467.                               number_of_passages_through_walls,
  468.                               number_of_extra_lives,
  469.                               number_of_lost_lives,
  470.                               delay_time );
  471.  
  472.                 if ( number_of_lives == 0 )
  473.                     return( choice );       // end of game
  474.                 _getch();                   // pause
  475.             }
  476.             else
  477.                 print_car(xc,yc,x,y);
  478.  
  479.                 print_scores( 6, rows,
  480.                               number_of_lives,
  481.                               number_of_passages_through_walls,
  482.                               number_of_extra_lives,
  483.                               number_of_lost_lives,
  484.                               delay_time );
  485.         } // while( !_kbhit() )
  486.  
  487.         choice = _getch();                  // read the keyboard
  488.  
  489.         if( choice == 0 || choice == 224 )  // if is pressed function key with leading 0 or 224
  490.         {
  491.             choice = _getch();              // let's empty that 0 or 224
  492.  
  493.             if( choice == UP )              // if pressed up arrow
  494.             {
  495.                 // not used
  496.             }
  497.  
  498.             if( choice == DOWN )            // if pressed down arrow
  499.             {
  500.                 // not used
  501.             }
  502.  
  503.             if( choice == LEFT )            // if pressed left arrow
  504.             {
  505.                 move_left( &xc, &yc, x, y );
  506.             }
  507.  
  508.             if( choice == RIGHT )           // if pressed right arrow
  509.             {
  510.                 move_right( &xc, &yc, x, y, columns );
  511.             }
  512.  
  513.         } // end of: if is pressed function key with leading 0 or 224
  514.         else    // if pressed ordinary keys
  515.         {
  516.             if( choice == SPACE )           // if is pressed SPACE
  517.             {
  518.                 _getch();                   // pause the game
  519.             }
  520.  
  521.             if( choice == ESC )             // if is pressed ESC
  522.             {
  523.                 return( choice );           // end of game
  524.             }
  525.  
  526.         } // end of: if pressed ordinary keys
  527.  
  528.     } // end of: while( 1 )
  529.  
  530.     return( choice );                       // have to return something
  531. }
  532.  
  533. // END OF----KEYBOARD CONTROL--------------------------------------------------
  534.  
  535. int main(void)
  536. {
  537.     int i, x=30, y=0, lines=6, columns=5, num_of_bricks=columns-1, distance=columns;
  538.     int BM[MAX_ROWS][MAX_COLUMNS];          // matrix, BM stands for Brik Matrix
  539.     time_t t;                               // for random number generator
  540.  
  541.     srand((unsigned) time(&t)); // Intializes random number generator, should only be called once.
  542.  
  543.     system("MODE CON: COLS=53 LINES=43");   // select MODE (size) of Console Window
  544.  
  545.     hidecursor();
  546.  
  547.     print_help();
  548.  
  549.     make_Brik_Matrix( BM, lines*distance+lines, columns, num_of_bricks, distance );
  550.  
  551.     print_Brik_Matrix( x, y, BM, lines*distance+lines, columns );
  552.  
  553.     keyboard_control( x, y, BM, lines*distance+lines, columns, distance );
  554.  
  555.     gotoxy(x-2,lines*distance+lines+1);
  556.     printf(" GAME OVER \n");
  557.     showcursor();
  558.  
  559.     return 0;
  560. } // main()
  561.  
RAW Paste Data Copied