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