A simple C and ncurses pong game
c
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pong.c 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include <ncurses.h>
  2. #include <unistd.h>
  3. #include <time.h>
  4. #include <stdlib.h>
  5. const int DELAY = 30000;
  6. const int PADDLE_SIZE = 5;
  7. const int PADDLE_SPEED = 4;
  8. int kbhit()
  9. {
  10. int ch = getch();
  11. if (ch != ERR) {
  12. ungetch(ch);
  13. return 1;
  14. } else {
  15. return 0;
  16. }
  17. }
  18. void print_paddle(int size, int y, int x)
  19. {
  20. for (int i = 0; i < size; ++i)
  21. mvprintw(y - i, x, "|");
  22. }
  23. void decorations(int width, int height)
  24. {
  25. for (int i = 0; i < width; ++i)
  26. mvprintw(0, i, "*");
  27. for (int i = 0; i < width; ++i)
  28. mvprintw(height - 1, i, "*");
  29. }
  30. // Updates the panel of information
  31. void refresh_score(int lives, int hits)
  32. {
  33. char str_lives[3];
  34. char str_hits[3];
  35. sprintf(str_lives, "%d", lives);
  36. sprintf(str_hits, "%d", hits);
  37. mvprintw(1, 1, "Lives:");
  38. mvprintw(1, 9, str_lives);
  39. mvprintw(1, 13, "Hits:");
  40. mvprintw(1, 20, str_hits);
  41. }
  42. int main()
  43. {
  44. srand(time(NULL)); // initiate randomness
  45. int ball_x = 20, ball_y = 10, paddle_y = 10;
  46. int max_y = 0, max_x = 0;
  47. int ball_next_x = 0, ball_next_y = 0;
  48. int ball_direction_x = 1, ball_direction_y = 0;
  49. int lives = 5;
  50. int hits = 0;
  51. initscr();
  52. noecho();
  53. nodelay(stdscr, TRUE);
  54. curs_set(FALSE);
  55. while (1) {
  56. getmaxyx(stdscr, max_y, max_x);
  57. if (kbhit()) {
  58. switch (getch()) {
  59. case 'q':
  60. endwin();
  61. return 0;
  62. case 'w':
  63. if ((paddle_y - PADDLE_SPEED) > 0)
  64. paddle_y -= PADDLE_SPEED;
  65. else
  66. paddle_y = PADDLE_SIZE;
  67. break;
  68. case 's':
  69. if ((paddle_y + PADDLE_SPEED) < max_y)
  70. paddle_y += PADDLE_SPEED;
  71. else
  72. paddle_y = max_y - 1;
  73. break;
  74. }
  75. }
  76. clear();
  77. decorations(max_x, max_y);
  78. refresh_score(lives, hits);
  79. mvprintw(ball_y, ball_x, "o");
  80. print_paddle(PADDLE_SIZE, paddle_y, max_x - 2);
  81. refresh();
  82. usleep(DELAY - hits * 500); // Make it progressively faster
  83. ball_next_x = ball_x + ball_direction_x;
  84. ball_next_y = ball_y + ball_direction_y;
  85. // Check if the ball is going to hit any part of the paddle
  86. for (int i = 0; i < PADDLE_SIZE; ++i) {
  87. if (ball_y == paddle_y - i && ball_next_x >= max_x - 2) {
  88. ball_direction_x *= -1;
  89. ball_direction_y = rand() % 3 - 1;
  90. hits++;
  91. break;
  92. }
  93. }
  94. // Check if the ball is going to hit the edges
  95. if (ball_next_x >= max_x || ball_next_x < 0)
  96. ball_direction_x *= -1;
  97. else
  98. ball_x += ball_direction_x;
  99. if (ball_next_y >= max_y - 1 || ball_next_y < 1)
  100. ball_direction_y *= -1;
  101. else
  102. ball_y += ball_direction_y;
  103. // Check if the ball gets past the paddle
  104. if (ball_next_x > max_x - 2) {
  105. lives -= 1;
  106. sleep(1);
  107. if (lives == 0)
  108. break;
  109. ball_x = 20;
  110. ball_y = 10;
  111. ball_direction_y = 0;
  112. ball_direction_x = 1;
  113. }
  114. }
  115. mvprintw(10, 34, "GAME OVER!");
  116. mvprintw(11, 31, "press \'q\' to quit");
  117. refresh();
  118. while (getchar() != 'q');
  119. endwin();
  120. printf("GAME OVER. You got %d hits!\n", hits);
  121. return 0;
  122. }