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