π Three Beats, Forever
INPUT β drain the event queue and read the keyboard. UPDATE β move every object, check every collision, change the game's state. RENDER β wipe the screen and redraw everything from scratch.
That's it. Pong is this loop. Minecraft is this loop with more update. Your capstone game will be this loop too.
π¬ The Event Queue
Pygame collects everything that happens β key presses, mouse clicks, the window's β button β into a queue. pygame.event.get() hands you the list and empties it. If you never drain the queue, the OS thinks your game froze. That's why the event loop comes first, every frame, no exceptions.
πΌ Why Redraw Everything?
Games don't "move" a sprite β they erase the whole screen with screen.fill(...) and repaint every object at its new position, 60 times a second. Your eye does the rest. Skip the fill and every frame smears over the last one β try deleting that line in your own build and watch the ghosting.
β± clock.tick(60) and dt
clock.tick(60) does two jobs: it sleeps just long enough to cap the loop at 60 frames per second, and it returns how many milliseconds the last frame took. Divide by 1000 and you have dt β delta time, the length of one frame in seconds.
Multiply every speed by dt and your game runs at the same real-world speed on a slow Chromebook and a gaming PC. The Frame Rate Lab on this page is exactly that experiment.
π¦ Rects Are Everything
A pygame.Rect is just x, y, width, height β but it gives you .left .right .top .bottom .center for free, and a.colliderect(b) runs the same four AABB comparisons you just dragged around in the lab. Player, enemies, coins, walls, buttons: in Pygame, everything is a Rect until proven otherwise.
π§ Where This Fits
Once you can build this loop from memory, you've earned the fun stuff: sprites and spritesheets, your Breakout clone, and game feel. And when you meet a JavaScript engine in 2D Game Engines or build one raw in From Scratch: Browser Game, you'll recognize the same three beats under different names.