๐Ÿ My First Python Game ยท Episode 1 of 7 ยท See All Episodes
๐ŸŽ Episode 1 ยท Beginner ยท No Experience Needed

Don't Drop It!
Fruit Catch Game

Your first Python game: slide a basket to catch falling fruit, score points, and speed things up until you drop one. You will learn the game loop, keyboard input, random numbers and collision.

๐Ÿ‘ถ Ages 10+ โฑ๏ธ ~1.5 Hours ๐Ÿ Python โœ“ Free
๐Ÿ” Game loop โŒจ๏ธ Keyboard input ๐ŸŽฒ Random numbers ๐Ÿ“ฆ Variables ๐Ÿ’ฅ Collision โฉ Speed scaling
โญ
0 XP
Level 1
๐Ÿ”ฅ0
Your Progress 0 / 6 steps
1
๐Ÿงฐ
Install Python & Pygame
Get the tools, open a window
Active
๐ŸŽฏ
Goal for this step

Install Python and Pygame, and open your first game window.

  • 1Install Python from python.org, tick "Add Python to PATH" during the install!
  • 2Open a terminal and run pip install pygame.
  • 3Create a folder for this game and a file called game.py.
  • 4Type the starter code below and run it with python game.py, a dark window should open and stay open until you close it.
game.py
import pygame
pygame.init()

screen = pygame.display.set_mode((800, 480))
pygame.display.set_caption("My Python Game")
clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((25, 30, 60))
    pygame.display.flip()
    clock.tick(60)          # 60 frames per second

pygame.quit()
๐Ÿ‘จโ€๐Ÿ‘ง
Parent note: Python and Pygame are completely free. If pip is not found, re-run the installer and tick "Add Python to PATH".
โœ๏ธ
Fill in the Blanks
+15 XP
Pygame is installed with the command pip install . The line clock.tick(60) locks the game to frames per second.
๐Ÿง 
Knowledge Check
+15 XP
What does the while running: loop do?
ARuns once and stops
BRepeats ~60 times a second, every frame of the game happens inside it
COnly runs when a key is pressed
2
๐Ÿงบ
The Basket
Draw a basket and slide it with the arrow keys
Locked
๐ŸŽฏ
Goal for this step

Get a basket on screen that glides left and right without leaving the window.

  • 1Above the loop, create the basket as a pygame.Rect, position and size in one object.
  • 2Inside the loop, read held keys with pygame.key.get_pressed().
  • 3Move 7 pixels per frame while an arrow is held, then clamp so it cannot leave the screen.
  • 4Draw it after the fill: pygame.draw.rect(screen, colour, basket).
game.py
basket = pygame.Rect(370, 430, 90, 26)
speed = 7

# inside the while loop, after event handling:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
    basket.x -= speed
if keys[pygame.K_RIGHT]:
    basket.x += speed
basket.x = max(0, min(800 - basket.width, basket.x))

screen.fill((25, 30, 60))
pygame.draw.rect(screen, (255, 119, 0), basket)
pygame.display.flip()
โŒจ๏ธ
Code Challenge
+20 XP
Keep the basket on screen. Fill in the clamp:
game.py
basket.x = (0, (800 - basket.width, basket.x))
๐Ÿ’ก Hint: One function stops it going below 0, the other stops it passing the right edge.
๐Ÿง 
Knowledge Check
+15 XP
Why use pygame.key.get_pressed() instead of KEYDOWN events for movement?
AEvents are broken in Pygame
Bget_pressed reports keys HELD each frame, smooth gliding instead of one step per press
CIt uses less memory
3
๐ŸŽ
Falling Fruit
Spawn fruit at random x positions and let gravity take it
Locked
๐ŸŽฏ
Goal for this step

Make a fruit fall from a random spot at the top, again and again.

  • 1Import random at the top.
  • 2The fruit is another Rect, starting above the screen at a random x.
  • 3Each frame: fruit.y += fall_speed.
  • 4When it falls past the bottom, reset it to the top at a new random x, one fruit object, reused forever.
game.py
import random

fruit = pygame.Rect(random.randint(20, 760), -30, 24, 24)
fall_speed = 4

# inside the loop:
fruit.y += fall_speed
if fruit.y > 480:
    fruit.y = -30
    fruit.x = random.randint(20, 760)

pygame.draw.ellipse(screen, (248, 113, 113), fruit)
๐Ÿ’ก
draw.ellipse in a square Rect gives you a circle, instant apple.
โœ๏ธ
Fill in the Blanks
+15 XP
A random x position comes from random.(20, 760). When the fruit leaves the bottom we reset y to so it re-enters from above the screen.
๐Ÿง 
Knowledge Check
+15 XP
Why reset the same fruit instead of creating a new one each time?
ANew objects are illegal in a loop
BReusing one object is simple and fast, nothing piles up in memory
CRandom only works once per object
4
๐Ÿ’ฅ
Catching & Scoring
Collision detection and an on-screen score
Locked
๐ŸŽฏ
Goal for this step

Catch fruit in the basket to score, and see the score on screen.

  • 1Pygame Rects have collision built in: basket.colliderect(fruit) returns True on overlap.
  • 2On a catch: score += 1 and reset the fruit to the top.
  • 3Render text with a Font object: create it once above the loop, then render + blit each frame.
  • 4Draw the score in the top-left corner.
game.py
score = 0
font = pygame.font.Font(None, 36)

# inside the loop:
if basket.colliderect(fruit):
    score += 1
    fruit.y = -30
    fruit.x = random.randint(20, 760)

text = font.render(f"Score: {score}", True, (255, 255, 255))
screen.blit(text, (16, 12))
โŒจ๏ธ
Code Challenge
+20 XP
Complete the catch check:
game.py
if basket.(fruit):
    score += 
    fruit.y = -30
๐Ÿ’ก Hint: Rect has a method that checks overlap with another rect. Each catch is worth one point.
๐Ÿง 
Knowledge Check
+15 XP
What does basket.colliderect(fruit) return when they touch?
AThe overlap area in pixels
BTrue
CThe fruitโ€™s coordinates
5
โฉ
Lives & Rising Difficulty
Miss three fruit and it is game over, and it gets faster
Locked
๐ŸŽฏ
Goal for this step

Add three lives, and make the fruit fall faster as your score climbs.

  • 1Add lives = 3. A fruit passing the bottom now costs a life before it resets.
  • 2Difficulty: every 5 catches, increase fall_speed by 1, fall_speed = 4 + score // 5.
  • 3The // operator is whole-number division: 12 catches โ†’ 4 + 2 = speed 6.
  • 4Show lives as hearts next to the score.
game.py
lives = 3

# replace the bottom check:
if fruit.y > 480:
    lives -= 1
    fruit.y = -30
    fruit.x = random.randint(20, 760)

fall_speed = 4 + score // 5

hearts = font.render("โค" * lives, True, (248, 113, 113))
screen.blit(hearts, (700, 12))
โœ๏ธ
Fill in the Blanks
+15 XP
Missing a fruit costs one . The speed formula 4 + score // uses whole-number division, so speed rises one point every five catches.
๐Ÿง 
Knowledge Check
+15 XP
With score = 17, what is 4 + score // 5?
A7, because 17 // 5 is 3
B7.4
C21
6
๐Ÿ
Game Over & Restart
Freeze the game at zero lives, press R to play again
Locked
๐ŸŽฏ
Goal for this step

End the game properly with a final score and a restart key.

  • 1Add game_over = False. When lives hits 0, set it True.
  • 2While game_over: skip ALL movement (wrap the update code in if not game_over:) but keep drawing.
  • 3Draw GAME OVER and the final score in big text in the centre.
  • 4Press R to reset: score, lives, speed, fruit position, game_over = False. A full game, done!
game.py
game_over = False
big_font = pygame.font.Font(None, 72)

# in the event loop:
if event.type == pygame.KEYDOWN and event.key == pygame.K_r and game_over:
    score, lives, game_over = 0, 3, False
    fruit.y = -30

# update only while playing:
if not game_over:
    # ... all movement / catching code ...
    if lives == 0:
        game_over = True

if game_over:
    msg = big_font.render("GAME OVER", True, (255, 209, 102))
    screen.blit(msg, (240, 190))
โŒจ๏ธ
Code Challenge
+20 XP
Reset everything when R is pressed after a game over:
game.py
score, lives, game_over = 0, , 
๐Ÿ’ก Hint: Lives go back to the starting three, and the game-over flag switches off so the loop runs again.
๐Ÿง 
Knowledge Check
+15 XP
Why keep drawing while game_over is True but skip updating?
ADrawing is free
BThe player needs to SEE the game-over screen, a frozen picture, not a black window
CPygame crashes if you stop drawing
๐ŸŽ‰๐Ÿ†๐ŸŽฎโœจ๐ŸŽ‰
Workshop Complete!
Game loop, input, random spawning, collision, difficulty, the DNA of every arcade game, written in Python by you. Episode 2: jumping!
0
Total XP
1
Level
0
Best Streak
0%
Accuracy
โ–ถ Episode 2: Simple Platformer โ†’
โญ 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