How to Build Your First Python Game
A Step-by-Step Guide to Creating a Simple Shooter with PyGame
Hi lovely readers,
Have you ever wanted to create your own video game? Maybe you’ve thought about building a simple shooter game where you can move around, dodge incoming enemies, and blast away at targets. Well, today’s your lucky day! We’re going to dive into the wonderful world of PyGame, a fantastic Python library that makes game development accessible and fun, even if you’ve only dabbled in Python with basic console applications.
If you already know the basics of Python—things like variables, loops, conditions, and functions—you’re in the perfect spot to start building your own game. Don’t worry if you’ve never used PyGame before; by the end of this post, you’ll have a basic but functional game to show off. So let’s get started!
Why PyGame?
Before we jump into the code, let’s take a moment to talk about why PyGame is such a great tool for building games, especially if you’re a beginner. PyGame is a 2D desktop game library that is:
- Easy to Learn: PyGame is straightforward and beginner-friendly. It abstracts many of the complex parts of game development, letting you focus on building your game.
- Cross-Platform: Games made with PyGame can run on Windows, Mac, and Linux without any changes to your code.
- Active: There’s a large and helpful community of developers using PyGame. You can find tons of tutorials, examples, and forums where you can ask questions and share your projects.
Setting Up Your Environment
Before we start coding, you’ll need to have Python installed on your computer. If you don’t have it yet, head over to python.org and download the latest version. It’s important to have Python set up correctly because it’s the foundation that PyGame runs on.
Next, you need to install PyGame. This is a library that provides the tools you need to create games, like managing windows, drawing shapes, and handling user input. Installing PyGame is easy—just open your terminal (or command prompt if you’re on Windows) and type:
pip install pygame
Once that’s done, you’re ready to start creating your game!
Step 1: Setting Up the Game Window
The first thing we need to do is create a window where the game will run. This window is where all the action will happen, so think of it as the stage for your game. Let’s write the code to set this up.
import pygame
import sys
# Initialize PyGame
pygame.init()
# Set up the game window
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Simple Shooter Game")
# Set the frame rate
clock = pygame.time.Clock()
# Main game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Fill the screen with a color (black in this case)
screen.fill((0, 0, 0))
# Update the display
pygame.display.flip()
# Cap the frame rate at 60 frames per second
clock.tick(60)
Let’s break this down:
Importing Libraries: We start by importing
pygame
andsys
. Thepygame
library is what we’ll use to create the game, whilesys
helps us cleanly exit the program when needed.Initializing PyGame: The line
pygame.init()
is crucial—it sets up all the modules that PyGame needs to run. You should always call this at the beginning of your PyGame projects.Creating the Game Window: We use
pygame.display.set_mode()
to create a window with a width of 800 pixels and a height of 600 pixels. This is where everything in our game will be displayed. Thepygame.display.set_caption()
function lets us set the title of the window to something meaningful, like "Simple Shooter Game".Setting Up the Frame Rate: The
clock = pygame.time.Clock()
line creates a clock object that helps us control how fast the game runs. By setting the frame rate to 60 frames per second, we ensure that the game runs smoothly.Main Game Loop: The
while True
loop is the heart of our game. It keeps running, allowing us to update the game and check for events like closing the window. Inside this loop:- Event Handling: We use
pygame.event.get()
to check if the player wants to quit the game. If they do, we callpygame.quit()
to clean up andsys.exit()
to exit the program. - Drawing the Background: The
screen.fill((0, 0, 0))
line fills the screen with black, essentially clearing it for the next frame. - Updating the Display: Finally,
pygame.display.flip()
updates the window to show whatever we’ve drawn.
- Event Handling: We use
When you run this code, you should see a plain black window. Congratulations! You’ve just set up the foundation of your game.
Step 2: Adding the Player
Now that we have a game window, let’s add something more interesting—a player character. For simplicity, we’ll represent the player as a rectangle that you can move left and right. The enemies will also be represented as rectangles, keeping things simple and focused on the game logic rather than complex graphics
# Player settings
player_width = 50
player_height = 60
player_x = screen_width // 2 - player_width // 2
player_y = screen_height - player_height - 10
player_speed = 5
# Main game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Handle player movement
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_x > 0:
player_x -= player_speed
if keys[pygame.K_RIGHT] and player_x < screen_width - player_width:
player_x += player_speed
# Fill the screen with black
screen.fill((0, 0, 0))
# Draw the player
pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))
# Update the display
pygame.display.flip()
# Cap the frame rate at 60 FPS
clock.tick(60)
Here’s what’s going on:
Player Settings: We define the player’s size (
player_width
andplayer_height
), starting position (player_x
andplayer_y
), and speed (player_speed
). The starting position is calculated so that the player appears centered horizontally near the bottom of the window.Handling Player Movement: Inside the main game loop, we check which keys are pressed using
pygame.key.get_pressed()
. This function returns a list of all keys on the keyboard, with aTrue
value for the keys that are currently pressed. If the left arrow key is pressed, and the player isn’t at the edge of the screen, we move the player to the left by subtractingplayer_speed
fromplayer_x
. Similarly, we move the player to the right if the right arrow key is pressed.Drawing the Player: The
pygame.draw.rect()
function draws a rectangle (our player) on the screen. The parameters are the screen to draw on, the color of the rectangle (a shade of blue in this case), and the rectangle’s position and size.
When you run this code, you’ll see a blue rectangle that you can move left and right using the arrow keys. This rectangle is our player, and it will be the hero of our game.
Step 3: Shooting Bullets
What’s a shooter game without some shooting? Let’s add the ability to fire bullets. We’ll create a bullet each time the player presses the space bar.
# Bullet settings
bullet_width = 5
bullet_height = 10
bullet_speed = 7
bullets = []
# Main game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# Create a bullet at the current player position
bullet_x = player_x + player_width // 2 - bullet_width // 2
bullet_y = player_y
bullets.append(pygame.Rect(bullet_x, bullet_y, bullet_width, bullet_height))
# Handle player movement
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_x > 0:
player_x -= player_speed
if keys[pygame.K_RIGHT] and player_x < screen_width - player_width:
player_x += player_speed
# Update bullet positions
for bullet in bullets:
bullet.y -= bullet_speed
# Remove bullets that are off the screen
bullets = [bullet for bullet in bullets if bullet.y > 0]
# Fill the screen with black
screen.fill((0, 0, 0))
# Draw the player
pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))
# Draw the bullets
for bullet in bullets:
pygame.draw.rect(screen, (255, 255, 255), bullet)
# Update the display
pygame.display.flip()
# Cap the frame rate at 60 FPS
clock.tick(60)
Let’s break this down:
Bullet Settings: We define the bullet’s size (
bullet_width
andbullet_height
), speed (bullet_speed
), and a list (bullets
) to keep track of all active bullets.Firing Bullets: Inside the main loop, we check for a
KEYDOWN
event, which occurs when any key is pressed. If the space bar (pygame.K_SPACE
) is pressed, we create a new bullet at the player’s current position. The bullet’s x-position is calculated to be centered horizontally with the player, and the bullet is then added to thebullets
list.Updating Bullet Positions: Each bullet in the
bullets
list is moved upwards by subtractingbullet_speed
from its y-position. Bullets that move off the top of the screen are removed from the list to save memory.Drawing Bullets: We loop through the
bullets
list and usepygame.draw.rect()
to draw each bullet on the screen.
Now, when you run the game, pressing the space bar will shoot white bullets from the player’s position. The bullets move upward, just like you’d expect in a shooter game.
Step 4: Adding Enemies
Let’s make the game more challenging by adding enemies that the player needs to shoot. We’ll start by creating some enemies that move down the screen toward the player. Again, we’ll keep things simple by representing the enemies as red rectangles.
import random
# Enemy settings
enemy_width = 50
enemy_height = 60
enemy_speed = 2
enemies = []
# Spawn an enemy every 2 seconds
enemy_timer = 0
enemy_spawn_time = 2000
# Main game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bullet_x = player_x + player_width // 2 - bullet_width // 2
bullet_y = player_y
bullets.append(pygame.Rect(bullet_x, bullet_y, bullet_width, bullet_height))
# Handle player movement
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_x > 0:
player_x -= player_speed
if keys[pygame.K_RIGHT] and player_x < screen_width - player_width:
player_x += player_speed
# Update bullet positions
for bullet in bullets:
bullet.y -= bullet_speed
bullets = [bullet for bullet in bullets if bullet.y > 0]
# Update enemy positions and spawn new ones
current_time = pygame.time.get_ticks()
if current_time - enemy_timer > enemy_spawn_time:
enemy_x = random.randint(0, screen_width - enemy_width)
enemy_y = -enemy_height
enemies.append(pygame.Rect(enemy_x, enemy_y, enemy_width, enemy_height))
enemy_timer = current_time
for enemy in enemies:
enemy.y += enemy_speed
# Remove enemies that are off the screen
enemies = [enemy for enemy in enemies if enemy.y < screen_height]
# Fill the screen with black
screen.fill((0, 0, 0))
# Draw the player
pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))
# Draw the bullets
for bullet in bullets:
pygame.draw.rect(screen, (255, 255, 255), bullet)
# Draw the enemies
for enemy in enemies:
pygame.draw.rect(screen, (255, 0, 0), enemy)
# Update the display
pygame.display.flip()
# Cap the frame rate at 60 FPS
clock.tick(60)
Here’s how we’ve added enemies:
Enemy Settings: We define the size (
enemy_width
andenemy_height
), speed (enemy_speed
), and a list (enemies
) to track all active enemies.Spawning Enemies: We use a timer to spawn a new enemy every 2 seconds. The current time is tracked with
pygame.time.get_ticks()
. If enough time has passed since the last enemy was spawned, we create a new enemy at a random horizontal position above the screen (so it moves downward). This enemy is then added to theenemies
list.Updating Enemy Positions: Each enemy in the
enemies
list moves downward by addingenemy_speed
to its y-position. If an enemy moves off the bottom of the screen, it’s removed from the list.Drawing Enemies: We loop through the
enemies
list and usepygame.draw.rect()
to draw each enemy on the screen.
When you run this code, you’ll see red rectangles (our enemies) falling from the top of the screen. The game is starting to take shape!
Step 5: Detecting Collisions
Now, let’s add some logic so that when a bullet hits an enemy, both the bullet and the enemy disappear. This involves detecting collisions between bullets and enemies.
# Collision detection function
def check_collision(rect1, rect2):
return rect1.colliderect(rect2)
# Main game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bullet_x = player_x + player_width // 2 - bullet_width // 2
bullet_y = player_y
bullets.append(pygame.Rect(bullet_x, bullet_y, bullet_width, bullet_height))
# Handle player movement
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_x > 0:
player_x -= player_speed
if keys[pygame.K_RIGHT] and player_x < screen_width - player_width:
player_x += player_speed
# Update bullet positions
for bullet in bullets:
bullet.y -= bullet_speed
bullets = [bullet for bullet in bullets if bullet.y > 0]
# Update enemy positions and spawn new ones
current_time = pygame.time.get_ticks()
if current_time - enemy_timer > enemy_spawn_time:
enemy_x = random.randint(0, screen_width - enemy_width)
enemy_y = -enemy_height
enemies.append(pygame.Rect(enemy_x, enemy_y, enemy_width, enemy_height))
enemy_timer = current_time
for enemy in enemies:
enemy.y += enemy_speed
# Check for collisions
for bullet in bullets[:]:
for enemy in enemies[:]:
if check_collision(bullet, enemy):
bullets.remove(bullet)
enemies.remove(enemy)
break
# Remove enemies that are off the screen
enemies = [enemy for enemy in enemies if enemy.y < screen_height]
# Fill the screen with black
screen.fill((0, 0, 0))
# Draw the player
pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))
# Draw the bullets
for bullet in bullets:
pygame.draw.rect(screen, (255, 255, 255), bullet)
# Draw the enemies
for enemy in enemies:
pygame.draw.rect(screen, (255, 0, 0), enemy)
# Update the display
pygame.display.flip()
# Cap the frame rate at 60 FPS
clock.tick(60)
Here’s what we did:
Collision Detection: We define a function
check_collision
that takes the positions and sizes of two rectangles and checks if they overlap usingcolliderect()
. This is how we detect if a bullet has hit an enemy.Removing Colliding Objects: Inside the main loop, after updating the positions of the bullets and enemies, we check if any bullet has collided with any enemy. If they have, both the bullet and the enemy are removed from their respective lists.
Now, when you run the game, bullets that hit enemies will make the enemies disappear. You’ve created a basic but functioning shooter game!
Important Note: In this simple game, there is no penalty for colliding with an enemy. The player can move through enemies without taking damage or losing the game. This keeps things straightforward but might be something you want to change in a more advanced version.
Putting it all together
In case you need it, here's everything we wrote:
import pygame
import sys
import random
# Initialize PyGame
pygame.init()
# Set up the game window
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Simple Shooter Game")
# Set the frame rate
clock = pygame.time.Clock()
# Player settings
player_width = 50
player_height = 60
player_x = screen_width // 2 - player_width // 2
player_y = screen_height - player_height - 10
player_speed = 5
# Bullet settings
bullet_width = 5
bullet_height = 10
bullet_speed = 7
bullets = []
# Enemy settings
enemy_width = 50
enemy_height = 60
enemy_speed = 2
enemies = []
# Spawn an enemy every 2 seconds
enemy_timer = 0
enemy_spawn_time = 2000
# Collision detection function
def check_collision(rect1, rect2):
return pygame.Rect(rect1).colliderect(pygame.Rect(rect2))
# Main game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# Create a bullet at the current player position
bullet_x = player_x + player_width // 2 - bullet_width // 2
bullet_y = player_y
bullets.append([bullet_x, bullet_y])
# Handle player movement
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_x > 0:
player_x -= player_speed
if keys[pygame.K_RIGHT] and player_x < screen_width - player_width:
player_x += player_speed
# Update bullet positions
for bullet in bullets:
bullet[1] -= bullet_speed
bullets = [bullet for bullet in bullets if bullet[1] > 0]
# Update enemy positions and spawn new ones
current_time = pygame.time.get_ticks()
if current_time - enemy_timer > enemy_spawn_time:
enemy_x = random.randint(0, screen_width - enemy_width)
enemy_y = -enemy_height
enemies.append([enemy_x, enemy_y])
enemy_timer = current_time
for enemy in enemies:
enemy[1] += enemy_speed
# Check for collisions
for bullet in bullets[:]:
for enemy in enemies[:]:
if check_collision((bullet[0], bullet[1], bullet_width, bullet_height),
(enemy[0], enemy[1], enemy_width, enemy_height)):
bullets.remove(bullet)
enemies.remove(enemy)
break
# Remove enemies that are off the screen
enemies = [enemy for enemy in enemies if enemy[1] < screen_height]
# Fill the screen with black
screen.fill((0, 0, 0))
# Draw the player
pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))
# Draw the bullets
for bullet in bullets:
pygame.draw.rect(screen, (255, 255, 255), (bullet[0], bullet[1], bullet_width, bullet_height))
# Draw the enemies
for enemy in enemies:
pygame.draw.rect(screen, (255, 0, 0), (enemy[0], enemy[1], enemy_width, enemy_height))
# Update the display
pygame.display.flip()
# Cap the frame rate at 60 FPS
clock.tick(60)
And with all this code together your game should like something like this, where you are the blue block and the enemies are the red blocks:
What's Next?
Congratulations, you’ve just built your first simple shooter game with PyGame! But this is just the beginning—there’s so much more you can do:
- Add a Scoring System: Track how many enemies the player destroys and display the score on the screen.
- Create Different Enemy Types: Make enemies that move differently, shoot back, or take multiple hits to destroy.
- Enhance Graphics: Replace the rectangles with images for the player, bullets, and enemies.
- Add Sound Effects: Make the game more immersive by adding sounds for shooting, hitting enemies, and other actions.
- Introduce Levels: Add different levels or waves of enemies to increase the difficulty as the player progresses.
- Add Player Health and Damage: Allow the player to take damage when colliding with an enemy and lose the game if their health reaches zero.
PyGame is incredibly flexible, so let your imagination run wild and keep experimenting. The more you play with the code, the more you’ll learn and the better your game will become.
It's a wrap!
And that’s it! You’ve gone from an empty window to a functioning shooter game in just a few steps. Whether you’re planning to expand this project or move on to something new, you’ve taken a big step in your game development journey. Don’t hesitate to share your progress or ask questions—I'm here to help!
Do you have any questions or comments? Be sure to leave them here or contact me at @lovelacecoding on most social media platforms. Thanks for coding along!