
Last Updated on 16 April 2025

Do you love playing the classic Space Shooter Game? What if we build our own? In this tutorial, we will create a Space Shooter Game using Python and the popular Pygame library. Whether you’re a beginner or an experienced programmer, this article will help you understand game mechanics, object-oriented programming (OOP), and most importantly how to structure a complete Python Project.
By the end of this tutorial, you will have a fully functional game with:
- Player spaceship controls (movement & shooting)
- Enemy waves with increasing difficulty
- Collision detection & scoring system
- Sound effects & visual feedback
- A beautiful User Interface with health bars and wave tracking
So, let’s start!
Visit Also: Learn How to Create a Game in Python with PyGame
What will we create?




Set up Your Space
Before we start make sure the following are installed on your system:
- Python 3.8+
- PyGame library:
pip install pygame - A code editor (Recommended: VS Code, PyCharm, or IDLE)
Get more information about Pygame library from here.
Download the resources
Want hassle-free game creation? Download the assets for this Space Shooter game using the Download button:
Now create a folder named SpaceShooter with these files:
SpaceShooter/ │── assets/ │ ├── player.png │ ├── enemy.png | ├── alien.png │ ├── bullet.png │ ├── background.png │ ├── shoot.wav │ ├── explosion.wav │ └── background.mp3 │── main.py
Source Code
Choose the complete project directory in your code editor and open the main.py program file. Now start writing the code step-by-step.
Import Modules
Let’s import the necessary modules and initialize pygame in our program:
import pygame import random import sys import os from pygame import mixer # Initialize pygame pygame.init() mixer.init()
Game Settings
Next declare some basic settings, for example: window size, FPS, player, enemy, bullet speed, star count, colors, etc.
WIDTH, HEIGHT = 800, 600 FPS = 60 PLAYER_SPEED = 7 ENEMY_SPEED = 2 BULLET_SPEED = 10 STAR_COUNT = 100 # Colors WHITE = (255, 255, 255) BLACK = (0, 0, 0) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) YELLOW = (255, 255, 0)
The Player
Now create the main character of our game which is our hero Spaceship. We can control left and right and shoot bullets with it.
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
try:
# Try to load player image
self.image = pygame.image.load(os.path.join('assets', 'player.png')).convert_alpha()
self.image = pygame.transform.scale(self.image, (50, 40))
except:
# If image not found, a blank image canvas will create
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect(center=(WIDTH//2, HEIGHT-50))
self.speed = PLAYER_SPEED
self.health = 100
self.max_health = 100
self.shoot_delay = 250 # milliseconds
self.last_shot = pygame.time.get_ticks()
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and self.rect.left > 0:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT] and self.rect.right < WIDTH:
self.rect.x += self.speed
def shoot(self):
now = pygame.time.get_ticks()
if now - self.last_shot > self.shoot_delay:
self.last_shot = now
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
shoot_sound.play()
In the above code, we declared all the functionalities of the player spaceship. Here, we loaded our custom-made spaceship image named “player.png.” If the image fails to load, it will create a blank green canvas in place of the spaceship and work the same way.
The Enemies
Now, we will add our enemy spaceships that move downward at random speeds.
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
try:
# Try to load enemy image
self.image = pygame.image.load(os.path.join('assets', 'enemy.png')).convert_alpha()
self.image = pygame.transform.scale(self.image, (40, 40))
except:
# If image not found, a blank image canvas will create
self.image = pygame.Surface((40, 40))
self.image.fill(RED)
self.rect = self.image.get_rect(center=(x, y))
self.speed = random.randint(1, 3)
self.health = 30
def update(self):
self.rect.y += self.speed
if self.rect.top > HEIGHT:
self.kill()
In the above code, we declared all the functionalities of enemy spaceships. These enemy spaceships are destroyed by player bullets and automatically removed when off-screen.
Here, we loaded our custom-made enemy spaceship image named “enemy.png.” If the image fails to load, it will create a red square canvas in place of the enemy spaceship and work the same.
The bullets
Implement Bullet class to add the bullets to our space shooter game.
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
try:
# Try to load bullet image
self.image = pygame.image.load(os.path.join('assets', 'bullet.png')).convert_alpha()
self.image = pygame.transform.scale(self.image, (5, 15))
except:
# If image not found, a blank image canvas will create
self.image = pygame.Surface((5, 15))
self.image.fill(BLUE)
self.rect = self.image.get_rect(center=(x, y))
self.speed = BULLET_SPEED
def update(self):
self.rect.y -= self.speed
if self.rect.bottom < 0:
self.kill()
Same as the previous one – we added an image “bullet.png” here and resized it to a suitable size. Pressing the SPACE button will shoot bullets from the top of our player spaceship while playing.
Star Animation
Let’s create a star animation for our space shooter game. If you don’t place the background image in the assets folder, this animation will play in the background. By the way, this animation also gives an exciting experience for this game.
class Star:
def __init__(self):
self.x = random.randint(0, WIDTH)
self.y = random.randint(0, HEIGHT)
self.speed = random.randint(1, 3)
self.size = random.randint(1, 3)
def update(self):
self.y += self.speed
if self.y > HEIGHT:
self.y = 0
self.x = random.randint(0, WIDTH)
def draw(self, screen):
pygame.draw.circle(screen, WHITE, (self.x, self.y), self.size)
The above code creates a black screen and drops random stars of different sizes with different speeds, from the top.
Enemy Waves
This is the most interesting part of our space shooter game. Here we will create a class named EnemyWave that will manage spawning enemies in controlled waves with progressive difficulty.
class EnemyWave:
def __init__(self):
self.wave_number = 0
self.enemies_in_wave = 5
self.enemies_spawned = 0
self.spawn_delay = 1000 # milliseconds between spawns
self.last_spawn = 0
self.wave_complete = False
def start_new_wave(self):
self.wave_number += 1
# Increase enemies gradually (capped at 15 per wave)
self.enemies_in_wave = min(5 + self.wave_number, 15)
self.enemies_spawned = 0
self.spawn_delay = max(300, 1000 - (self.wave_number * 50)) # Faster spawns as waves progress
self.wave_complete = False
def update(self):
now = pygame.time.get_ticks()
if (self.enemies_spawned < self.enemies_in_wave and
now - self.last_spawn > self.spawn_delay):
self.last_spawn = now
self.spawn_enemy()
self.enemies_spawned += 1
if self.enemies_spawned >= self.enemies_in_wave:
self.wave_complete = True
def spawn_enemy(self):
# Spawn enemies in different patterns
if self.wave_number % 3 == 0:
# V formation
cols = min(5, self.enemies_in_wave)
spacing = WIDTH // (cols + 1)
x = spacing * ((self.enemies_spawned % cols) + 1)
y = -40 - (20 * (self.enemies_spawned // cols))
else:
# Random spread
x = random.randint(50, WIDTH-50)
y = -40
enemy = Enemy(x, y)
all_sprites.add(enemy)
enemies.add(enemy)
The above code sends a group of enemies. In each wave, the enemy count increases, and enemies spawn get faster.
self.enemies_in_wave = min(5 + self.wave_number, 15): This line increases enemy count (capped at 15)
- Wave 1: 6 enemies
- Wave 2: 7 enemies
- …
- Wave 10+: 15 enemies (max).
self.spawn_delay = max(300, 1000 - (self.wave_number * 50)): Reduces spawn delay (enemies spawn faster each wave)
- Wave 1: 950ms
- Wave 2: 900ms
- …
- Caps at 300ms (minimum delay).
Health Bar
Let’s declare a normal function to show the health bar at the top-left corner of the gaming window.
def draw_health_bar(surface, x, y, health, max_health):
BAR_LENGTH = 100
BAR_HEIGHT = 10
fill = (health / max_health) * BAR_LENGTH
outline_rect = pygame.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
fill_rect = pygame.Rect(x, y, fill, BAR_HEIGHT)
pygame.draw.rect(surface, GREEN, fill_rect)
pygame.draw.rect(surface, WHITE, outline_rect, 2)
Start Screen
Before the game starts, our game will show a welcoming window displaying the name of the game in bold text and some instructions to start and play the game. Let’s declare a function named show_start_screen.
def show_start_screen():
screen.fill(BLACK)
if background:
screen.blit(background, (0, 0))
else:
for star in stars:
star.draw(screen)
title = big_font.render("SPACE SHOOTER", True, WHITE)
start = font.render("Press any key to begin", True, WHITE)
controls = font.render("Arrow keys to move, SPACE to shoot", True, WHITE)
screen.blit(title, (WIDTH//2 - title.get_width()//2, HEIGHT//4))
screen.blit(start, (WIDTH//2 - start.get_width()//2, HEIGHT//2))
screen.blit(controls, (WIDTH//2 - controls.get_width()//2, HEIGHT*3//4))
pygame.display.flip()
waiting = True
while waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
waiting = False
Game Over
As we’ve created the start screen, now we will declare a function for showing another window when the game ends. The window will display a “Game Over” message in a big red color including the Total Score and how to restart the game again.
def show_game_over_screen():
screen.fill(BLACK)
if background:
screen.blit(background, (0, 0))
else:
for star in stars:
star.draw(screen)
game_over = big_font.render("GAME OVER", True, RED)
final_score = font.render(f"Final Score: {score}", True, WHITE)
restart = font.render("Press R to restart or ESC to quit", True, WHITE)
screen.blit(game_over, (WIDTH//2 - game_over.get_width()//2, HEIGHT//3))
screen.blit(final_score, (WIDTH//2 - final_score.get_width()//2, HEIGHT//2))
screen.blit(restart, (WIDTH//2 - restart.get_width()//2, HEIGHT*2//3))
pygame.display.flip()
waiting = True
while waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_r:
return True # Restart
elif event.key == pygame.K_ESCAPE:
return False # Quit
The Main Block
This section is the heart of the game. Here, we will tie all the components to create a real gameplay experience.
if __name__ == "__main__":
# Create game window
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Shooter")
clock = pygame.time.Clock()
# Try to load background image
try:
background = pygame.image.load(os.path.join('assets', 'background.jpg')).convert()
background = pygame.transform.scale(background, (WIDTH, HEIGHT))
except:
background = None
# Create sprite groups
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
# Create player
player = Player()
all_sprites.add(player)
# Create stars for background (if no background image)
stars = [Star() for _ in range(STAR_COUNT)] if background is None else []
# Create enemy wave controller
wave_controller = EnemyWave()
wave_controller.start_new_wave()
# Load sounds
try:
shoot_sound = mixer.Sound(os.path.join('assets', 'shoot.wav'))
explosion_sound = mixer.Sound(os.path.join('assets', 'explosion.wav'))
mixer.music.load(os.path.join('assets', 'background.mp3'))
mixer.music.set_volume(0.5)
mixer.music.play(loops=-1)
except:
print("Sound files not found - continuing without sound")
shoot_sound = mixer.Sound(buffer=bytearray(44))
explosion_sound = mixer.Sound(buffer=bytearray(44))
# Game variables
score = 0
game_over = False
paused = False
font = pygame.font.Font(None, 36)
big_font = pygame.font.Font(None, 72)
# Game loop
running = True
show_start_screen()
while running:
# Keep loop running at the right speed
clock.tick(FPS)
# Process input
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and not game_over and not paused:
player.shoot()
elif event.key == pygame.K_p and not game_over:
paused = not paused
elif event.key == pygame.K_ESCAPE:
running = False
if not game_over and not paused:
# Update
# Update enemy wave
wave_controller.update()
# Start new wave if current one is complete
if wave_controller.wave_complete and len(enemies) == 0:
wave_controller.start_new_wave()
# Update all sprites
all_sprites.update()
# Update stars (if no background image)
if background is None:
for star in stars:
star.update()
# Check for bullet-enemy collisions
hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
for hit in hits:
explosion_sound.play()
score += 50 - hit.speed * 10 # Faster enemies give less points
# Check for player-enemy collisions
hits = pygame.sprite.spritecollide(player, enemies, True)
for hit in hits:
explosion_sound.play()
player.health -= 20
if player.health <= 0:
game_over = True
# Draw
if background:
screen.blit(background, (0, 0))
else:
screen.fill(BLACK)
for star in stars:
star.draw(screen)
# Draw all sprites
all_sprites.draw(screen)
# Draw UI
draw_health_bar(screen, 5, 5, player.health, player.max_health)
score_text = font.render(f"Score: {score}", True, WHITE)
wave_text = font.render(f"Wave: {wave_controller.wave_number}", True, WHITE)
screen.blit(score_text, (WIDTH - score_text.get_width() - 10, 10))
screen.blit(wave_text, (WIDTH - wave_text.get_width() - 10, 50))
if paused:
pause_text = big_font.render("PAUSED", True, WHITE)
screen.blit(pause_text, (WIDTH//2 - pause_text.get_width()//2, HEIGHT//2))
if game_over:
if show_game_over_screen():
# Reset game
game_over = False
score = 0
player.health = player.max_health
# Clear all sprites
for sprite in all_sprites:
sprite.kill()
# Recreate player
player = Player()
all_sprites.add(player)
# Reset wave controller
wave_controller = EnemyWave()
wave_controller.start_new_wave()
else:
running = False
# Flip the display
pygame.display.flip()
pygame.quit()
sys.exit()
In the above code, we did the following tasks:
Game Setup
- Creates the game window (800×600 pixels)
- Loads visual and audio assets (with fallback options if missing)
- Prepares all game objects:
- Player spaceship
- Enemy wave system
- Background (image or starfield)
Core Gameplay Loop (Runs 60 Times/Second)
- Listens for player input (movement, shooting, pausing)
- Manages enemies:
- Spawns them in waves
- Increases difficulty progressively
- Handles collisions:
- Bullets destroy enemies (score increases)
- Enemies damage player (health decreases)
- Controls game states:
- Normal play
- Paused mode
- Game over screen
Visual Display
- Draws everything in the correct order:
- Background
- Game objects (player, enemies, bullets)
- UI elements (health bar, score, wave counter)
- Shows special screens when needed (paused/game over messages)
Clean Management
- Automatically restarts the game if players choose to continue
- Properly closes the game when exiting
Complete Source Code
Here is the complete source code for your convenience:
import pygame
import random
import sys
import os
from pygame import mixer
# Initialize pygame
pygame.init()
mixer.init()
WIDTH, HEIGHT = 800, 600
FPS = 60
PLAYER_SPEED = 7
ENEMY_SPEED = 2
BULLET_SPEED = 10
STAR_COUNT = 100
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
try:
# Try to load player image
self.image = pygame.image.load(os.path.join('assets', 'player.png')).convert_alpha()
self.image = pygame.transform.scale(self.image, (50, 40))
except:
# If image not found, a blank image canvas will create
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect(center=(WIDTH//2, HEIGHT-50))
self.speed = PLAYER_SPEED
self.health = 100
self.max_health = 100
self.shoot_delay = 250 # milliseconds
self.last_shot = pygame.time.get_ticks()
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and self.rect.left > 0:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT] and self.rect.right < WIDTH:
self.rect.x += self.speed
def shoot(self):
now = pygame.time.get_ticks()
if now - self.last_shot > self.shoot_delay:
self.last_shot = now
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
shoot_sound.play()
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
try:
# Try to load enemy image
self.image = pygame.image.load(os.path.join('assets', 'enemy.png')).convert_alpha()
self.image = pygame.transform.scale(self.image, (40, 40))
except:
# If image not found, a blank image canvas will create
self.image = pygame.Surface((40, 40))
self.image.fill(RED)
self.rect = self.image.get_rect(center=(x, y))
self.speed = random.randint(1, 3)
self.health = 30
def update(self):
self.rect.y += self.speed
if self.rect.top > HEIGHT:
self.kill()
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
try:
# Try to load bullet image
self.image = pygame.image.load(os.path.join('assets', 'bullet.png')).convert_alpha()
self.image = pygame.transform.scale(self.image, (10, 15))
except:
# If image not found, a blank image canvas will create
self.image = pygame.Surface((5, 15))
self.image.fill(BLUE)
self.rect = self.image.get_rect(center=(x, y))
self.speed = BULLET_SPEED
def update(self):
self.rect.y -= self.speed
if self.rect.bottom < 0:
self.kill()
class Star:
def __init__(self):
self.x = random.randint(0, WIDTH)
self.y = random.randint(0, HEIGHT)
self.speed = random.randint(1, 3)
self.size = random.randint(1, 3)
def update(self):
self.y += self.speed
if self.y > HEIGHT:
self.y = 0
self.x = random.randint(0, WIDTH)
def draw(self, screen):
pygame.draw.circle(screen, WHITE, (self.x, self.y), self.size)
class EnemyWave:
def __init__(self):
self.wave_number = 0
self.enemies_in_wave = 5
self.enemies_spawned = 0
self.spawn_delay = 1000 # milliseconds between spawns
self.last_spawn = 0
self.wave_complete = False
def start_new_wave(self):
self.wave_number += 1
# Increase enemies gradually (capped at 15 per wave)
self.enemies_in_wave = min(5 + self.wave_number, 15)
self.enemies_spawned = 0
self.spawn_delay = max(300, 1000 - (self.wave_number * 50)) # Faster spawns as waves progress
self.wave_complete = False
def update(self):
now = pygame.time.get_ticks()
if (self.enemies_spawned < self.enemies_in_wave and
now - self.last_spawn > self.spawn_delay):
self.last_spawn = now
self.spawn_enemy()
self.enemies_spawned += 1
if self.enemies_spawned >= self.enemies_in_wave:
self.wave_complete = True
def spawn_enemy(self):
# Spawn enemies in different patterns
if self.wave_number % 3 == 0:
# V formation
cols = min(5, self.enemies_in_wave)
spacing = WIDTH // (cols + 1)
x = spacing * ((self.enemies_spawned % cols) + 1)
y = -40 - (20 * (self.enemies_spawned // cols))
else:
# Random spread
x = random.randint(50, WIDTH-50)
y = -40
enemy = Enemy(x, y)
all_sprites.add(enemy)
enemies.add(enemy)
def draw_health_bar(surface, x, y, health, max_health):
BAR_LENGTH = 100
BAR_HEIGHT = 10
fill = (health / max_health) * BAR_LENGTH
outline_rect = pygame.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
fill_rect = pygame.Rect(x, y, fill, BAR_HEIGHT)
pygame.draw.rect(surface, GREEN, fill_rect)
pygame.draw.rect(surface, WHITE, outline_rect, 2)
def show_start_screen():
screen.fill(BLACK)
if background:
screen.blit(background, (0, 0))
else:
for star in stars:
star.draw(screen)
title = big_font.render("SPACE SHOOTER", True, WHITE)
start = font.render("Press any key to begin", True, WHITE)
controls = font.render("Arrow keys to move, SPACE to shoot", True, WHITE)
screen.blit(title, (WIDTH//2 - title.get_width()//2, HEIGHT//4))
screen.blit(start, (WIDTH//2 - start.get_width()//2, HEIGHT//2))
screen.blit(controls, (WIDTH//2 - controls.get_width()//2, HEIGHT*3//4))
pygame.display.flip()
waiting = True
while waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
waiting = False
def show_game_over_screen():
screen.fill(BLACK)
if background:
screen.blit(background, (0, 0))
else:
for star in stars:
star.draw(screen)
game_over = big_font.render("GAME OVER", True, RED)
final_score = font.render(f"Final Score: {score}", True, WHITE)
restart = font.render("Press R to restart or ESC to quit", True, WHITE)
screen.blit(game_over, (WIDTH//2 - game_over.get_width()//2, HEIGHT//3))
screen.blit(final_score, (WIDTH//2 - final_score.get_width()//2, HEIGHT//2))
screen.blit(restart, (WIDTH//2 - restart.get_width()//2, HEIGHT*2//3))
pygame.display.flip()
waiting = True
while waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_r:
return True # Restart
elif event.key == pygame.K_ESCAPE:
return False # Quit
if __name__ == "__main__":
# Create game window
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Shooter")
clock = pygame.time.Clock()
# Try to load background image
try: # background.jpg
background = pygame.image.load(os.path.join('assets', '')).convert()
background = pygame.transform.scale(background, (WIDTH, HEIGHT))
except:
background = None
# Create sprite groups
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
# Create player
player = Player()
all_sprites.add(player)
# Create stars for background (if no background image)
stars = [Star() for _ in range(STAR_COUNT)] if background is None else []
# Create enemy wave controller
wave_controller = EnemyWave()
wave_controller.start_new_wave()
# Load sounds
try:
shoot_sound = mixer.Sound(os.path.join('assets', 'shoot.wav'))
explosion_sound = mixer.Sound(os.path.join('assets', 'explosion.wav'))
mixer.music.load(os.path.join('assets', 'background.mp3'))
mixer.music.set_volume(0.5)
mixer.music.play(loops=-1)
except:
print("Sound files not found - continuing without sound")
shoot_sound = mixer.Sound(buffer=bytearray(44))
explosion_sound = mixer.Sound(buffer=bytearray(44))
# Game variables
score = 0
game_over = False
paused = False
font = pygame.font.Font(None, 36)
big_font = pygame.font.Font(None, 72)
# Game loop
running = True
show_start_screen()
while running:
# Keep loop running at the right speed
clock.tick(FPS)
# Process input
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and not game_over and not paused:
player.shoot()
elif event.key == pygame.K_p and not game_over:
paused = not paused
elif event.key == pygame.K_ESCAPE:
running = False
if not game_over and not paused:
# Update
# Update enemy wave
wave_controller.update()
# Start new wave if current one is complete
if wave_controller.wave_complete and len(enemies) == 0:
wave_controller.start_new_wave()
# Update all sprites
all_sprites.update()
# Update stars (if no background image)
if background is None:
for star in stars:
star.update()
# Check for bullet-enemy collisions
hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
for hit in hits:
explosion_sound.play()
score += 50 - hit.speed * 10 # Faster enemies give less points
# Check for player-enemy collisions
hits = pygame.sprite.spritecollide(player, enemies, True)
for hit in hits:
explosion_sound.play()
player.health -= 20
if player.health <= 0:
game_over = True
# Draw
if background:
screen.blit(background, (0, 0))
else:
screen.fill(BLACK)
for star in stars:
star.draw(screen)
# Draw all sprites
all_sprites.draw(screen)
# Draw UI
draw_health_bar(screen, 5, 5, player.health, player.max_health)
score_text = font.render(f"Score: {score}", True, WHITE)
wave_text = font.render(f"Wave: {wave_controller.wave_number}", True, WHITE)
screen.blit(score_text, (WIDTH - score_text.get_width() - 10, 10))
screen.blit(wave_text, (WIDTH - wave_text.get_width() - 10, 50))
if paused:
pause_text = big_font.render("PAUSED", True, WHITE)
screen.blit(pause_text, (WIDTH//2 - pause_text.get_width()//2, HEIGHT//2))
if game_over:
if show_game_over_screen():
# Reset game
game_over = False
score = 0
player.health = player.max_health
# Clear all sprites
for sprite in all_sprites:
sprite.kill()
# Recreate player
player = Player()
all_sprites.add(player)
# Reset wave controller
wave_controller = EnemyWave()
wave_controller.start_new_wave()
else:
running = False
# Flip the display
pygame.display.flip()
pygame.quit()
sys.exit()
Summary
In this tutorial, we built a fully functional computer game called Space Shooter using Python and the Pygame library. We learned how to create game logic, sprite controls, sound controls, user input, and all the core concepts needed to build a 2D computer game.
The entire article is divided into multiple segments that help beginners to learn faster. This project is best for those who want to build their Python game development portfolio.
So, why wait to? Launch your spaceship and shoot all the enemies coming your way in the space.
If you have any queries related to this Python project, let me know at contact@pyseek.com.
Happy Shooting!



