Game Development 21 min read

Build an Alien Invasion Game with Pygame: Complete Code Walkthrough

This article walks through the complete implementation of an Alien Invasion game using Python's Pygame library, explaining the modular structure, key classes, functions, and game mechanics while providing full source code for each component.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Build an Alien Invasion Game with Pygame: Complete Code Walkthrough

The article demonstrates how to build a simple "Alien Invasion" shooting game with Python and Pygame, emphasizing modular design, object‑oriented programming, and reusable functions.

Main entry (alien_invasion.py)

"""该游戏主程序,尽量做到最简单"""
import pygame
from settings import Settings
from ship import Ship
from pygame.sprite import Group
from game_stats import GameStats
from button import Button
from score_board import Scoreboard
import game_function as gf

def run_game():
    """初始化背景设置"""
    pygame.init()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption('Alien Invasion')
    ship = Ship(ai_settings, screen)
    bullets = Group()
    aliens = Group()
    gf.creat_fleet(ai_settings, screen, ship, aliens)
    stats = GameStats(ai_settings)
    sb = Scoreboard(ai_settings, screen, stats)
    play_button = Button(ai_settings, screen, "Play")
    while True:
        gf.check_events(ai_settings, screen, ship, aliens, bullets, stats, play_button, sb)
        if stats.game_active:
            ship.update()
            gf.update_bullet(ai_settings, screen, ship, aliens, bullets, stats, sb)
            gf.update_aliens(ai_settings, screen, ship, aliens, stats, bullets, sb)
        gf.update_screen(ai_settings, screen, ship, aliens, bullets, stats, play_button, sb)

run_game()

Game logic (game_function.py)

This module contains the core functions that handle events, update game objects, and render the screen.

import sys
import pygame
from random import randint
from bullet import Bullet
from alien import Alien
from time import sleep

def fire_bullet(ai_settings, screen, ship, bullets, stats):
    """Create a new bullet if limit not reached"""
    for i in range(int(stats.level / 5) + 1):
        if len(bullets) < ai_settings.bullet_allowed:
            new_bullet = Bullet(ai_settings, screen, ship)
            bullets.add(new_bullet)

def check_keydown(event, ai_settings, screen, ship, bullets, stats):
    """Respond to keypresses"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_UP:
        ship.moving_up = True
    elif event.key == pygame.K_DOWN:
        ship.moving_down = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(ai_settings, screen, ship, bullets, stats)

def check_keyup(event, ship):
    """Respond to key releases"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
    elif event.key == pygame.K_UP:
        ship.moving_up = False
    elif event.key == pygame.K_DOWN:
        ship.moving_down = False

def check_events(ai_settings, screen, ship, aliens, bullets, stats, play_button, sb):
    """Handle keyboard and mouse events"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown(event, ai_settings, screen, ship, bullets, stats)
        elif event.type == pygame.KEYUP:
            check_keyup(event, ship)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(ai_settings, screen, ship, aliens, bullets, stats, play_button, mouse_x, mouse_y, sb)

def check_play_button(ai_settings, screen, ship, aliens, bullets, stats, play_button, mouse_x, mouse_y, sb):
    """Start a new game when Play is clicked"""
    if play_button.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active:
        ai_settings.init_dynamic_settings()
        pygame.mouse.set_visible(False)
        stats.reset_stats()
        stats.game_active = True
        sb.prep_score()
        sb.prep_high_score(screen)
        sb.prep_level()
        sb.prep_ships(screen)
        aliens.empty()
        bullets.empty()
        creat_fleet(ai_settings, screen, ship, aliens)
        ship.center_ship(ai_settings)

def update_screen(ai_settings, screen, ship, aliens, bullets, stats, play_button, sb):
    """Redraw the screen each frame"""
    screen.fill(ai_settings.bg_color)
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    aliens.draw(screen)
    sb.show_score()
    if not stats.game_active:
        play_button.draw_button()
    pygame.display.flip()

Settings (settings.py)

Defines all configurable parameters such as screen size, colors, ship limits, bullet properties, alien speed, and scaling factors.

class Settings():
    def __init__(self):
        self.screen_width = 800
        self.screen_height = 700
        self.bg_color = (255, 255, 255)
        self.ship_limit = 2
        # Bullet settings
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = (60, 60, 60)
        self.bullet_allowed = 8
        # Alien movement
        self.fleet_drop_speed = 10
        self.speed_up_scale = 1.1
        self.init_dynamic_settings()
        self.score_scale = 1.5
        self.bullet_scale = 10
    def init_dynamic_settings(self):
        self.speed = 1.5
        self.bullet_speed = 3
        self.alien_speed = 0.2
        self.fleet_direction = -1
        self.alien_points = 10
    def increase_speed(self):
        self.speed *= self.speed_up_scale
        self.bullet_speed *= self.speed_up_scale
        self.alien_speed *= self.speed_up_scale
        self.alien_points = int(self.alien_points * self.score_scale)
    def increase_bullet_size(self):
        self.bullet_width += self.bullet_scale

Ship class (ship.py)

Represents the player’s spaceship, handles movement flags, and draws the ship on the screen.

import pygame
from pygame.sprite import Sprite

class Ship(Sprite):
    def __init__(self, ai_settings, screen):
        super(Ship, self).__init__()
        self.screen = screen
        self.image = pygame.image.load('images/ship.bmp')
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        self.ai_settings = ai_settings
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        self.center_x = float(self.rect.centerx)
        self.center_y = float(self.rect.centery)
        self.moving_right = False
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False
    def update(self):
        if self.moving_right and self.rect.right < self.screen_rect.right:
            self.center_x += self.ai_settings.speed
        if self.moving_left and self.rect.left > 0:
            self.center_x -= self.ai_settings.speed
        if self.moving_up and self.rect.top > 0:
            self.center_y -= self.ai_settings.speed
        if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
            self.center_y += self.ai_settings.speed
        self.rect.centerx = self.center_x
        self.rect.centery = self.center_y
    def blitme(self):
        self.screen.blit(self.image, self.rect)
    def center_ship(self, ai_settings):
        self.center_x = ai_settings.screen_width / 2
        self.center_y = ai_settings.screen_height - 28

Alien class (alien.py)

Defines the enemy alien sprite, its movement, and edge‑detection logic.

import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
    def __init__(self, ai_settings, screen):
        super().__init__()
        self.screen = screen
        self.ai_settings = ai_settings
        self.image = pygame.image.load('images/alien.bmp')
        self.rect = self.image.get_rect()
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height
        self.x = float(self.rect.x)
    def check_edges(self):
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.left <= 0:
            return True
    def update(self):
        self.x += self.ai_settings.alien_speed * self.ai_settings.fleet_direction
        self.rect.x = self.x
    def blitme(self):
        self.screen.blit(self.image, self.rect)

Bullet class (bullet.py)

Handles bullet creation, movement, and drawing.

import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
    def __init__(self, ai_settings, screen, ship):
        super(Bullet, self).__init__()
        self.screen = screen
        self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height)
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top
        self.y = float(self.rect.y)
        self.color = ai_settings.bullet_color
        self.speed = ai_settings.bullet_speed
    def update(self):
        self.y -= self.speed
        self.rect.y = self.y
    def draw_bullet(self):
        pygame.draw.rect(self.screen, self.color, self.rect)

Button class (button.py)

Creates a simple rectangular button with a label, used for the "Play" button.

import pygame.font

class Button():
    def __init__(self, ai_settings, screen, msg):
        self.screen = screen
        self.screen_rect = screen.get_rect()
        self.width, self.height = 200, 50
        self.button_color = (0, 255, 0)
        self.text_color = (60, 60, 60)
        self.font = pygame.font.SysFont(None, 48)
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        self.rect.center = self.screen_rect.center
        self.prep_msg(msg)
    def prep_msg(self, msg):
        self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
        self.msg_image_rect = self.msg_image.get_rect()
        self.msg_image_rect.center = self.rect.center
    def draw_button(self):
        self.screen.fill(self.button_color, self.rect)
        self.screen.blit(self.msg_image, self.msg_image_rect)

Game statistics (game_stats.py)

Tracks mutable game data such as score, level, remaining ships, and game state.

class GameStats():
    """Track statistics for the game"""
    def __init__(self, ai_settings):
        self.ai_settings = ai_settings
        self.game_active = False
        self.high_score = 0
        self.reset_stats()
    def reset_stats(self):
        self.ship_left = self.ai_settings.ship_limit
        self.score = 0
        self.level = 1
        self.bullet_width = 3

Scoreboard (score_board.py)

Renders the current score, high score, level, and remaining ships on the screen.

import pygame.font
from pygame.sprite import Group
from ship import Ship

class Scoreboard():
    def __init__(self, ai_settings, screen, stats):
        self.screen = screen
        self.screen_rect = screen.get_rect()
        self.ai_settings = ai_settings
        self.stats = stats
        self.text_color = (30, 30, 30)
        self.font = pygame.font.SysFont(None, 48)
        self.prep_score()
        self.prep_high_score(screen)
        self.prep_level()
        self.prep_ships(screen)
    def prep_score(self):
        rounded_score = int(round(self.stats.score, -1))
        score_str = "Score:" + "{:,}".format(rounded_score)
        self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color)
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = self.screen_rect.right - 20
        self.score_rect.top = 20
    def prep_high_score(self, screen):
        high_score = int(round(self.stats.high_score, -1))
        high_score_str = "High Score:" + "{:,}".format(high_score)
        self.high_score_image = self.font.render(high_score_str, True, self.text_color, self.ai_settings.bg_color)
        self.high_score_rect = self.high_score_image.get_rect()
        self.high_score_rect.left = self.screen_rect.left + 20
        self.high_score_rect.top = 20
    def prep_level(self):
        self.level_image = self.font.render("Level:" + str(self.stats.level), True, self.text_color, self.ai_settings.bg_color)
        self.level_rect = self.level_image.get_rect()
        self.level_rect.right = self.score_rect.right
        self.level_rect.bottom = self.score_rect.bottom + 650
    def show_score(self):
        self.screen.blit(self.score_image, self.score_rect)
        self.screen.blit(self.high_score_image, self.high_score_rect)
        self.screen.blit(self.level_image, self.level_rect)
        self.ships.draw(self.screen)
    def prep_ships(self, screen):
        self.ships = Group()
        for ship_number in range(self.stats.ship_left + 1):
            ship = Ship(self.ai_settings, self.screen)
            ship.rect.x = 10 + ship_number * ship.rect.width
            ship.rect.y = self.screen_rect.top + 640
            self.ships.add(ship)

The author notes that the project is still a work in progress but highlights the learning outcomes: modular thinking, class usage, and extensive function decomposition, which have already begun influencing other subjects and daily life.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PythonObject-OrientedModular ProgrammingAlien Invasion
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.