SFML C++ Pong Game Project: Code Breakdown

This document presents the core C++ source code for a simple Pong game built using the SFML multimedia library. It details the implementation of the Ball and Bat classes, along with the main game loop.

Ball Class Implementation

The Ball class manages the game ball’s properties and behavior, including its position, shape, speed, and collision responses.

Ball.h: Class Definition

#pragma once
#include <SFML/Graphics.hpp>

using namespace sf;

class Ball {
private:
    Vector2f m_Position;
    CircleShape m_Shape;
    float m_Speed = 1000.0f;
    float m_DirectionX = 0.2f;
    float m_DirectionY = 0.2f;

public:
    Ball(float startX, float startY);
    FloatRect getPosition();
    CircleShape getShape();
    void reboundSides();
    void reboundBatOrTop();
    void reboundBottom();
    void update(Time dt);
};

Ball.cpp: Method Implementations

#include "Ball.h"

Ball::Ball(float startX, float startY) {
    m_Position.x = startX;
    m_Position.y = startY;
    m_Shape.setRadius(10);
    m_Shape.setPosition(m_Position);
}

FloatRect Ball::getPosition() {
    return m_Shape.getGlobalBounds();
}

CircleShape Ball::getShape() {
    return m_Shape;
}

void Ball::reboundSides() {
    m_DirectionX = -m_DirectionX;
}

void Ball::reboundBatOrTop() {
    m_DirectionY = -m_DirectionY;
}

void Ball::reboundBottom() {
    m_Position.y = 11; // Reset Y position
    m_Position.x = 500; // Reset X position
}

void Ball::update(Time dt) {
    m_Position.y += m_DirectionY * m_Speed * dt.asSeconds();
    m_Position.x += m_DirectionX * m_Speed * dt.asSeconds();
    m_Shape.setPosition(m_Position);
}

Bat Class Implementation

The Bat class controls the player-controlled paddle, handling its movement and visual representation.

Bat.h: Class Definition

#include <SFML/Graphics.hpp>

using namespace sf;

class Bat {
private:
    Vector2f m_Position;
    RectangleShape m_Shape;
    float m_Speed = 600.0f;
    bool m_MovingLeft = false;
    bool m_MovingRight = false;

public:
    Bat(float startX, float startY);
    FloatRect getPosition();
    RectangleShape getShape();
    void moveLeft();
    void moveRight();
    void stopLeft();
    void stopRight();
    void update(Time dt);
};

Bat.cpp: Method Implementations

#include "Bat.h"

Bat::Bat(float startX, float startY) {
    m_Position.x = startX;
    m_Position.y = startY;
    m_Shape.setSize(sf::Vector2f(50, 5));
    m_Shape.setPosition(m_Position);
}

FloatRect Bat::getPosition() {
    return m_Shape.getGlobalBounds();
}

RectangleShape Bat::getShape() {
    return m_Shape;
}

void Bat::moveLeft() {
    m_MovingLeft = true;
}

void Bat::moveRight() {
    m_MovingRight = true;
}

void Bat::stopLeft() {
    m_MovingLeft = false;
}

void Bat::stopRight() {
    m_MovingRight = false;
}

void Bat::update(Time dt) {
    if (m_MovingLeft) {
        if (m_Position.x > 0) {
            m_Position.x -= m_Speed * dt.asSeconds();
        }
    }
    if (m_MovingRight) {
        if (m_Position.x < 910) { // Window width - bat width (960 - 50 = 910)
            m_Position.x += m_Speed * dt.asSeconds();
        }
    }
    m_Shape.setPosition(m_Position);
}

Pong.cpp: Main Game Logic

This file contains the main function, setting up the SFML window, game objects, event handling, game loop, and rendering.

Main Game Loop and Event Handling

#include <SFML/Graphics.hpp>
#include <sstream>
#include "Bat.h"
#include "Ball.h"

using namespace sf;

int main() {
    VideoMode vm(960, 540);
    RenderWindow window(vm, "Pong Game");

    int score = 0;
    int lives = 3;

    Bat bat(960 / 2, 540 - 20);
    Ball ball(960 / 2, 0);

    Clock clock;
    Text hud;
    Font font;
    font.loadFromFile("font/KOMIKAP_.ttf");
    hud.setFont(font);
    hud.setCharacterSize(30);
    hud.setFillColor(Color::White);
    hud.setPosition(20, 20);

    while (window.isOpen()) {
        Event event1;
        while (window.pollEvent(event1)) {
            if (event1.type == Event::Closed) {
                window.close();
            }
        }

        if (Keyboard::isKeyPressed(Keyboard::Escape)) {
            window.close();
        }

        // Handle bat movement
        if (Keyboard::isKeyPressed(Keyboard::Left)) {
            bat.moveLeft();
        } else {
            bat.stopLeft();
        }

        if (Keyboard::isKeyPressed(Keyboard::Right)) {
            bat.moveRight();
        } else {
            bat.stopRight();
        }

        // Update game objects
        Time dt = clock.restart();
        bat.update(dt);
        ball.update(dt);

        // Update HUD text
        std::stringstream ss;
        ss << "Score " << score << " Lives " << lives;
        hud.setString(ss.str());

        // Handle ball collisions
        // Rebound off sides
        if (ball.getPosition().left < 0 || ball.getPosition().left + ball.getPosition().width > window.getSize().x) {
            ball.reboundSides();
        }

        // Rebound off top
        if (ball.getPosition().top < 0) {
            ball.reboundBatOrTop();
            score++;
        }

        // Ball misses bat (bottom of screen)
        if (ball.getPosition().top > window.getSize().y) {
            ball.reboundBottom();
            lives--;
            if (lives < 1) {
                ss.str(""); // Clear stringstream
                ss << "Game Over!";
                hud.setString(ss.str());
                score = 0;
                lives = 3;
            }
        }

        // Ball hits bat
        if (ball.getPosition().intersects(bat.getPosition())) {
            ball.reboundBatOrTop();
        }

        // Render frame
        window.clear(Color::Black);
        window.draw(hud);
        window.draw(bat.getShape());
        window.draw(ball.getShape());
        window.display();
    }
    return 0;
}