SFML Pong, but object oriented

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. ////////////////////////////////////////////////////////////
  2. // Headers
  3. ////////////////////////////////////////////////////////////
  4. #include <SFML/Graphics.hpp>
  5. #include <SFML/Audio.hpp>
  6. #include <cmath>
  7. #include <ctime>
  8. #include <cstdlib>
  9. #include "Ball.h"
  10. #include "Paddle.h"
  11. #ifdef SFML_SYSTEM_IOS
  12. #include <SFML/Main.hpp>
  13. #endif
  14. using namespace std;
  15. string resourcesDir()
  16. {
  17. #ifdef SFML_SYSTEM_IOS
  18. return "";
  19. #else
  20. return "resources/";
  21. #endif
  22. }
  23. ////////////////////////////////////////////////////////////
  24. /// Entry point of application
  25. ///
  26. /// \return Application exit code
  27. ///
  28. ////////////////////////////////////////////////////////////
  29. int main()
  30. {
  31. srand(static_cast<unsigned int>(time(NULL)));
  32. // Define some constants
  33. const float pi = 3.1415;
  34. const int gameWidth = 800;
  35. const int gameHeight = 600;
  36. float ballRadius = 10;
  37. // Create the window of the application
  38. sf::RenderWindow window(sf::VideoMode(gameWidth, gameHeight, 32), "SFML Pong",
  39. sf::Style::Titlebar | sf::Style::Close);
  40. window.setVerticalSyncEnabled(true);
  41. // Load the sounds used in the game
  42. sf::SoundBuffer ballSoundBuffer;
  43. if (!ballSoundBuffer.loadFromFile(resourcesDir() + "ball.wav"))
  44. return EXIT_FAILURE;
  45. sf::Sound ballSound(ballSoundBuffer);
  46. // Create the left paddle
  47. Paddle leftPaddle;
  48. // Create the right paddle
  49. Paddle rightPaddle;
  50. // Create the ball
  51. Ball ball;
  52. // Load the text font
  53. sf::Font font;
  54. if (!font.loadFromFile(resourcesDir() + "sansation.ttf"))
  55. return EXIT_FAILURE;
  56. // Initialize the pause message
  57. sf::Text pauseMessage;
  58. pauseMessage.setFont(font);
  59. pauseMessage.setCharacterSize(40);
  60. pauseMessage.setPosition(170, 150);
  61. //pauseMessage.setFillColor(sf::Color::White);
  62. #ifdef SFML_SYSTEM_IOS
  63. pauseMessage.setString("Welcome to SFML pong!\nTouch the screen to start the game");
  64. #else
  65. pauseMessage.setString("Welcome to SFML pong!\nPress space to start the game");
  66. #endif
  67. // Define the paddles properties
  68. sf::Clock AITimer;
  69. const sf::Time AITime = sf::seconds(0.1f);
  70. const float paddleSpeed = 400.f;
  71. float rightPaddleSpeed = 0.f;
  72. float ballAngle = 0.f; // to be changed later
  73. sf::Clock clock;
  74. bool isPlaying = false;
  75. while (window.isOpen())
  76. {
  77. // Handle events
  78. sf::Event event;
  79. while (window.pollEvent(event))
  80. {
  81. // Window closed or escape key pressed: exit
  82. if ((event.type == sf::Event::Closed) ||
  83. ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
  84. {
  85. window.close();
  86. break;
  87. }
  88. // Space key pressed: play
  89. if (((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space)) ||
  90. (event.type == sf::Event::TouchBegan))
  91. {
  92. if (!isPlaying)
  93. {
  94. // (re)start the game
  95. isPlaying = true;
  96. clock.restart();
  97. // Reset the position of the paddles and ball
  98. leftPaddle.setPosition(10 + leftPaddle.getSize().x / 2, gameHeight / 2);
  99. rightPaddle.setPosition(gameWidth - 10 - leftPaddle.getSize().x / 2, gameHeight / 2);
  100. ball.setPosition(gameWidth / 2, gameHeight / 2);
  101. // Reset the ball angle
  102. do
  103. {
  104. // Make sure the ball initial angle is not too much vertical
  105. ballAngle = (rand() % 360) * 2 * pi / 360;
  106. }
  107. while (abs(cos(ballAngle)) < 0.7f);
  108. }
  109. }
  110. // Window size changed, adjust view appropriately
  111. if (event.type == sf::Event::Resized)
  112. {
  113. sf::View view;
  114. view.setSize(gameWidth, gameHeight);
  115. view.setCenter(gameWidth/2.f, gameHeight/2.f);
  116. window.setView(view);
  117. }
  118. }
  119. if (isPlaying)
  120. {
  121. float deltaTime = clock.restart().asSeconds();
  122. // Move the player's paddle
  123. if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) &&
  124. (leftPaddle.getY() - leftPaddle.getSize().y / 2 > 5))
  125. {
  126. leftPaddle.move(0.f, -paddleSpeed * deltaTime);
  127. }
  128. if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) &&
  129. (leftPaddle.getY() + leftPaddle.getSize().y / 2 < gameHeight - 5))
  130. {
  131. leftPaddle.move(0.f, paddleSpeed * deltaTime);
  132. }
  133. if (sf::Touch::isDown(0))
  134. {
  135. sf::Vector2i pos = sf::Touch::getPosition(0);
  136. sf::Vector2f mappedPos = window.mapPixelToCoords(pos);
  137. leftPaddle.setPosition(leftPaddle.getX(), mappedPos.y);
  138. }
  139. // Move the computer's paddle
  140. if (((rightPaddleSpeed < 0.f) && (rightPaddle.getY() - leftPaddle.getSize().y / 2 > 5.f)) ||
  141. ((rightPaddleSpeed > 0.f) && (rightPaddle.getY() + leftPaddle.getSize().y / 2 < gameHeight - 5.f)))
  142. {
  143. rightPaddle.move(0.f, rightPaddleSpeed * deltaTime);
  144. }
  145. // Update the computer's paddle direction according to the ball position
  146. if (AITimer.getElapsedTime() > AITime)
  147. {
  148. AITimer.restart();
  149. if (ball.getY() + ballRadius > rightPaddle.getY() + leftPaddle.getSize().y / 2)
  150. rightPaddleSpeed = paddleSpeed;
  151. else if (ball.getY() - ballRadius < rightPaddle.getY() - leftPaddle.getSize().y / 2)
  152. rightPaddleSpeed = -paddleSpeed;
  153. else
  154. rightPaddleSpeed = 0.f;
  155. }
  156. // Move the ball
  157. float factor = ball.getSpeed() * deltaTime;
  158. ball.move(cos(ballAngle) * factor, sin(ballAngle) * factor);
  159. #ifdef SFML_SYSTEM_IOS
  160. const string inputString = "Touch the screen to restart";
  161. #else
  162. const string inputString = "Press space to restart or\nescape to exit";
  163. #endif
  164. // Check collisions between the ball and the screen
  165. if (ball.getX() - ballRadius < 0.f)
  166. {
  167. isPlaying = false;
  168. pauseMessage.setString("You Lost!\n" + inputString);
  169. }
  170. if (ball.getX() + ballRadius > gameWidth)
  171. {
  172. isPlaying = false;
  173. pauseMessage.setString("You Won!\n" + inputString);
  174. }
  175. if (ball.getY() - ballRadius < 0.f)
  176. {
  177. ballSound.play();
  178. ballAngle = -ballAngle;
  179. ball.setPosition(ball.getX(), ballRadius + 0.1f);
  180. }
  181. if (ball.getY() + ballRadius > gameHeight)
  182. {
  183. ballSound.play();
  184. ballAngle = -ballAngle;
  185. ball.setPosition(ball.getX(), gameHeight - ballRadius - 0.1f);
  186. }
  187. // Check the collisions between the ball and the paddles
  188. // Left Paddle
  189. if (ball.getX() - ballRadius < leftPaddle.getX() + leftPaddle.getSize().x / 2 &&
  190. ball.getX() - ballRadius > leftPaddle.getX() &&
  191. ball.getY() + ballRadius >= leftPaddle.getY() - leftPaddle.getSize().y / 2 &&
  192. ball.getY() - ballRadius <= leftPaddle.getY() + leftPaddle.getSize().y / 2)
  193. {
  194. if (ball.getY() > leftPaddle.getY())
  195. ballAngle = pi - ballAngle + (rand() % 20) * pi / 180;
  196. else
  197. ballAngle = pi - ballAngle - (rand() % 20) * pi / 180;
  198. ballSound.play();
  199. ball.setPosition(leftPaddle.getX() + ballRadius + leftPaddle.getSize().x / 2 + 0.1f, ball.getY());
  200. }
  201. // Right Paddle
  202. if (ball.getX() + ballRadius > rightPaddle.getX() - leftPaddle.getSize().x / 2 &&
  203. ball.getX() + ballRadius < rightPaddle.getX() &&
  204. ball.getY() + ballRadius >= rightPaddle.getY() - leftPaddle.getSize().y / 2 &&
  205. ball.getY() - ballRadius <= rightPaddle.getY() + leftPaddle.getSize().y / 2)
  206. {
  207. if (ball.getY() > rightPaddle.getY())
  208. ballAngle = pi - ballAngle + (rand() % 20) * pi / 180;
  209. else
  210. ballAngle = pi - ballAngle - (rand() % 20) * pi / 180;
  211. ballSound.play();
  212. ball.setPosition(rightPaddle.getX() - ballRadius - leftPaddle.getSize().x / 2 - 0.1f, ball.getY());
  213. }
  214. }
  215. // Clear the window
  216. window.clear(sf::Color(50, 200, 50));
  217. if (isPlaying)
  218. {
  219. // Draw the paddles and the ball
  220. window.draw(leftPaddle);
  221. window.draw(rightPaddle);
  222. window.draw(ball);
  223. }
  224. else
  225. {
  226. // Draw the pause message
  227. window.draw(pauseMessage);
  228. }
  229. // Display things on screen
  230. window.display();
  231. }
  232. return EXIT_SUCCESS;
  233. }