Hello loyal readers,
I hope you all had a wonderful and relaxing holiday with those you love-I know I sure did. I did promise you all new and exciting programming content in 2024, so let’s get started!
My first post of 2024 (and first several posts of 2024 for that matter) will do something I haven’t done on this blog in its nearly 6-year existence-game development! Yup, that’s right, we’ll learn how to make a simple game using Python’s pygame package. And yes, this game will include graphics (so we’re making something way cooler than a simple text-based blackjack game or something like that).
Let’s begin!
Setting ourselves up
Before we even start to design our game, let’s install the pygame package using the following line either on our IDE or command prompt-pip install pygame.
Next, let’s open our IDE. You could technically use Jupyter notebook to start creating the game, but for something like game creation that utilizes graphics (and likely lots of code) I’d suggest an IDE like Spyder.
Now, where do we begin?
To start, here are the first three lines of code we should include in our script:
import pygame
from pygame.locals import *
import sys
What game will I teach you how to program? Well, in this series of posts, we’ll learn to make our own BINGO clone.
Why BINGO? Well, compared to many other games I could possibly teach you to program, BINGO seemed like a relatively easy first game to learn to develop as it doesn’t involve multiple levels, much scoring, health tracking, or final bosses (though we could certainly explore games that involve these concepts later on).
Let’s start coding!
First off, since we are programming a BINGO game, we’ll need to draw squares. 30 of them, to be precise, as simple BINGO games utilize a 5×5 card along with five squares at the top that contain the letters B, I, N, G, and O.
Seems simple enough to understand right? Let’s see how we code it!
class Square(pygame.sprite.Sprite):
def __init__(self):
super(Square, self).__init__()
self.surf = pygame.Surface((75, 75))
self.surf.fill((50, 205, 50))
self.rect = self.surf.get_rect()
pygame.init()
screen = pygame.display.set_mode((800, 600))
square1 = Square()
First of all, to draw the BINGO squares, we’ll first need to create a Square class and pass in the pygame.sprite.Sprite parameter into it like so-class Square(pygame.sprite.Sprite).
What is the Sprite class in pygame? For those who are familiar with fanatsy works (e.g. Shrek, Lord of the Rings), a sprite is a legendary mythical creature such as a pixie, fairy, or elf (among others). In pygame a sprite simply represents a 2D image or animation that is displayed on the game screen-like the squares we’ll need to draw for our BINGO board.
The next line-the one that begins with super-allows the Square class to inherit all of the methods and capabilites of the Sprite class, which is necessary if you want the squares drawn on the game screen.
The following three lines set the drawing surface (and in turn, the size) of the square, set the color of each square on the gameboard using RGB color coding (yes, you can make the squares different colors, but I’m keeping it simple and coloring all the squares lime green), and get the rectangular area of each square, respectively.
The next two lines initiate the instace of the game-using the line pygame.init()-and set the size of the screen (in pixels). In this case, we’ll use an 800×600 pixel screen.
The last line initiates a square object for us to draw. The interesting thing to note here is that even though we’ll ultimately need to draw 30 squares for our BINGO board, we only need one square object since we can draw that same square object 30 different times in 30 different places.
Even with all this code, we’ll still need to actually draw the squares onto our game screen-this code just ensures that we have the ability to do just that (it doesn’t actually take care of the graphics drawing).
Let’s run the game!
Now that we have created the squares for our BINGO game and imported the necessary packages, let’s figure out how to get our game running! Check out this chunk of code that helps us do just that!
gameOn = True
while gameOn:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_BACKSPACE:
gameOn = False
elif event.type == QUIT:
gameOn = False
First, we have our boolean variable gameOn, which indicates whether or not our game is currently running (True if it is, False if it isn’t).
The while loop that follows is a great example of event handling (I think this is the first time I mention it on this blog), which is the process of what your program should do in various scenarios, or events. This while loop will keep running as long as gameOn is true (in other words, as long as the game is running).
You’ll notice two event types that will shut the game down, KEYDOWN and QUIT. In the case of KEYDOWN, the game will shut down only if the backspace key is pressed. In the case of the QUIT event, the game will quit if the user presses the X close button on the window. However, something to note about the QUIT event is that pressing X alone doesn’t quit the game-I know because I tried using the X button to quit the game and ran into an unresponsive window that I ended up force-quitting. Don’t worry, I’ll explain how to quit the game properly later in this post.
Drawing the squares
Now that we have a means to keep our game running (or close it if we so choose), let’s now draw the squares onto the gameboard. Here’s the code to do so:
screen.blit(square1.surf, (40, 75))
screen.blit(square1.surf, (115, 75))
screen.blit(square1.surf, (180, 75))
screen.blit(square1.surf, (255, 75))
screen.blit(square1.surf, (330, 75))
screen.blit(square1.surf, (40, 150))
screen.blit(square1.surf, (115, 150))
screen.blit(square1.surf, (180, 150))
screen.blit(square1.surf, (255, 150))
screen.blit(square1.surf, (330, 150))
screen.blit(square1.surf, (40, 225))
screen.blit(square1.surf, (115, 225))
screen.blit(square1.surf, (180, 225))
screen.blit(square1.surf, (255, 225))
screen.blit(square1.surf, (330, 225))
screen.blit(square1.surf, (40, 300))
screen.blit(square1.surf, (115, 300))
screen.blit(square1.surf, (180, 300))
screen.blit(square1.surf, (255, 300))
screen.blit(square1.surf, (330, 300))
screen.blit(square1.surf, (40, 375))
screen.blit(square1.surf, (115, 375))
screen.blit(square1.surf, (180, 375))
screen.blit(square1.surf, (255, 375))
screen.blit(square1.surf, (330, 375))
screen.blit(square1.surf, (40, 450))
screen.blit(square1.surf, (115, 450))
screen.blit(square1.surf, (180, 450))
screen.blit(square1.surf, (255, 450))
screen.blit(square1.surf, (330, 450))
pygame.display.flip()
Even though you’ll only need to create one square object, you’ll need to draw that object 30 different times since the BINGO board will consist of 30 squares drawn in a 6×5 matrix. To draw the squares, you’ll need to use the following method-screen.blit(square1.surf, (x-coordinate, y-coordinate). The screen.blit(...) method drawes the squares onto the screen and it takes two parameters-the square1.surf, which is the surface of the square and a two-integer tuple stating the coordinates where you want the square placed (x-coordinate first, then y-coordinate).
After the 30 instances of the screen.blit() method, the pygame.display.flip() method is called, which simply updates the game screen to display the 30 squares. You might’ve thought the screen.blit() method already accomplishes this, but this method simply draws the squares while the pygame.display.flip() method updates the game screen to ensure the squares are present.
Quitting the game
As I mentioned earlier in this post, I’ll show you how to properly quit the game. Here are the two lines of code needed to do so:
pygame.quit()
sys.exit()
To properly end the pygame session, you’ll need to include these two commands in your code. Why do you need them both? Wouldn’t one command or the other work?
You need both commands because the pygame.quit() method simply shuts down the active pygame module while the sys.exit() method proprely shuts down the entire window.
And now, let’s see our work!
Now that we’ve got the basic game outline set up, let’s see our work by running our script!

As you see here, we simply have one giant lime-green square. However, that lime green square consists of the 30 squares we drew earlier-the squares are simply drawn on top of each other, hence why the output looks like one big square. Don’t worry, in the next post we’ll make this square look more like a BINGO board!
A small coding improvement
As you noticed earlier in this post, I was calling the screen.blit() method 30 times while drawing the squares. However, there is a much better way to accomplish this:
x = [40, 115, 180, 255, 330]
y = [75, 150, 225, 300, 375, 450]
for xcoord in x:
for ycoord in y:
screen.blit(square1.surf, (xcoord, ycoord))
In this example, I placed all possible x and y coordinates into arrays and drew each square by looping through the values in both arrays. Here’s the output of this improved approach:
As you see, not only did we improve the process for drawing the squares onto the game screen, but we also got the same result we did when we were calling the screen.blit() method 30 times.
For your reference, the code
Just in case you want it, here’s the code we used for our game development in this post (and we will certainly change it throughout this series of posts). I’m copying the code here since WordPress won’t let me upload .PY files:
import pygame
from pygame.locals import *
import sys
class Square(pygame.sprite.Sprite):
def __init__(self):
super(Square, self).__init__()
self.surf = pygame.Surface((75, 75))
self.surf.fill((50, 205, 50))
self.rect = self.surf.get_rect()
pygame.init()
screen = pygame.display.set_mode((800, 600))
square1 = Square()
gameOn = True
while gameOn:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_BACKSPACE:
gameOn = False
# Check for QUIT event
elif event.type == QUIT:
gameOn = False
x = [40, 115, 180, 255, 330]
y = [75, 150, 225, 300, 375, 450]
for xcoord in x:
for ycoord in y:
screen.blit(square1.surf, (xcoord, ycoord))
# Update the display using flip
pygame.display.flip()
pygame.quit()
sys.exit()
Thanks for reading, and I look forward to having you code along with me in 2024!
Michael