๐Ÿ My First Python Game ยท Episode 5 of 7 ยท See All Episodes
๐Ÿงฑ Episode 5 ยท Improver ยท Arcade Classic

Brick Storm!
Breakout

Paddle, ball, wall of bricks, the 1976 classic in Pygame. Bounce physics, paddle spin, rows of bricks from nested loops, lives and a win state. Part 2 next episode adds power-ups!

๐Ÿ‘ถ Ages 10+ โฑ๏ธ ~1.5 Hours ๐Ÿ Python โœ“ Free
๐Ÿ“ Paddle โšช Bounce physics ๐Ÿงฑ Brick grid ๐ŸŽฏ Paddle spin โค๏ธ Lives ๐Ÿ† Win state
โญ
0 XP
Level 1
๐Ÿ”ฅ0
Your Progress 0 / 6 steps
1
๐Ÿ“
Setup & Paddle
Template plus a clamped paddle
Active
๐ŸŽฏ
Goal for this step

Fresh project with a smooth, clamped paddle at the bottom.

  • 1New game.py, 700ร—520 window, the usual template.
  • 2Paddle Rect: 110ร—14 at the bottom, arrows move ยฑ8, clamped.
  • 3This is the third time you have built "move a thing with arrows", notice it now takes you two minutes. That is skill.
game.py
paddle = pygame.Rect(295, 480, 110, 14)

keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
    paddle.x -= 8
if keys[pygame.K_RIGHT]:
    paddle.x += 8
paddle.x = max(0, min(700 - paddle.width, paddle.x))
โœ๏ธ
Fill in the Blanks
+15 XP
The paddle is clamped between 0 and 700 minus its . Held-key movement uses pygame.key.().
๐Ÿง 
Knowledge Check
+15 XP
You have now written the arrow-move-and-clamp pattern three times. What is the lesson?
AProgramming is repetitive and boring
BCore patterns repeat across games, mastering a few building blocks unlocks many games
CPygame has no better way
2
โšช
The Ball
Velocity vector, wall bounces
Locked
๐ŸŽฏ
Goal for this step

A ball that moves diagonally and bounces off three walls.

  • 1Ball Rect (14ร—14) plus velocity bvx, bvy = 4, -4.
  • 2Each frame add velocity; left/right walls flip bvx, ceiling flips bvy.
  • 3The floor does NOT bounce, falling past it will cost a life later.
  • 4Draw it white with draw.ellipse.
game.py
ball = pygame.Rect(340, 300, 14, 14)
bvx, bvy = 4, -4

ball.x += bvx
ball.y += bvy
if ball.left <= 0 or ball.right >= 700:
    bvx = -bvx
if ball.top <= 0:
    bvy = -bvy
โŒจ๏ธ
Code Challenge
+20 XP
Bounce off the three solid walls:
game.py
if ball.left <= 0 or ball.right >= :
    bvx = 
if ball.top <= 0:
    bvy = 
๐Ÿ’ก Hint: The right wall is the window width. Bouncing negates the matching velocity component.
๐Ÿง 
Knowledge Check
+15 XP
Why does the bottom edge NOT bounce the ball?
APygame cannot detect it
BLosing the ball past the paddle is the core challenge, bounce it and the game has no stakes
CThe paddle blocks the check
3
๐ŸŽฏ
Paddle Spin
Where the ball lands on the paddle steers the rebound
Locked
๐ŸŽฏ
Goal for this step

Rebound off the paddle with player-controlled angle.

  • 1On paddle collision (while moving down), flip bvy.
  • 2Then the spin: offset = ball centre โˆ’ paddle centre; bvx = offset // 12.
  • 3Catch on the left edge โ†’ sharp left shot; centre โ†’ straight up. YOU aim every rebound.
  • 4Never allow bvx = 0 (a perfectly vertical ball is a softlock), nudge it to 1.
game.py
if ball.colliderect(paddle) and bvy > 0:
    bvy = -bvy
    offset = ball.centerx - paddle.centerx
    bvx = offset // 12
    if bvx == 0:
        bvx = 1
โœ๏ธ
Fill in the Blanks
+15 XP
The rebound angle comes from the offset between the two values divided by 12. A bvx of exactly must be avoided or the ball bounces straight up forever.
๐Ÿง 
Knowledge Check
+15 XP
Paddle spin turns Breakout from luck into skill becauseโ€ฆ
AThe ball moves faster
BThe player chooses each rebound angle by where they catch the ball, aiming becomes the core skill
CBricks become softer
4
๐Ÿงฑ
The Brick Wall
Nested loops build a colour-banded wall of Rects
Locked
๐ŸŽฏ
Goal for this step

Generate 5 rows ร— 10 columns of bricks with row colours.

  • 1Bricks are a list of dicts: {"rect": Rect, "row": r} built by nested loops before the game loop.
  • 2Each brick 64ร—22 with small gaps: x = col*68 + 12, y = row*26 + 50.
  • 3Colour by row from a list of 5 colours.
  • 4Run it, a proper arcade wall.
game.py
colours = [(248,113,113),(251,146,60),(250,204,21),(74,222,128),(96,165,250)]
bricks = []
for row in range(5):
    for col in range(10):
        bricks.append({
            "rect": pygame.Rect(col*68 + 12, row*26 + 50, 64, 22),
            "row": row
        })

for b in bricks:
    pygame.draw.rect(screen, colours[b["row"]], b["rect"])
โŒจ๏ธ
Code Challenge
+20 XP
Build the full wall with nested loops:
game.py
for row in range():
    for col in range():
        bricks.append({"rect": pygame.Rect(col* + 12, row*26 + 50, 64, 22), "row": row})
๐Ÿ’ก Hint: 5 rows, 10 columns; each column steps 68 px across (64 brick + 4 gap).
๐Ÿง 
Knowledge Check
+15 XP
Why 68 in col*68 when bricks are 64 wide?
AA typo
BThe extra 4 px is the gap between bricks, spacing is part of the step
CPygame adds borders
5
๐Ÿ’ฅ
Smashing & Scoring
Ball destroys bricks; higher rows pay more
Locked
๐ŸŽฏ
Goal for this step

Destroy bricks on contact with a satisfying bounce and scaled score.

  • 1Loop bricks (copy!), on colliderect: remove, bounce (bvy = -bvy), score, and break.
  • 2The break means one brick per frame, no laser-drilling a whole column.
  • 3Score by depth: score += (5 - b["row"]) * 10, top rows are worth 50.
  • 4Draw the score.
game.py
score = 0

for b in bricks[:]:
    if ball.colliderect(b["rect"]):
        bricks.remove(b)
        score += (5 - b["row"]) * 10
        bvy = -bvy
        break
โœ๏ธ
Fill in the Blanks
+15 XP
After removing a hit brick we flip and use so only one brick dies per frame. Row 0 bricks are worth points.
๐Ÿง 
Knowledge Check
+15 XP
What goes wrong WITHOUT the break?
ANothing, it is just faster
BOne pass can delete several overlapping bricks and double-flip bvy, so the ball drills through the wall
CPython raises an error
6
โค๏ธ
Lives, Loss & Victory
Three lives, serve after a drop, win when the wall is gone
Locked
๐ŸŽฏ
Goal for this step

Finish the game: lives, game over, and the you-cleared-it screen.

  • 1Ball past the bottom: lives -= 1, recentre the ball and serve again; at 0 โ†’ game over.
  • 2Victory when len(bricks) == 0.
  • 3Freeze updates in either end state, draw the message, R to fully reset (rebuild the brick list with the same nested loops, make it a function!).
  • 4SAVE THIS FILE, Episode 6 builds power-ups directly on top of it.
game.py
lives = 3
state = "PLAY"

if ball.top > 520:
    lives -= 1
    ball.center = (350, 300)
    bvx, bvy = 4, -4
    if lives == 0:
        state = "LOSE"

if len(bricks) == 0:
    state = "WIN"
โŒจ๏ธ
Code Challenge
+20 XP
Handle the dropped ball:
game.py
if ball.top > 520:
    lives -= 1
    ball. = (350, 300)
    if lives == :
        state = 
๐Ÿ’ก Hint: Rects can be repositioned by their centre point. Zero lives ends the game with the losing state.
๐Ÿง 
Knowledge Check
+15 XP
The win check is len(bricks) == 0. Why does this work?
Abricks is a boolean
BDestroyed bricks are removed from the list, so an empty list literally means the wall is gone
Clen counts the ball too
๐ŸŽ‰๐Ÿ†๐ŸŽฎโœจ๐ŸŽ‰
Workshop Complete!
The arcade classic rebuilt in Python. Keep your code safe, Episode 6 upgrades THIS game with power-ups, multi-ball and levels!
0
Total XP
1
Level
0
Best Streak
0%
Accuracy
โ–ถ Episode 6: Breakout Part 2 โ†’
โญ View My Progress & Certificates

This workshop was free and took many hours to build. If it helped you learn something new, consider supporting the project.

☕ Support on Ko-fi