Pygame Game Development: A Submarine Shooter Review
- Zartom
- Aug 27
- 10 min read

Embarking on your journey with Pygame, you've crafted a delightful submarine-themed game. This review delves into the code's structure, functionality, and adherence to Pythonic practices, offering insights for both Pygame beginners and those looking to refine their Python skills. We'll explore how your game manages moving objects, handles player input, and implements core mechanics like scoring and collision detection.
This guide provides a structured approach to developing a simple Pygame application, focusing on game mechanics, object-oriented design, and best practices for Python game development. We will break down the core components of the game, from initialization and game loops to event handling and object management.
Developing a Pygame Submarine Game
The objective is to create a 2D game using Pygame where players control a ship and launch bombs to destroy submarines. The game involves managing multiple moving objects, scoring, and user input for actions like dropping bombs and toggling fullscreen mode.
Core Game Mechanics
The game simulates a naval battle where a player-controlled ship moves horizontally, releasing bombs downwards. Submarines move horizontally in the opposite direction, below the water line. Destroying submarines earns points, with deeper submarines yielding more points. There's a limit to the number of simultaneous bombs, and dropping additional bombs incurs a score penalty, making strategic bomb deployment crucial.
The player's interaction is limited to dropping bombs using the down arrow key. Additional controls include toggling fullscreen with 'F' and quitting the game with 'Q'. The game loop must efficiently handle drawing, updating states, and processing user inputs.
Technical Requirements
The game requires Pygame to be installed. It utilizes several image assets for the ship, submarines, and bombs, loaded from external files. A settings file manages game parameters like screen dimensions, frame rate, object speeds, and colors. A separate utility file handles color name translations.
The code structure should be modular, with classes for game logic and moving objects. Error handling for missing assets or incorrect configurations is beneficial for robustness.
Pygame Game Development Strategy
We will implement the game using object-oriented principles, with a central Game class managing the game state and a MovingObject class to handle the behavior of all dynamic elements.
Game Initialization and Setup
The Game class constructor initializes Pygame, sets up the display window, loads assets, and defines game constants such as screen dimensions, colors, and frame rate. It creates instances of game objects like the ship and initializes game state variables like score and object lists.
The game loop, managed by the run method, continuously handles events, updates game states, and renders the scene. The pygame.time.Clock is used to control the frame rate, ensuring consistent game speed across different hardware.
Object Management and Movement
The MovingObject class encapsulates the logic for objects that move across the screen. It handles image loading, position tracking, movement calculations based on speed and time, and drawing on the screen. It also manages object activation and deactivation.
The Game class maintains lists of active submarines and bombs. In each frame, it iterates through these lists to update object positions and check for collisions, ensuring efficient management of game elements.
Implementing Core Gameplay Mechanics
This section details the implementation of key game features, including bomb dropping, submarine spawning, collision detection, and scoring.
Bomb Dropping and Scoring
The player drops bombs using the down arrow key. The drop_bomb method checks if bombs can be dropped based on available capacity and score. Dropping bombs deducts score, with the cost increasing for subsequent bombs. The score is updated to reflect this penalty.
Destroying a submarine awards points based on its depth. The handle_hits method detects collisions between bombs and submarines. Upon a hit, both objects are deactivated, and the score is updated accordingly, reflecting the depth-based reward.
Submarine Spawning and Movement
Submarines are spawned randomly with a probability defined by p_spawn, which is derived from the settings. The spawn_submarine method creates new submarines at random depths and speeds within specified ranges. Submarines move from right to left.
The update_state method iterates through all active submarines and bombs, calling their respective move methods. The move method in MovingObject calculates the new position based on speed and elapsed time. If an object reaches its destination and is not set to repeat, it is deactivated.
Collision Detection and State Updates
Collision detection is performed in the handle_hits method by checking the bounding boxes of bombs and submarines using colliderect. When a collision occurs, both the bomb and the submarine are marked as inactive.
After checking for hits, the game state is updated by filtering out inactive objects from the submarines and bombs lists. This cleanup process ensures that only active objects are processed and drawn in subsequent frames.
Handling User Input and Game Events
The handle_events method processes all Pygame events. This includes checking for the quit event (closing the window) and key press events.
Key Controls
The down arrow key triggers the drop_bomb function. The 'F' key toggles fullscreen mode by switching the display mode. The 'Q' key is mapped to the quit event, allowing the player to exit the game gracefully.
Event handling is crucial for making the game interactive. Pygame's event queue allows for responsive control, ensuring that player inputs are registered and acted upon promptly within the game loop.
Ensuring Robustness and Asset Management
The game relies on external image files for its visual elements. The MovingObject class uses a dictionary (imagestore) to cache loaded images, preventing redundant loading and improving performance.
Asset Loading and Error Handling
The MovingObject constructor loads images from specified paths. It's recommended to perform an initial check of all required asset files during game startup to catch missing files early. Case sensitivity in file names can be a common issue, especially on different operating systems.
The colours.py module handles color definitions, translating named colors into RGB values using both custom settings and an external rgb.txt file. This modular approach to color management makes it easier to customize the game's appearance.
Adhering to Pythonic Code Style
Following Python's style conventions, such as PEP 8, enhances code readability and maintainability. Key style considerations include proper spacing and line wrapping.
Spacing and Line Length
Python style guides recommend two blank lines between methods and functions for better separation. Line wrapping should be considered for readability, typically around 100-120 characters, rather than a strict 80-character limit.
Adopting consistent spacing and logical line breaks makes the code easier to understand and debug, especially for developers new to Python or Pygame.
Object-Oriented Design Principles
The current approach uses separate lists for submarines and bombs. An alternative could be to use a single list of generic MovingObject instances, possibly with a type attribute, simplifying iteration. However, maintaining separate lists can be beneficial for specific logic, like tracking counts.
Considering a physics-based movement model (position, velocity, acceleration) instead of path-based movement might align better with common game development practices and principles of least surprise.
Key Takeaways for Pygame Development
This project demonstrates fundamental Pygame concepts: initializing the environment, managing game objects, handling user input, implementing game logic (spawning, movement, collision), and rendering graphics. The code structure promotes modularity and reusability.
Key improvements could include more robust asset loading, adhering to Python style guides, and potentially refactoring the object management approach for greater flexibility. The core mechanics provide a solid foundation for further game development.
Related Pygame Development Tasks
Explore these related programming challenges to deepen your Pygame skills.
Creating a Scrolling Background
Implement a background that moves continuously, creating an illusion of forward motion. This often involves drawing the background image twice and offsetting its position.
Implementing Player Health and Lives
Add a health system or multiple lives for the player character. This involves tracking a numerical value and updating the game state when health is lost or a life is depleted.
Adding Sound Effects and Music
Integrate audio elements using Pygame's mixer module to play sound effects for actions like shooting or explosions, and background music.
Developing a Simple Platformer
Create a character that can move left, right, and jump. This involves handling gravity, collision detection with platforms, and character animations.
Creating a Particle System
Generate visual effects like explosions or smoke using a system of small, short-lived particles. Each particle would have its own position, velocity, and lifespan.
Code Examples for Pygame Enhancement
These code snippets illustrate common Pygame techniques and improvements.
Basic Pygame Window Setup
import pygame
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Pygame Window")
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0)) # Black background
pygame.display.flip()
pygame.quit()
This code demonstrates the fundamental structure for initializing Pygame, creating a display window, and running a basic game loop that handles the quit event.
Sprite Groups for Efficient Rendering
import pygame
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
# Example sprite
player_image = pygame.Surface((50, 50))
player_image.fill((0, 255, 0)) # Green
player_sprite = pygame.sprite.Sprite()
player_sprite.image = player_image
player_sprite.rect = player_sprite.image.get_rect(topleft=(50, 50))
player_group = pygame.sprite.Group()
player_group.add(player_sprite)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0))
player_group.draw(screen) # Draw all sprites in the group
pygame.display.flip()
pygame.quit()
Using sprite groups simplifies drawing and updating multiple game objects. The player_group.draw(screen) call efficiently renders all sprites within the group.
Handling Keyboard Input for Movement
import pygame
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.key.set_repeat(1, 10) # Enable key repeat
player_rect = pygame.Rect(50, 50, 50, 50)
player_color = (255, 0, 0) # Red
player_speed = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_rect.x -= player_speed
if event.key == pygame.K_RIGHT:
player_rect.x += player_speed
if event.key == pygame.K_UP:
player_rect.y -= player_speed
if event.key == pygame.K_DOWN:
player_rect.y += player_speed
screen.fill((0, 0, 0))
pygame.draw.rect(screen, player_color, player_rect)
pygame.display.flip()
pygame.quit()
This example shows how to capture key press events (KEYDOWN) to move a player-controlled rectangle. Enabling key repeat allows for continuous movement when a key is held down.
Collision Detection Between Rectangles
import pygame
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
rect1 = pygame.Rect(100, 100, 100, 100)
rect2 = pygame.Rect(150, 150, 100, 100)
color1 = (255, 0, 0) # Red
color2 = (0, 0, 255) # Blue
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0))
pygame.draw.rect(screen, color1, rect1)
pygame.draw.rect(screen, color2, rect2)
if rect1.colliderect(rect2):
pygame.draw.rect(screen, (255, 255, 0), rect1.union(rect2)) # Yellow overlap
pygame.display.flip()
pygame.quit()
The colliderect() method is fundamental for detecting overlaps between two pygame.Rect objects, crucial for game interactions like detecting hits or triggers.
Displaying Text on the Screen
import pygame
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
font = pygame.font.SysFont('Arial', 30)
text_surface = font.render('Hello, Pygame!', True, (255, 255, 255)) # White text
text_rect = text_surface.get_rect(center=(screen_width//2, screen_height//2))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0))
screen.blit(text_surface, text_rect)
pygame.display.flip()
pygame.quit()
This snippet shows how to render text using Pygame's font module. It creates a surface with the text and then blits it onto the main screen surface at a specified position.
Component | Description | Key Features |
Game Logic (uboot.py) | Manages the overall game state, including player ship, submarines, bombs, score, and event handling. | Initialization, game loop, drawing, state updates, event processing, collision detection. |
Moving Objects (objects.py) | A class for all dynamic game elements like the ship, submarines, and bombs. | Handles movement along a path, image loading, activation/deactivation, and bounding box calculation. |
Color Utility (colours.py) | Translates named colors into RGB values. | Uses custom settings and X11's rgb.txt database for color definitions. |
Game Settings (settings.py) | Configuration file for game parameters. | Screen resolution, object speeds, limits, spawn rates, colors, and font settings. |
Graphics Assets | Image files for game elements. | schiff.png (ship), Uboot.png (submarine), bomb.png (bomb). |
Core Mechanics | Player controls, scoring, and game objectives. | Dropping bombs, destroying submarines, score penalties for extra bombs, depth-based scoring. |
User Controls | Input handling for game interaction. | Down arrow for bombs, 'F' for fullscreen, 'Q' to quit. |
Code Style | Adherence to Python best practices. | PEP 8 guidelines, line wrapping, object-oriented design, asset caching. |
From our network :
Navigating the End of Support for Windows 10: A Comprehensive Guide to Your Options
Decision Tree Regression Plotting in Python: Visualizing Multidimensional Data
Rajagopala Chidambaram India’s Nuclear Weapons Designer Passes Away
Understanding Newton’s Law of Gravitation: A Detailed Explanation and Example
Comments