Space Invaders with Pygame Zero and Phidgets

Pygame Zero allows you to create simple games in Python. In this project, you will modify a Space Invaders game to use the buttons from your Getting Started Kit and a Thumbstick Phidget!

Prerequisites

You should review the following before moving on:

Setup

All you need for this project is the Getting Started Kit.

Getting Started Kit

Install Pygame Zero

In order to use Pygame Zero, you first have to install it. You do this in the same way you previously installed the Phidget22 library. Simply navigate to your package manager, search for pgzero and press install!

Thonny

If you're using Thonny, select Tools > Manage Packages and search for pgzero.

PyCharm

If you're using PyCharm, select File > Settings > Python Interpreter and use the + symbol to install pgzero.

PyScripter

If you're using PyScripter, select Tools > Tools > Install Packages with pip and enter pgzero.

Create Project Structure

Create a python script called space_invaders.py in a location of your choice. Download the required images and place them in a folder called images in the same location as your python file.

Write code (Python)

Copy the code below into your python script spaceinvaders.py.

  
#Add Phidgets Library
from Phidget22.Phidget import *
from Phidget22.Devices.VoltageRatioInput import *
from Phidget22.Devices.DigitalInput import *

import pgzrun
from random import randint
import math
DIFFICULTY = 1
player = Actor("player", (400, 550)) # Load in the player Actor image

def draw(): # Pygame Zero draw function
    screen.blit('background', (0, 0))
    player.image = player.images[math.floor(player.status/6)]
    player.draw()
    drawLasers()
    drawAliens()
    drawBases()
    screen.draw.text(str(score) , topright=(780, 10), owidth=0.5, ocolor=(255,255,255), color=(0,64,255) , fontsize=60)
    if player.status >= 30:
        screen.draw.text("GAME OVER\nPress Enter to play again" , center=(400, 300), owidth=0.5, ocolor=(255,255,255), color=(255,64,0) , fontsize=60)
    if len(aliens) == 0 :
        screen.draw.text("YOU WON!\nPress Enter to play again" , center=(400, 300), owidth=0.5, ocolor=(255,255,255), color=(255,64,0) , fontsize=60)
        
def update(): # Pygame Zero update function
    global moveCounter,player
    if player.status < 30 and len(aliens) > 0:
        checkThumbstick() #Check Phidgets Thumbstick
        updateLasers()
        moveCounter += 1
        if moveCounter == moveDelay:
            moveCounter = 0
            updateAliens() 
        if player.status > 0: player.status += 1
    else:
        if keyboard.RETURN: init()

def drawAliens():
    for a in range(len(aliens)): aliens[a].draw()

def drawBases():
    for b in range(len(bases)): bases[b].drawClipped()

def drawLasers():
    for l in range(len(lasers)): lasers[l].draw()

#Phidgets Code Start
def checkThumbstick():
    global player
    if (horizontal.getVoltageRatio() < -0.2):
        if (player.x > 40):
            player.x-=5
    if (horizontal.getVoltageRatio() > 0.2):
        if (player.x < 760):
            player.x+=5
#Phidgets Code End            

def makeLaserActive():
    global player
    player.laserActive = 1
            
def checkBases():
    for b in range(len(bases)):
        if l < len(bases):
            if bases[b].height < 5:
                del bases[b]

def updateLasers():
    global lasers, aliens
    for l in range(len(lasers)):
        if lasers[l].type == 0:
            lasers[l].y += (2*DIFFICULTY)
            checkLaserHit(l)
            if lasers[l].y > 600: lasers[l].status = 1
        if lasers[l].type == 1:
            lasers[l].y -= 5
            checkPlayerLaserHit(l)
            if lasers[l].y < 10: lasers[l].status = 1
    lasers = listCleanup(lasers)
    aliens = listCleanup(aliens)

def listCleanup(l):
    newList = []
    for i in range(len(l)):
        if l[i].status == 0: newList.append(l[i])
    return newList
    
def checkLaserHit(l):
    global player
    if player.collidepoint((lasers[l].x, lasers[l].y)):
        player.status = 1
        lasers[l].status = 1
    for b in range(len(bases)):
        if bases[b].collideLaser(lasers[l]):
            bases[b].height -= 10
            lasers[l].status = 1

def checkPlayerLaserHit(l):
    global score
    for b in range(len(bases)):
        if bases[b].collideLaser(lasers[l]): lasers[l].status = 1
    for a in range(len(aliens)):
        if aliens[a].collidepoint((lasers[l].x, lasers[l].y)):
            lasers[l].status = 1
            aliens[a].status = 1
            score += 1000
            
def updateAliens():
    global moveSequence, lasers, moveDelay
    movex = movey = 0
    if moveSequence < 10 or moveSequence > 30: movex = -15
    if moveSequence == 10 or moveSequence == 30:
        movey = 50 + (10 * DIFFICULTY)
        moveDelay -= 1
    if moveSequence >10 and moveSequence < 30: movex = 15
    for a in range(len(aliens)):
        animate(aliens[a], pos=(aliens[a].x + movex, aliens[a].y + movey), duration=0.5, tween='linear')
        if randint(0, 1) == 0:
            aliens[a].image = "alien1"
        else:
            aliens[a].image = "alien1b"
            if randint(0, 5) == 0:
                lasers.append(Actor("laser1", (aliens[a].x,aliens[a].y)))
                lasers[len(lasers)-1].status = 0
                lasers[len(lasers)-1].type = 0
        if aliens[a].y > player.y and player.status == 0:
            player.status = 1
    moveSequence +=1
    if moveSequence == 40: moveSequence = 0

def init():
    global lasers, score, player, moveSequence, moveCounter, moveDelay
    initAliens()
    initBases()
    moveCounter = moveSequence = player.status = score = player.laserCountdown = 0
    lasers = []
    moveDelay = 30
    player.images = ["player","explosion1","explosion2","explosion3","explosion4","explosion5"]
    player.laserActive = 1

def initAliens():
    global aliens
    aliens = []
    for a in range(18):
        aliens.append(Actor("alien1", (210+(a % 6)*80,100+(int(a/6)*64))))
        aliens[a].status = 0

def drawClipped(self):
    screen.surface.blit(self._surf, (self.x-32, self.y-self.height+30),(0,0,64,self.height))

def collideLaser(self, other):
    return (
        self.x-20 < other.x+5 and
        self.y-self.height+30 < other.y and
        self.x+32 > other.x+5 and
        self.y-self.height+30 + self.height > other.y
    )

def initBases():
    global bases
    bases = []
    bc = 0
    for b in range(3):
        for p in range(3):
            bases.append(Actor("base1", midbottom=(150+(b*200)+(p*40),520)))
            bases[bc].drawClipped = drawClipped.__get__(bases[bc])
            bases[bc].collideLaser = collideLaser.__get__(bases[bc])
            bases[bc].height = 60
            bc +=1

#Phidgets Code Start
#Event
def onRedButton_StateChange(self, state):
    global player, lasers
    if (state):
        if (player.laserActive == 1):
            player.laserActive = 0
            clock.schedule(makeLaserActive, 1.0)
            l = len(lasers)
            lasers.append(Actor("laser2", (player.x,player.y-32)))
            lasers[l].status = 0
            lasers[l].type = 1

#Create
redButton = DigitalInput()
horizontal = VoltageRatioInput()

#Address
redButton.setHubPort(0)
redButton.setIsHubPortDevice(True)
horizontal.setChannel(1)

#Subscribe to Events
redButton.setOnStateChangeHandler(onRedButton_StateChange)

#Open
redButton.openWaitForAttachment(1000)
horizontal.openWaitForAttachment(1000)

#Set data interval to minimum
horizontal.setDataInterval(horizontal.getMinDataInterval())
#Phidgets Code End
    
init()
pgzrun.go()
  

Run Your Program

When you move your Thumbstick Phidget, your spaceship will move. When you press the red button, a laser will be fired.

Code Review

In this example, the Thumbstick Phidget is being used instead of the left and right keys, and the red button is used instead of the spacebar. You can view the original code here to compare

Practice

  1. Add new functionality to your game using the green button. Some examples may be pausing the game, ending the game, speeding the game up, slowing the game down, etc.

What are Phidgets?

Phidgets are programmable USB sensors. Simply plug in your sensor, write code in your favorite language and go!

Phidgets have been used by STEM professionals for over 20 years and are now available to students.

Learn more

Set your preferences

Windows

Mac OS

Raspberry Pi

Java

Python

C#

Swift

NetBeans

Processing

Eclipse

Thonny

PyCharm

PyScripter

Visual Studio

Xcode

Setting your preferred operating system, programming language and environment lets us display relevant code samples for the Getting Started Tutorial, Device Tutorials and Projects

Done