Breakout rebuilt the C++ way: a Brick class, std::vector, constructors, and collision that knows which side it hit. Your third Breakout, but your first with real object-oriented C++.
๐ถ Ages 12+โฑ๏ธ ~2 Hoursโ๏ธ C++ & SFMLโ Free
๐๏ธ C++ classes๐ std::vector๐งฑ Brick objects๐ฅ Side detectionโค๏ธ Lives๐ Win state
The rebound spin is the offset between ball centre and paddle centre times , clamped to ยฑ px/sec.
๐ง
Knowledge Check
+15 XP
The ball uses px/second velocities while Snake used grid ticks. When do you pick each?
ATicks are always better
BContinuous motion โ dt velocities; cell-based games โ grid ticks. Match the technique to the game
Cdt is only for C++
4
๐ฅ
Smart Brick Collision
Detect WHICH side you hit for correct bounces
Locked
๐ฏ
Goal for this step
Bounce correctly off brick sides, not just up/down.
1Naive Breakout always flips bvy, hitting a brickโs SIDE then looks wrong. We compare overlap depths.
2On intersect, compute horizontal and vertical overlap; the SMALLER overlap is the entry side.
3Shallow horizontal overlap โ side hit โ flip bvx. Otherwise flip bvy.
4Mark the brick dead, add points, break out of the loop.
breakout.cpp
for (auto& brick : bricks) {
if (!brick.alive) continue;
sf::FloatRect bb = ball.getGlobalBounds();
sf::FloatRect kb = brick.shape.getGlobalBounds();
if (bb.intersects(kb)) {
float overlapX = std::min(bb.left + bb.width, kb.left + kb.width)
- std::max(bb.left, kb.left);
float overlapY = std::min(bb.top + bb.height, kb.top + kb.height)
- std::max(bb.top, kb.top);
if (overlapX < overlapY) bvx = -bvx; // side hit
else bvy = -bvy; // top/bottom hit
brick.alive = false;
score += brick.points;
break;
}
}
๐ก
Overlap-depth side detection is the same technique 2D engines use under the hood. You just wrote engine code.
โจ๏ธ
Code Challenge
+20 XP
Bounce off the correct side:
breakout.cpp
if (overlapX < overlapY) = -bvx; // came in from the side
else = -bvy;
brick.alive = ;
๐ก Hint: A shallow horizontal overlap means a side entry, flipping horizontal velocity. The brick then stops existing.
๐ง
Knowledge Check
+15 XP
The smaller overlap tells you the entry side becauseโฆ
ASmall numbers are sides
BThe ball has barely penetrated on the axis it entered from, depth of penetration reveals direction of travel
CSFML sorts overlaps
5
๐งน
Alive Flags vs Erasing
Two cleanup strategies and the erase-remove idiom
Locked
๐ฏ
Goal for this step
Skip dead bricks efficiently and learn the famous C++ idiom.
1We used alive = false and skip dead bricks when drawing/colliding, simple and fast for a fixed wall.
2The alternative is really deleting: the erase-remove idiom, worth knowing because ALL serious C++ uses it.
3Win check with the flag approach: std::none_of over the vector asking if any brick is alive.
4Draw only living bricks.
breakout.cpp
#include <algorithm>
// erase-remove (the famous idiom, for reference):
bricks.erase(
std::remove_if(bricks.begin(), bricks.end(),
[](const Brick& b){ return !b.alive; }),
bricks.end());
// win check with flags:
bool won = std::none_of(bricks.begin(), bricks.end(),
[](const Brick& b){ return b.alive; });
โ๏ธ
Fill in the Blanks
+15 XP
The famous C++ deletion pattern is the erase- idiom. Our simpler approach keeps bricks but marks them with an flag.
๐ง
Knowledge Check
+15 XP
Why can we get away with alive-flags here instead of erasing?
AErasing is illegal on vectors
BThe wall is small and fixed (50 bricks), skipping dead ones costs nothing. Erasing matters when lists grow unbounded
CFlags draw faster
6
โค๏ธ
Lives, Loss & Victory
The complete game loop with all three endings
Locked
๐ฏ
Goal for this step
Finish with lives, a losing screen, a winning screen, and restart.
1Ball past y 520: life lost, re-serve from centre; 0 lives โ LOSE state.
2All bricks dead โ WIN state.
3Freeze physics in end states; draw the message + final score; R rebuilds the wall (clear the vector, refill with the nested loops) and resets everything.
4Three languages, three Breakouts, three times faster each time. THAT is learning to program.
breakout.cpp
int lives = 3;
enum State { PLAY, WIN, LOSE };
State state = PLAY;
if (p.y > 520) {
lives--;
ball.setPosition(343, 300);
bvx = 260; bvy = -260;
if (lives == 0) state = LOSE;
}
if (won) state = WIN;
// restart on R:
bricks.clear();
for (int r = 0; r < 5; r++)
for (int c = 0; c < 10; c++)
bricks.emplace_back(r, c);
lives = 3; score = 0; state = PLAY;
โจ๏ธ
Code Challenge
+20 XP
Use a proper C++ enum for the game state:
breakout.cpp
enum State { PLAY, , LOSE };
State state = ;
if (lives == 0) state = ;
๐ก Hint: Three named states; the game starts in play mode; zero lives means the losing state.
๐ง
Knowledge Check
+15 XP
An enum beats a String state (like Java Ep 4 used) becauseโฆ
AEnums are colourful
BThe compiler catches typos, sate = PLYA will not compile, while "PLYA" would silently break a string version
CEnums are required by SFML
๐๐๐ฎโจ๐
Workshop Complete!
Classes, vectors, erase-remove, Breakout in proper object-oriented C++. Episode 4 brings gravity: the platformer!