Skip to content
Related Articles

Related Articles

Improve Article
Save Article
Like Article

Building Space Invaders Using PyGame – Python

  • Last Updated : 22 Nov, 2021

In this article, we’re going to build space invaders using PyGame in Python. 

The used file can be downloaded from here.

Approach:

  • Import the required module.
  • Initialize the pygame.
  • Create three functions:
    • isCollision(): Which tells us whether the collision has occurred or not?
    • game_over(): Which returns True or False on the basis of which the code decided if the game has ended.
    • show_score(x, y): This shows the score on the screen
  • Create an infinite loop to execute the code continuously.

isCollision():

It’s very simple actually. Before explaining this, we want you to take a look at the collision portion of the code inside the game loop first below:

Python3




# Collision
collision = isCollision(bullet_X, invader_X[i], bullet_Y, invader_Y[i])
if collision:
        score_val += 1
        bullet_Y = 600
        bullet_state = "rest"
        invader_X[i] = random.randint(64, 736)
        invader_Y[i] = random.randint(30, 200)
        invader_Xchange[i] *= -1

The value returned by the “isCollision()” function is being stored inside the “collision” variable. The value returned by the function is either True or False based on the criteria set for collision inside the function. Let’s take a look at what is inside the isCollision() function:

Python3




def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2, 2)) + (math.pow(y1 - y2, 2)))
    if distance <= 50:
        return True
    else:
        return False

The criteria for collision set inside the function is the simplest thing as the distance between the bullet and the invader (our enemy). As you can see the formula used for calculating distance is something that every student study in their high school mathematics class. It’s the formula of the distance between two points having coordinates (x1, y1) and (x2, y2) which are being passed as parameters of the isCollision() function. 

Here, we have set the criteria that if the value of the distance is less than or equal to 50, then it means collision has occurred. The value is chosen on the basis of the height and width of the png image used for the bullet and the invader. The value can be tweaked as per your own requirements by using the trial and error method. 

So, whenever the position of the bullet and the invader changes then the isCollision() function checks if a collision has occurred or not. That is the reason why it is being called inside the game loop. 

game_over():

Which returns True or False on the basis of which the code decided if the game has ended. For understanding the game_over() function, let’s take a look at the below snippet of code which is present inside the game loop:

Python3




# movement of the invader
for i in range(no_of_invaders):
  
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break

Before getting into the explanation of code, it is recommended to know about the coordinate system followed in pygame. Take a look at the image below:

So, the criteria for game over is also collision. When the y-coordinate of the invader is greater than the spaceship i.e., 450 (y-coordinate of the spaceship), and the distance between the invader and the spaceship is less than 80 then a collision occurs and the game_over() function is called followed by the explosion sound. 

The following lines will make it more clear:

Python3




# y-coordinate of invader more than 450
if invader_Y[i] >= 450:
    
        # distance between the x-coordinate of invader
        # and spaceship
        if abs(player_X-invader_X[i]) < 80:
            #....... rest code .....#

The above is checked for all the invaders present in the game which is ensured by a for-loop at the starting.

show_score(x, y):

It shows the score on the screen.

Python3




def show_score(x, y):
    score = font.render("Points: " + str(score_val),
                        True, (255, 255, 255))
    screen.blit(score, (x, y))

The only thing show_score() function is doing is showing the score on the screen in a proper font selected by the user.  

Every time a collision between the bullet and the invaders is happening a variable “score_val” is being incremented. This variable is then being displayed on the screen by the show_score() function as can be seen in the above code snippet.  

Below is the implementation:

Python3




import pygame
import random
import math
from pygame import mixer
  
# initializing pygame
pygame.init()
  
# creating screen
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width,
                                  screen_height))
  
# caption and icon
pygame.display.set_caption("Welcome to Space\
Invaders Game by:- styles")
  
  
# Score
score_val = 0
scoreX = 5
scoreY = 5
font = pygame.font.Font('freesansbold.ttf', 20)
  
# Game Over
game_over_font = pygame.font.Font('freesansbold.ttf', 64)
  
  
def show_score(x, y):
    score = font.render("Points: " + str(score_val),
                        True, (255,255,255))
    screen.blit(score, (x , y ))
  
def game_over():
    game_over_text = game_over_font.render("GAME OVER",
                                           True, (255,255,255))
    screen.blit(game_over_text, (190, 250))
  
# Background Sound
mixer.music.load('data/background.wav')
mixer.music.play(-1)
  
# player
playerImage = pygame.image.load('data/spaceship.png')
player_X = 370
player_Y = 523
player_Xchange = 0
  
# Invader
invaderImage = []
invader_X = []
invader_Y = []
invader_Xchange = []
invader_Ychange = []
no_of_invaders = 8
  
for num in range(no_of_invaders):
    invaderImage.append(pygame.image.load('data/alien.png'))
    invader_X.append(random.randint(64, 737))
    invader_Y.append(random.randint(30, 180))
    invader_Xchange.append(1.2)
    invader_Ychange.append(50)
  
# Bullet
# rest - bullet is not moving
# fire - bullet is moving
bulletImage = pygame.image.load('data/bullet.png')
bullet_X = 0
bullet_Y = 500
bullet_Xchange = 0
bullet_Ychange = 3
bullet_state = "rest"
  
# Collision Concept
def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2,2)) +
                         (math.pow(y1 - y2,2)))
    if distance <= 50:
        return True
    else:
        return False
  
def player(x, y):
    screen.blit(playerImage, (x - 16, y + 10))
  
def invader(x, y, i):
    screen.blit(invaderImage[i], (x, y))
  
def bullet(x, y):
    global bullet_state
    screen.blit(bulletImage, (x, y))
    bullet_state = "fire"
  
# game loop
running = True
while running:
  
    # RGB
    screen.fill((0, 0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
  
        # Controling the player movement
        # from the arrow keys
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player_Xchange = -1.7
            if event.key == pygame.K_RIGHT:
                player_Xchange = 1.7
            if event.key == pygame.K_SPACE:
                
                # Fixing the change of direction of bullet
                if bullet_state is "rest":
                    bullet_X = player_X
                    bullet(bullet_X, bullet_Y)
                    bullet_sound = mixer.Sound('data/bullet.wav')
                    bullet_sound.play()
        if event.type == pygame.KEYUP:
            player_Xchange = 0
  
    # adding the change in the player position
    player_X += player_Xchange
    for i in range(no_of_invaders):
        invader_X[i] += invader_Xchange[i]
  
    # bullet movement
    if bullet_Y <= 0:
        bullet_Y = 600
        bullet_state = "rest"
    if bullet_state is "fire":
        bullet(bullet_X, bullet_Y)
        bullet_Y -= bullet_Ychange
  
    # movement of the invader
    for i in range(no_of_invaders):
          
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break
  
        if invader_X[i] >= 735 or invader_X[i] <= 0:
            invader_Xchange[i] *= -1
            invader_Y[i] += invader_Ychange[i]
        # Collision
        collision = isCollision(bullet_X, invader_X[i],
                                bullet_Y, invader_Y[i])
        if collision:
            score_val += 1
            bullet_Y = 600
            bullet_state = "rest"
            invader_X[i] = random.randint(64, 736)
            invader_Y[i] = random.randint(30, 200)
            invader_Xchange[i] *= -1
  
        invader(invader_X[i], invader_Y[i], i)
  
  
    # restricting the spaceship so that
    # it doesn't go out of screen
    if player_X <= 16:
        player_X = 16;
    elif player_X >= 750:
        player_X = 750
  
  
    player(player_X, player_Y)
    show_score(scoreX, scoreY)
    pygame.display.update()

Output:


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!