Step-by-Step Guide to Building an Aircraft Shooting Game with Python and Pygame
This tutorial walks you through creating a complete airplane‑shooting game in Python using Pygame, covering game settings, player and enemy plane classes, bullet and supply modules, the main game loop, scoring, difficulty scaling, and provides full source code for each component.
1. Game Settings
The game features three sizes of enemy aircraft (small, medium, large) with three speed levels, bullet range covering about 80% of the screen, and scoring rules: destroying a small plane gives 1,000 points, a medium plane 6,000 points, and a large plane 10,000 points. Every 30 seconds a random supply (full‑screen bomb or double‑bullet) appears, and the difficulty increases as the score rises by adding more enemies and speeding them up.
2. Player Plane
The player aircraft is defined in myplane.py . The MyPlane class inherits from pygame.sprite.Sprite , loads two normal images and a series of destruction images, sets the initial position, speed, and provides movement methods moveUp , moveDown , moveLeft , moveRight , as well as a reset method to restore the plane after a crash.
<code>import pygame</code><code></code><code>class MyPlane(pygame.sprite.Sprite):</code><code> def __init__(self, bg_size):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image1 = pygame.image.load("images/me1.png").convert_alpha()</code><code> self.image2 = pygame.image.load("images/me2.png").convert_alpha()</code><code> self.destroy_images = []</code><code> self.destroy_images.extend([\</code><code> pygame.image.load("images/me_destroy_1.png").convert_alpha(), \</code><code> pygame.image.load("images/me_destroy_2.png").convert_alpha(), \</code><code> pygame.image.load("images/me_destroy_3.png").convert_alpha(), \</code><code> pygame.image.load("images/me_destroy_4.png").convert_alpha() \</code><code> ])</code><code> self.rect = self.image1.get_rect()</code><code> self.width, self.height = bg_size[0], bg_size[1]</code><code> self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, self.height - self.rect.height - 60</code><code> self.speed = 10</code><code> self.active = True</code><code> self.invincible = False</code><code> self.mask = pygame.mask.from_surface(self.image1)</code><code></code><code> # moveUp, moveDown, moveLeft, moveRight control the plane</code><code> def moveUp(self):</code><code> if self.rect.top > 0:</code><code> self.rect.top -= self.speed</code><code> else:</code><code> self.rect.top = 0</code><code></code><code> def moveDown(self):</code><code> if self.rect.bottom < self.height - 60:</code><code> self.rect.top += self.speed</code><code> else:</code><code> self.rect.bottom = self.height - 60</code><code></code><code> def moveLeft(self):</code><code> if self.rect.left > 0:</code><code> self.rect.left -= self.speed</code><code> else:</code><code> self.rect.left = 0</code><code></code><code> def moveRight(self):</code><code> if self.rect.right < self.width:</code><code> self.rect.left += self.speed</code><code> else:</code><code> self.rect.right = self.width</code><code></code><code> def reset(self):</code><code> self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, self.height - self.rect.height - 60</code><code> self.active = True</code><code> self.invincible = True</code>3. Enemy Planes
The enemy aircraft are defined in enemy.py . Three classes – SmallEnemy , MidEnemy , and BigEnemy – each load their own images, set speed, health (energy), and implement move and reset methods. Medium and large enemies have a health bar displayed during gameplay.
<code>import pygame</code><code>from random import *</code><code>class SmallEnemy(pygame.sprite.Sprite):</code><code> def __init__(self, bg_size):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image = pygame.image.load("images/enemy1.png").convert_alpha()</code><code> self.destroy_images = []</code><code> self.destroy_images.extend([ \</code><code> pygame.image.load("images/enemy1_down1.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy1_down2.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy1_down3.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy1_down4.png").convert_alpha() \</code><code> ])</code><code> self.rect = self.image.get_rect()</code><code> self.width, self.height = bg_size[0], bg_size[1]</code><code> self.speed = 2</code><code> self.active = True</code><code> self.rect.left, self.rect.top = randint(0, self.width - self.rect.width), randint(-5 * self.height, 0)</code><code> self.mask = pygame.mask.from_surface(self.image)</code><code></code><code> def move(self):</code><code> if self.rect.top < self.height:</code><code> self.rect.top += self.speed</code><code> else:</code><code> self.reset()</code><code></code><code> def reset(self):</code><code> self.active = True</code><code> self.rect.left, self.rect.top = randint(0, self.width - self.rect.width), randint(-5 * self.height, 0)</code><code></code><code>class MidEnemy(pygame.sprite.Sprite):</code><code> energy = 8</code><code> def __init__(self, bg_size):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image = pygame.image.load("images/enemy2.png").convert_alpha()</code><code> self.image_hit = pygame.image.load("images/enemy2_hit.png").convert_alpha()</code><code> self.destroy_images = []</code><code> self.destroy_images.extend([ \</code><code> pygame.image.load("images/enemy2_down1.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy2_down2.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy2_down3.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy2_down4.png").convert_alpha() \</code><code> ])</code><code> self.rect = self.image.get_rect()</code><code> self.width, self.height = bg_size[0], bg_size[1]</code><code> self.speed = 1</code><code> self.active = True</code><code> self.rect.left, self.rect.top = randint(0, self.width - self.rect.width), randint(-10 * self.height, -self.height)</code><code> self.mask = pygame.mask.from_surface(self.image)</code><code> self.energy = MidEnemy.energy</code><code> self.hit = False</code><code></code><code> def move(self):</code><code> if self.rect.top < self.height:</code><code> self.rect.top += self.speed</code><code> else:</code><code> self.reset()</code><code></code><code> def reset(self):</code><code> self.active = True</code><code> self.energy = MidEnemy.energy</code><code> self.rect.left, self.rect.top = randint(0, self.width - self.rect.width), randint(-10 * self.height, -self.height)</code><code></code><code>class BigEnemy(pygame.sprite.Sprite):</code><code> energy = 20</code><code> def __init__(self, bg_size):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image1 = pygame.image.load("images/enemy3_n1.png").convert_alpha()</code><code> self.image2 = pygame.image.load("images/enemy3_n2.png").convert_alpha()</code><code> self.image_hit = pygame.image.load("images/enemy3_hit.png").convert_alpha()</code><code> self.destroy_images = []</code><code> self.destroy_images.extend([ \</code><code> pygame.image.load("images/enemy3_down1.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy3_down2.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy3_down3.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy3_down4.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy3_down5.png").convert_alpha(), \</code><code> pygame.image.load("images/enemy3_down6.png").convert_alpha() \</code><code> ])</code><code> self.rect = self.image1.get_rect()</code><code> self.width, self.height = bg_size[0], bg_size[1]</code><code> self.speed = 1</code><code> self.active = True</code><code> self.rect.left, self.rect.top = randint(0, self.width - self.rect.width), randint(-15 * self.height, -5 * self.height)</code><code> self.mask = pygame.mask.from_surface(self.image1)</code><code> self.energy = BigEnemy.energy</code><code> self.hit = False</code><code></code><code> def move(self):</code><code> if self.rect.top < self.height:</code><code> self.rect.top += self.speed</code><code> else:</code><code> self.reset()</code><code></code><code> def reset(self):</code><code> self.active = True</code><code> self.energy = BigEnemy.energy</code><code> self.rect.left, self.rect.top = randint(0, self.width - self.rect.width), randint(-15 * self.height, -5 * self.height)</code>4. Bullets
Bullet behavior is defined in bullet.py . Bullet1 is the normal bullet (single shot) and Bullet2 is the double‑bullet power‑up (two shots at once). Both classes handle image loading, position resetting, movement, and deactivation when leaving the screen.
<code>import pygame</code><code>class Bullet1(pygame.sprite.Sprite):</code><code> def __init__(self, position):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image = pygame.image.load("images/bullet1.png").convert_alpha()</code><code> self.rect = self.image.get_rect()</code><code> self.rect.left, self.rect.top = position</code><code> self.speed = 12</code><code> self.active = False</code><code> self.mask = pygame.mask.from_surface(self.image)</code><code></code><code> def move(self):</code><code> self.rect.top -= self.speed</code><code> if self.rect.top < 0:</code><code> self.active = False</code><code></code><code> def reset(self, position):</code><code> self.rect.left, self.rect.top = position</code><code> self.active = True</code><code></code><code>class Bullet2(pygame.sprite.Sprite):</code><code> def __init__(self, position):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image = pygame.image.load("images/bullet2.png").convert_alpha()</code><code> self.rect = self.image.get_rect()</code><code> self.rect.left, self.rect.top = position</code><code> self.speed = 14</code><code> self.active = False</code><code> self.mask = pygame.mask.from_surface(self.image)</code><code></code><code> def move(self):</code><code> self.rect.top -= self.speed</code><code> if self.rect.top < 0:</code><code> self.active = False</code><code></code><code> def reset(self, position):</code><code> self.rect.left, self.rect.top = position</code><code> self.active = True</code>5. Supplies
Power‑up items are defined in supply.py . Bullet_Supply provides the double‑bullet effect, while Bomb_Supply gives a full‑screen bomb. Both move downwards, become inactive when leaving the screen, and can be reset when collected.
<code>import pygame</code><code>from random import *</code><code>class Bullet_Supply(pygame.sprite.Sprite):</code><code> def __init__(self, bg_size):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image = pygame.image.load("images/bullet_supply.png").convert_alpha()</code><code> self.rect = self.image.get_rect()</code><code> self.width, self.height = bg_size[0], bg_size[1]</code><code> self.rect.left, self.rect.bottom = randint(0, self.width - self.rect.width), -100</code><code> self.speed = 5</code><code> self.active = False</code><code> self.mask = pygame.mask.from_surface(self.image)</code><code></code><code> def move(self):</code><code> if self.rect.top < self.height:</code><code> self.rect.top += self.speed</code><code> else:</code><code> self.active = False</code><code></code><code> def reset(self):</code><code> self.active = True</code><code> self.rect.left, self.rect.bottom = randint(0, self.width - self.rect.width), -100</code><code></code><code>class Bomb_Supply(pygame.sprite.Sprite):</code><code> def __init__(self, bg_size):</code><code> pygame.sprite.Sprite.__init__(self)</code><code> self.image = pygame.image.load("images/bomb_supply.png").convert_alpha()</code><code> self.rect = self.image.get_rect()</code><code> self.width, self.height = bg_size[0], bg_size[1]</code><code> self.rect.left, self.rect.bottom = randint(0, self.width - self.rect.width), -100</code><code> self.speed = 5</code><code> self.active = False</code><code> self.mask = pygame.mask.from_surface(self.image)</code><code></code><code> def move(self):</code><code> if self.rect.top < self.height:</code><code> self.rect.top += self.speed</code><code> else:</code><code> self.active = False</code><code></code><code> def reset(self):</code><code> self.active = True</code><code> self.rect.left, self.rect.bottom = randint(0, self.width - self.rect.width), -100</code>6. Main Module
The main.py script ties everything together: it initializes Pygame, loads graphics and sounds, creates sprite groups for the player, enemies, bullets, and supplies, and runs the main game loop. Inside the loop it processes events (quit, pause, fire, supply timers), updates positions, checks collisions, draws all objects, updates the score, adjusts difficulty, handles pause/resume, and shows the game‑over screen with high‑score persistence.
<code># main.py
import pygame
import sys
import traceback
import myplane
import enemy
import bullet
import supply
from pygame.locals import *
from random import *
pygame.init()
pygame.mixer.init()
bg_size = width, height = 480, 700
screen = pygame.display.set_mode(bg_size)
pygame.display.set_caption("飞机大战 -- FishC Demo")
background = pygame.image.load("images/background.png").convert()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
# load sounds ... (omitted for brevity)
def add_small_enemies(group1, group2, num):
for i in range(num):
e1 = enemy.SmallEnemy(bg_size)
group1.add(e1)
group2.add(e1)
def add_mid_enemies(group1, group2, num):
for i in range(num):
e2 = enemy.MidEnemy(bg_size)
group1.add(e2)
group2.add(e2)
def add_big_enemies(group1, group2, num):
for i in range(num):
e3 = enemy.BigEnemy(bg_size)
group1.add(e3)
group2.add(e3)
def inc_speed(target, inc):
for each in target:
each.speed += inc
def main():
pygame.mixer.music.play(-1)
me = myplane.MyPlane(bg_size)
enemies = pygame.sprite.Group()
small_enemies = pygame.sprite.Group()
add_small_enemies(small_enemies, enemies, 15)
mid_enemies = pygame.sprite.Group()
add_mid_enemies(mid_enemies, enemies, 4)
big_enemies = pygame.sprite.Group()
add_big_enemies(big_enemies, enemies, 2)
# create bullets, supplies, UI elements, timers ... (omitted for brevity)
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# handle pause, key presses, supply timers, etc.
# update game state, move sprites, check collisions, draw everything
pygame.display.flip()
clock.tick(60)
if __name__ == "__main__":
try:
main()
except SystemExit:
pass
except:
traceback.print_exc()
pygame.quit()
input()
</code>All modules should be placed in the same directory. Running main.py launches the complete aircraft war game. The full source code and assets are available at the GitHub repository: https://github.com/yangshangqi/The-Python-code-implements-aircraft-warfare .
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.