import pygame # may need to install:  pip install pygame
import os # needed to get paths to images
import math

#get path to our game
myPath = os.path.dirname( os.path.realpath( __file__ ) )

#Set up the screen
screenW = 800
screenH = 600
screen = pygame.display.set_mode( (screenW, screenH) )

# Title
pygame.display.set_caption("Space Invaders")

#background
background = pygame.image.load( os.path.join( myPath, "images\\background.png") )

# player
playerImg = pygame.image.load( os.path.join( myPath, "images\\player.png" ) )
playerW = 64
playerH = 64
playerX = screenW / 2 - playerW / 2 # half screen width - half player width
playerY = 480
playerX_change = 0 # how far to move the player
player_state = "alive"
num_enemies = 20 # how many enemies to spawn
wave = 1
score = 0

# Enemy Class
class Enemy:
    def __init__(self, x, y):
        self.Img = pygame.image.load( os.path.join( myPath, "images\\enemy.png" ) )
        self.width = 64
        self.height = 64
        self.X = x
        self.Y = y
        self.X_change = 2 # how far to move the enemy
        self.Y_change = self.height


#Create a list of enemies from the Enemy Class
# enemies = [ Enemy(10, 30), Enemy(100, 30), Enemy(200, 30),
#             Enemy(10, 100), Enemy(100, 100), Enemy(200, 100)]

# Bullet
bulletImg = pygame.image.load( os.path.join( myPath, "images\\bullet.png" ) )
bulletX = 0
bulletY = 0
bulletY_change = -3
bullet_state = "ready"

def draw_sprite( sprite, x, y ):
    x = int(x)
    y = int(y)
    screen.blit( sprite, ( x, y ) ) # blit basically means draw

def fire_bullet( x, y ):
    global bullet_state, bulletX, bulletY
    bullet_state = "fire"
    bulletX = x
    bulletY = y

def isCollision(x1, y1, x2, y2):
    hypotenuse = math.sqrt( math.pow(x1 - x2, 2 ) + math.pow(y1 - y2, 2) ) # pythagoras theorum
    if hypotenuse < 64 :
        return True
    else:
        return False

def init( enemies, amount ):
    for e in range( amount ): # loop for the number of times provided
        enemies.append( Enemy(0,0) ) # Add a new enemy to the list at 0,0
        # current enemy * width * a bit for a gap - max 10 enemies per row
        enemies[e].X = e % 10 * enemies[e].width * 1.1
        enemies[e].Y = math.floor( e / 10 ) * ( enemies[e].height + enemies[e].Y_change )

    #return enemies

# create enemies using the init method
enemies = []
init( enemies, num_enemies )

# game loop
running = True
while running:
    # need to clear the screen and set the background before drawing any sprites
    screen.fill((0,0,0))
    screen.blit( background, (0,0) )

    for event in pygame.event.get():  # get all python events and loop through them
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                playerX_change = -2
            if event.key == pygame.K_RIGHT:
                playerX_change = 2
            if event.key == pygame.K_SPACE:
                if bullet_state == "ready":
                    fire_bullet( playerX + 64 / 2 - 32 / 2, playerY )

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                playerX_change = 0

    playerX += playerX_change
    if playerX <= 0: # if player tries to move too far left
        playerX = 0
    if playerX >= 800 - 64: # if the player moves too far right
        playerX = 800 - 64

    # Loop though all the enemy objects in the list
    for e in enemies:
        e.X += e.X_change # Move the enemy
        if e.X <= 0: # if enemy tries to move too far left
            e.X_change = e.X_change * -1 
            e.Y += e.Y_change
        if e.X >= 800 - e.width: # if the enemy moves too far right
            e.X_change = e.X_change * -1
            e.Y += e.Y_change
        draw_sprite(e.Img, e.X, e.Y) # draw the enemy
        
        #test collisions
        collision = isCollision(e.X + e.width / 2, e.Y + e.width / 2, bulletX + 32 / 2, bulletY + 32 /2 )
        if collision and bullet_state == "fire":
            enemies.remove( e )
            bullet_state = "ready"
            score += 1
            print( score )

    #bullet movement
    if bullet_state == "fire":
        bulletY += bulletY_change

        if bulletY <= 0:
            bullet_state = "ready"
    
    draw_sprite(playerImg, playerX, playerY) # draw the player 
    
    # if the players bullet is firing, draw it
    if bullet_state == "fire":
        draw_sprite(bulletImg, bulletX, bulletY)

    pygame.display.update() # needed to apply the change

Last modified: Thursday, 10 December 2020, 3:32 PM