Hello!
This might not be the ideal forum section so please move my topic if it's misplaced here. Also I don't know if you're open to such modifications or not.
I've modified a little bit the SFML 2 Pong example to slightly enhance the gameplay, that is:
- there is a 1 second delay before a round starts (shows how to use an sf::Clock),
- the game restarts when a player scores a point (encourages to play),
- the scores are printed on the screen instead of the end text (show how to print variables with sf::Text),
- fixes AITime to sf::Uint32,
- added comments.
Just an idea: a new sound (a whistle) could be played on every new round.
I think along with these enhancement the example is still encouraging the new users to modify it but also to play with it.
What do you think?
The code:
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
//#include <cmath>
//#include <ctime>
//#include <cstdlib>
#include <sstream>
////////////////////////////////////////////////////////////
/// Entry point of application
///
/// \return Application exit code
///
////////////////////////////////////////////////////////////
int main()
{
std::srand(static_cast<unsigned int>(std::time(NULL)));
// Defines PI
const float PI = 3.14159f;
// Create the window of the application
sf::RenderWindow window(sf::VideoMode(800, 600, 32), "SFML Pong");
// Load the sounds used in the game
sf::SoundBuffer ballSoundBuffer;
if (!ballSoundBuffer.LoadFromFile("resources/ball.wav"))
{
return EXIT_FAILURE;
}
sf::Sound ballSound(ballSoundBuffer);
// Load the textures used in the game
sf::Texture backgroundTexture, leftPaddleTexture, rightPaddleTexture, ballTexture;
if (!backgroundTexture.LoadFromFile("resources/background.jpg") ||
!leftPaddleTexture.LoadFromFile("resources/paddle_left.png") ||
!rightPaddleTexture.LoadFromFile("resources/paddle_right.png") ||
!ballTexture.LoadFromFile("resources/ball.png"))
{
return EXIT_FAILURE;
}
// Load the text font
sf::Font font;
if (!font.LoadFromFile("resources/sansation.ttf"))
return EXIT_FAILURE;
// Initialize the score text
sf::Text scoreText;
scoreText.SetFont(font);
scoreText.SetCharacterSize(60);
scoreText.SetColor(sf::Color(50, 50, 250));
// Create the sprites of the background, the paddles and the ball
sf::Sprite background(backgroundTexture);
sf::Sprite leftPaddle(leftPaddleTexture);
sf::Sprite rightPaddle(rightPaddleTexture);
sf::Sprite ball(ballTexture);
leftPaddle.Move(10, (window.GetView().GetSize().y - leftPaddle.GetSize().y) / 2);
rightPaddle.Move(window.GetView().GetSize().x - rightPaddle.GetSize().x - 10, (window.GetView().GetSize().y - rightPaddle.GetSize().y) / 2);
// Define the paddles properties
sf::Clock AITimer;
sf::Uint32 AITime = 200;
float leftPaddleSpeed = 400.f;
float rightPaddleSpeed = 400.f;
// Define the ball properties
float ballSpeed = 400.f;
float ballAngle;
// Main loop
int leftScore = 0, rightScore = 0;
sf::Clock start;
bool restart = true;
while (window.IsOpened())
{
// Handle events
sf::Event event;
while (window.PollEvent(event))
{
// Window closed or escape key pressed : exit
if ((event.Type == sf::Event::Closed) ||
((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Keyboard::Escape)))
{
window.Close();
break;
}
}
// Restart the game
if (restart)
{
// Make sure the ball initial angle is not too much vertical
do
{
ballAngle = std::rand() * 2 * PI / RAND_MAX;
}
while (std::abs(std::cos(ballAngle)) < 0.7f);
ball.SetPosition((window.GetView().GetSize().x - ball.GetSize().x) / 2, (window.GetView().GetSize().y - ball.GetSize().y) / 2);
// Update score
std::ostringstream oss;
oss << leftScore << " : " << rightScore;
scoreText.SetString(oss.str());
scoreText.SetPosition((window.GetView().GetSize().x / 2) - (scoreText.GetRect().Width / 2), 20.f);
// Reset
start.Reset();
restart = false;
}
if (!restart)
{
// Move the player's paddle
if (sf::Keyboard::IsKeyPressed(sf::Keyboard::Up) && (leftPaddle.GetPosition().y > 5.f))
leftPaddle.Move(0.f, -leftPaddleSpeed * window.GetFrameTime() / 1000.f);
if (sf::Keyboard::IsKeyPressed(sf::Keyboard::Down) && (leftPaddle.GetPosition().y < window.GetView().GetSize().y - leftPaddle.GetSize().y - 5.f))
leftPaddle.Move(0.f, leftPaddleSpeed * window.GetFrameTime() / 1000.f);
// Move the computer's paddle
if (((rightPaddleSpeed < 0.f) && (rightPaddle.GetPosition().y > 5.f)) ||
((rightPaddleSpeed > 0.f) && (rightPaddle.GetPosition().y < window.GetView().GetSize().y - rightPaddle.GetSize().y - 5.f)))
{
rightPaddle.Move(0.f, rightPaddleSpeed * window.GetFrameTime() / 1000.f);
}
// Update the computer's paddle direction according to the ball position
if (AITimer.GetElapsedTime() > AITime)
{
AITimer.Reset();
if ((rightPaddleSpeed < 0) && (ball.GetPosition().y + ball.GetSize().y > rightPaddle.GetPosition().y + rightPaddle.GetSize().y))
rightPaddleSpeed = -rightPaddleSpeed;
if ((rightPaddleSpeed > 0) && (ball.GetPosition().y < rightPaddle.GetPosition().y))
rightPaddleSpeed = -rightPaddleSpeed;
}
// Wait a second before the ball starts moving
if (start.GetElapsedTime() > 1000)
{
// Move the ball
float factor = ballSpeed * window.GetFrameTime() / 1000.f;
ball.Move(std::cos(ballAngle) * factor, std::sin(ballAngle) * factor);
}
// Check collisions between the ball and the screen
if (ball.GetPosition().x < 0.f)
{
restart = true;
++rightScore;
}
if (ball.GetPosition().x + ball.GetSize().x > window.GetView().GetSize().x)
{
restart = true;
++leftScore;
}
if (ball.GetPosition().y < 0.f)
{
ballSound.Play();
ballAngle = -ballAngle;
ball.SetY(0.1f);
}
if (ball.GetPosition().y + ball.GetSize().y > window.GetView().GetSize().y)
{
ballSound.Play();
ballAngle = -ballAngle;
ball.SetY(window.GetView().GetSize().y - ball.GetSize().y - 0.1f);
}
// Check the collisions between the ball and the paddles
// Left Paddle
if (ball.GetPosition().x < leftPaddle.GetPosition().x + leftPaddle.GetSize().x &&
ball.GetPosition().x > leftPaddle.GetPosition().x + (leftPaddle.GetSize().x / 2.0f) &&
ball.GetPosition().y + ball.GetSize().y >= leftPaddle.GetPosition().y &&
ball.GetPosition().y <= leftPaddle.GetPosition().y + leftPaddle.GetSize().y)
{
ballSound.Play();
ballAngle = PI - ballAngle;
ball.SetX(leftPaddle.GetPosition().x + leftPaddle.GetSize().x + 0.1f);
}
// Right Paddle
if (ball.GetPosition().x + ball.GetSize().x > rightPaddle.GetPosition().x &&
ball.GetPosition().x + ball.GetSize().x < rightPaddle.GetPosition().x + (rightPaddle.GetSize().x / 2.0f) &&
ball.GetPosition().y + ball.GetSize().y >= rightPaddle.GetPosition().y &&
ball.GetPosition().y <= rightPaddle.GetPosition().y + rightPaddle.GetSize().y)
{
ballSound.Play();
ballAngle = PI - ballAngle;
ball.SetX(rightPaddle.GetPosition().x - ball.GetSize().x - 0.1f);
}
}
// Clear the window
window.Clear();
// Draw the background, paddles and ball sprites
window.Draw(background);
window.Draw(leftPaddle);
window.Draw(rightPaddle);
window.Draw(ball);
window.Draw(scoreText);
// Display things on screen
window.Display();
}
return EXIT_SUCCESS;
}
Cheers,
easy