DEV Community

Cover image for Arkanoid: Building a Classic Arcade Game in C++ with SFML
Mr Punk da Silva
Mr Punk da Silva

Posted on • Edited on

Arkanoid: Building a Classic Arcade Game in C++ with SFML

Repository: Click here

This comprehensive tutorial demonstrates how to build the classic Arkanoid game from scratch using C++ and SFML. We'll progress from fundamental concepts to advanced implementations, with clear explanations at each stage.

Game Concept

Arkanoid is a breakout-style game where players control a paddle at the bottom of the screen, bouncing a ball to destroy colourful brick formations above. Think of it as single-player tennis with destructible targets:

  • A physics-driven ball ricochets around the play area
  • Player-controlled paddle moves horizontally
  • Balls must be kept in play
  • Brick destruction earns points
  • Objective: Clear all bricks without losing the ball

This project teaches essential game development concepts including collision physics, object-oriented programming, and state management.

Architectural Design

Game State Management

Arkanoid requires more sophisticated state handling than simpler games:

stateDiagram-v2 [*] --> MENU MENU --> PLAYING: Space PLAYING --> PAUSED: P PAUSED --> PLAYING: P PLAYING --> GAME_OVER: No lives PLAYING --> VICTORY: All bricks GAME_OVER --> MENU: R VICTORY --> MENU: R 
Enter fullscreen mode Exit fullscreen mode

Implementation using an enumeration:

enum GameState { MENU, // Title screen PLAYING, // Active gameplay PAUSED, // Paused session GAME_OVER, // Failed condition VICTORY // Success condition }; 
Enter fullscreen mode Exit fullscreen mode

Object-Oriented Structure

Key game elements are implemented as distinct classes:

Brick Class Implementation

class Brick { public: sf::Sprite visual; // Graphical representation bool destroyed; // Destruction state int pointValue; // Scoring worth Brick() : destroyed(false), pointValue(10) {} // Constructor void destroy() { destroyed = true; } // Mark as destroyed sf::FloatRect getBounds() const; // Collision area void render(sf::RenderWindow& window); // Drawing method }; 
Enter fullscreen mode Exit fullscreen mode

Design Rationale:

  • Encapsulates brick-specific properties
  • Enables efficient management of multiple bricks
  • Promotes code organisation and reusability

Ball Physics Implementation

class Ball { public: sf::Sprite visual; // Graphical representation sf::Vector2f velocity; // Movement vector float baseSpeed; // Movement scalar void update(float deltaTime, const sf::Vector2u& windowSize); // Position update void invertX() { velocity.x = -velocity.x; } // Horizontal bounce void invertY() { velocity.y = -velocity.y; } // Vertical bounce bool isOOB(const sf::Vector2u& windowSize) const; // Boundary check }; 
Enter fullscreen mode Exit fullscreen mode

Core Game Mechanics

Ball Physics System

The ball follows simplified physics with collision responses:

flowchart TD A[Frame Start] --> B[Position Update] B --> C[Boundary Check] C --> D{Collision?} D -->|Yes| E[Velocity Inversion] D -->|No| F[Paddle Check] F --> G{Collision?} G -->|Yes| H[Angled Rebound] G -->|No| I[Brick Check] I --> J{Collision?} J -->|Yes| K[Brick Destruction] J -->|No| A 
Enter fullscreen mode Exit fullscreen mode

Movement Implementation

void Ball::update(float deltaTime, const sf::Vector2u& windowSize) { sf::Vector2f position = getPosition(); position += velocity * deltaTime; // Boundary collision handling if (position.x <= 0 || position.x + getBounds().width >= windowSize.x) { invertX(); } if (position.y <= 0) { invertY(); } visual.setPosition(position); } 
Enter fullscreen mode Exit fullscreen mode

DeltaTime Explanation:

  • Represents time since last frame
  • Ensures consistent movement speed across hardware
  • At 60 FPS, deltaTime ≈ 0.0167 seconds

Intelligent Paddle Control

The paddle features responsive yet constrained movement:

void Paddle::update(float deltaTime, const sf::Vector2u& windowSize) { sf::Vector2f position = getPosition(); if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) { position.x -= speed * deltaTime; } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) { position.x += speed * deltaTime; } // Screen boundary enforcement position.x = std::clamp(position.x, 0.0f, windowSize.x - getBounds().width); visual.setPosition(position); } 
Enter fullscreen mode Exit fullscreen mode

Advanced Paddle Rebounds

The ball's rebound angle varies based on impact position:

if (ball.getBounds().intersects(paddle.getBounds())) { ball.invertY(); float ballCenterX = ball.getPosition().x + ball.getBounds().width/2; float paddleCenterX = paddle.getPosition().x + paddle.getBounds().width/2; float offset = (ballCenterX - paddleCenterX) / (paddle.getBounds().width/2); ball.velocity.x = ball.baseSpeed * offset * 0.75f; ball.velocity.y = -std::abs(ball.velocity.y); } 
Enter fullscreen mode Exit fullscreen mode

World Building Systems

Procedural Brick Generation

The game creates organised brick formations:

void generateBricks() { bricks.clear(); const int rows = 8, cols = 10; const float brickWidth = 60, brickHeight = 25; const float padding = 5; const float startX = (800 - (cols * brickWidth + (cols-1)*padding))/2; const float startY = 50; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { Brick brick; brick.setPosition(startX + col*(brickWidth+padding), startY + row*(brickHeight+padding)); brick.pointValue = (rows - row) * 10; brick.visual.setColor(rowColors[row % rowColors.size()]); bricks.push_back(brick); } } } 
Enter fullscreen mode Exit fullscreen mode

Lives and Progression Systems

// Ball loss handling if (ball.isOOB(window.getSize())) { lives--; if (lives <= 0) gameState = GAME_OVER; else ball.reset(400, 300); } // Level completion if (std::all_of(bricks.begin(), bricks.end(), [](const Brick& b){ return b.destroyed; })) { level++; score += 1000 * level; if (level <= 3) { generateBricks(); ball.increaseSpeed(50); } else { gameState = VICTORY; } } 
Enter fullscreen mode Exit fullscreen mode

Key Development Insights

This project demonstrates:

  1. OOP Principles: Encapsulation, modular design
  2. Game Physics: Collision detection, movement systems
  3. State Management: Complex game flow control
  4. Procedural Generation: Dynamic content creation
  5. Performance Optimization: Time-based movement
  6. UX Design: Player feedback systems

The complete implementation showcases how classic arcade games combine simple concepts into engaging experiences while teaching fundamental programming techniques.

Top comments (0)