In the world of game development, Python, when paired with PyGame, offers a platform that is both approachable for beginners and sufficiently robust for experienced developers.
This article takes you into the creation of a Space Shooter game, a genre loved for its simplicity and excitement.
The game comprises of several core components: the player's spaceship, enemy ships, and projectiles, each designed and integrated to create an engaging gameplay experience.
Here is the game in action:
Game Architecture
The Space Shooter game is structured into several modular Python files, each responsible for a distinct aspect of the game:
Game.py: The heart of our game, this file orchestrates the game loop, event handling, and the rendering process. It initializes the PyGame library, sets up the game window, and integrates other components to create a fluid gameplay experience.
Player.py: This file defines the Player class, encapsulating the player's spaceship. It includes functionalities for moving the spaceship, rendering its visual representation (Player.png
), and shooting projectiles.
Enemy.py: Similar to the Player class, the Enemy class defined in this file manages the behavior of enemy ships. It handles their movement patterns, interaction with projectiles, and rendering of Enemy.png
.
Projectile.py: Projectiles are crucial for the game's firing mechanics. This file contains the Projectile class, which manages the creation, movement, and rendering of projectiles (Projectile.png
) shot by the player.
The Visual Elements
The game's visual appeal is delivered from the PNG files:
Player.png
The Player.png
file offers distinct visual identities to the player's spaceship making it easily recognizable during gameplay.
Enemy.png
The Enemy.png
file offers distinct visual identities to the enemy ships making them easily recognizable during gameplay.
Projectile.png
Projectile.png
provides a visual for the bullets fired by the player, enhancing the game's immersive experience.
Excited to dive deeper into the world of Python programming? Look no further than my latest ebook, "Python Tricks - A Collection of Tips and Techniques".
Get the eBook
Inside, you'll discover a plethora of Python secrets that will guide you through a journey of learning how to write cleaner, faster, and more Pythonic code. Whether it's mastering data structures, understanding the nuances of object-oriented programming, or uncovering Python's hidden features, this ebook has something for everyone.
Developing the Game Components
With the design of the game architecture and main components explained, let's now implement the different files and logic.
Player.py: Steering the Spaceship
The Player.py
script introduces the Player
class, a fundamental component that controls the player's spaceship:
import pygame
from Projectile import Projectile
# Create classes for the player's spaceship
class Player(pygame.sprite.Sprite):
def __init__(self, speed, screen_width, screen_height):
super().__init__()
# Load the image for the player's spaceship
self.image = pygame.image.load("Player.png").convert_alpha()
# Set the initial position and size of the spaceship
self.rect = self.image.get_rect(center=(screen_width/2, screen_height-64))
# Set the speed of the spaceship
self.speed = speed
# Set up shooting variables
self.shoot_delay = 500 # Shooting delay in milliseconds
self.last_shot = pygame.time.get_ticks()
# Set up the player's score
self.score = 0
def update(self, player_projectiles):
# Get the current keyboard state
keys = pygame.key.get_pressed()
# Move the spaceship based on the keyboard state
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.rect.x += self.speed
# Shoot projectiles when the space key is pressed
if keys[pygame.K_SPACE]:
self.shoot(player_projectiles)
# Keep the spaceship within the screen boundaries
self.rect.clamp_ip(pygame.display.get_surface().get_rect())
def shoot(self, player_projectiles):
# Check if enough time has passed since the last shot
current_time = pygame.time.get_ticks()
if current_time - self.last_shot >= self.shoot_delay:
# Create a new projectile and add it to the projectile group
projectile = Projectile(5, self.rect.centerx, self.rect.top)
player_projectiles.add(projectile)
# Update the last shot time
self.last_shot = current_time
return player_projectiles
Here's a breakdown of its key components and functionalities:
Player Class: Inherits from pygame.sprite.Sprite
, making it a subclass that can use all the sprite functionalities provided by PyGame, such as rendering images and detecting collisions.
init
Method: The constructor initializes the player's spaceship with several attributes:
Image Loading: Loads the spaceship's image from
Player.png
and sets it to use alpha transparency for better visual quality.Positioning: The spaceship's starting position is centered horizontally (
screen_width/2
) and placed near the bottom (screen_height-64
) of the game screen.Speed and Shooting Delay: Sets the player's speed and a delay between shots (500 milliseconds) to prevent continuous firing.
Score Tracking: Initializes a score attribute to track the player's score.
update
Method: This method updates the player's position based on keyboard inputs (left, right, and space for shooting). It ensures the player's spaceship stays within the screen boundaries.
shoot
Method: Handles the shooting mechanism. It checks if the time elapsed since the last shot is greater than the shooting delay before creating a new Projectile
object at the player's current position and adding it to the player_projectiles
group for management and rendering. This prevents the player from shooting continuously without any delay.
The Player
class is designed to encapsulate all the functionalities necessary for controlling the player's spaceship, including moving it across the screen and shooting projectiles.
Enemy.py: The Space Adversaries
The Enemy.py
file hosts the Enemy
class, responsible for defining the attributes and behaviors of enemy spaceships that the player must confront:
import random
import pygame
# Create classes for the enemy's spaceship
class Enemy(pygame.sprite.Sprite):
def __init__(self, speed, screen_width, screen_height):
super().__init__()
# Load the enemy image
self.image = pygame.image.load("Enemy.png").convert_alpha()
# Set the initial position and size of the enemy
self.rect = self.image.get_rect(center=(random.randint(64, screen_width-64), random.randint(32, 132)))
# Set the speed of the enemy
self.speed = speed
# Set height
self.screen_height = screen_height
# Set up the timer for updating the enemy's position
self.last_update_time = pygame.time.get_ticks()
self.update_interval = 500 # 500ms
def update(self):
# Get the current time
current_time = pygame.time.get_ticks()
# Check if enough time has passed since the last position update
if current_time - self.last_update_time >= self.update_interval:
# Update the enemy's position
self.rect.y += self.speed
# Reset the timer for the next position update
self.last_update_time = current_time
# Remove the enemy if it goes off-screen
if self.rect.bottom > self.screen_height:
self.kill()
Let's dissect its components and functionalities:
Enemy Class: Inherits from pygame.sprite.Sprite
, enabling it to use sprite-related features offered by PyGame, such as image handling and collision detection.
init
Method: The constructor initializes the enemy ship with several key attributes:
Image Loading: Loads the enemy ship's image from
Enemy.png
and enables alpha transparency for improved visual effects.Positioning: Sets the enemy's starting position at a random location near the top of the screen. The
random.randint
function ensures that each enemy appears at a different horizontal position within the playable area.Speed: Determines how quickly the enemy moves down the screen.
Movement Timing: Uses
pygame.time.get_ticks()
to manage the timing of the enemy's movement, along with anupdate_interval
that defines how often (in milliseconds) the enemy's position is updated.
update
Method: This method is called to update the enemy's position:
It checks if the current time minus the last update time is greater than the update interval. If so, the enemy moves downward by increasing its y-coordinate by the speed amount, and the
lastupdatetime
is updated to the current time.If the enemy moves off the bottom of the screen (
self.rect.bottom > self.screen_height
), it is removed from the game using thekill
method. This prevents enemies from continuing to consume resources once they are no longer visible or interactable.
The Enemy
class encapsulates the functionality needed for enemy ships in the game, including their appearance, randomized starting positions, and downward movement.
Projectile.py: Managing Firepower
The Projectile.py
file contains the Projectile
class, which is crucial for the game's firing mechanics, allowing the player to shoot projectiles:
Full article at: https://developer-service.blog/building-a-space-shooter-game-with-pygame/