piman2

The game screen appears here if your browser supports the Canvas API.

Attribution

Retro Gaming with Raspberry Pi 2nd Edition, pages 114 - 122.

Retro Gaming with Raspberry Pi, pages 90 - 98.

Licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported.

Original Python code


import pgzrun
from pygame import joystick, key
from pygame.locals import *
from pygame import image, surface, Color
from random import randint
from datetime import datetime

joystick.init()
joystick_count = joystick.get_count()

if(joystick_count > 0):
    joyin = joystick.Joystick(0)
    joyin.init()

def checkInput(p):
    global joyin, joystick_count
    xaxis = yaxis = 0
    if p.status == 0:
        if joystick_count > 0:
            xaxis = joyin.get_axis(0)
            yaxis = joyin.get_axis(1)
        if key.get_pressed()[K_LEFT] or xaxis < -0.8:
            p.angle = 180
            p.movex = -20
        if key.get_pressed()[K_RIGHT] or xaxis > 0.8:
            p.angle = 0
            p.movex = 20
        if key.get_pressed()[K_UP] or yaxis < -0.8:
            p.angle = 90
            p.movey = -20
        if key.get_pressed()[K_DOWN] or yaxis > 0.8:
            p.angle = 270
            p.movey = 20
    if joystick_count > 0:
        jb = joyin.get_button(1)
    else:
        jb = 0
    if p.status == 1:
        if key.get_pressed()[K_RETURN] or jb:
            return 1
    if p.status == 2:
        if key.get_pressed()[K_RETURN] or jb:
            return 1

moveimage = image.load('images/pimanmovemap.png')
dotimage = image.load('images/pimandotmap.png')

def checkMovePoint(p):
    global moveimage
    if p.x+p.movex < 0: p.x = p.x+600
    if p.x+p.movex > 600: p.x = p.x-600
    if moveimage.get_at((int(p.x+p.movex), int(p.y+p.movey-80))) != Color('black'):
        p.movex = p.movey = 0

def checkDotPoint(x,y):
    global dotimage
    if dotimage.get_at((int(x), int(y))) == Color('black'):
        return 1
    if dotimage.get_at((int(x), int(y))) == Color('red'):
        return 2
    return False

def getPossibleDirection(g):
    global moveimage
    if g.x-20 < 0:
        g.x = g.x+600
    if g.x+20 > 600:
        g.x = g.x-600
    directions = [0,0,0,0]
    if g.x+20 < 600:
        if moveimage.get_at((int(g.x+20), int(g.y-80))) == Color('black'): directions[0] = 1
    if g.x < 600 and g.x >= 0:
        if moveimage.get_at((int(g.x), int(g.y-60))) == Color('black'): directions[1] = 1
    if g.x-20 >= 0:
        if moveimage.get_at((int(g.x-20), int(g.y-80))) == Color('black'): directions[2] = 1
    if g.x < 600 and g.x >= 0:
        if moveimage.get_at((int(g.x), int(g.y-100))) == Color('black'): directions[3] = 1
    return directions

WIDTH = 600
HEIGHT = 660

player = Actor("piman_o") # Load in the player Actor image
player.score = 0
player.lives = 3
level = 0
SPEED = 3

def draw(): # Pygame Zero draw function
    global piDots, player
    screen.blit('header', (0, 0))
    screen.blit('colourmap', (0, 80))
    piDotsLeft = 0
    for a in range(len(piDots)):
        if piDots[a].status == 0:
            piDots[a].draw()
            piDotsLeft += 1
        if piDots[a].collidepoint((player.x, player.y)):
            if piDots[a].status == 0:
                if piDots[a].type == 2:
                    for g in range(len(flames)): flames[g].status = 1200
                else:
                    player.score += 10
            piDots[a].status = 1
    if piDotsLeft == 0: player.status = 2
    drawFlames()
    getPlayerImage()
    player.draw()
    drawLives()
    screen.draw.text("LEVEL "+str(level) , topleft=(10, 10), owidth=0.5, ocolor=(0,0,255), color=(255,255,0) , fontsize=40)
    screen.draw.text(str(player.score) , topright=(590, 20), owidth=0.5, ocolor=(255,255,255), color=(0,64,255) , fontsize=60)
    if player.status == 3: drawCentreText("GAME OVER")
    if player.status == 2: drawCentreText("LEVEL CLEARED!\nPress Enter or Button A\nto Continue")
    if player.status == 1: drawCentreText("CAUGHT!\nPress Enter or Button A\nto Continue")


def drawCentreText(t):
    screen.draw.text(t , center=(300, 434), owidth=0.5, ocolor=(255,255,255), color=(255,64,0) , fontsize=60)

def update(): # Pygame Zero update function
    global player, moveFlamesFlag, flames
    if player.status == 0:
        if moveFlamesFlag == 4: moveFlames()
        for g in range(len(flames)):
            if flames[g].status > 0: flames[g].status -= 1
            if flames[g].collidepoint((player.x, player.y)):
                if flames[g].status > 0:
                    player.score += 100
                    animate(flames[g], pos=(290, 370), duration=1/SPEED, tween='linear', on_finished=flagMoveFlames)
                else:
                    player.lives -= 1
                    sounds.pi2.play()
                    if player.lives == 0:
                        player.status = 3
                        music.fadeout(3)
                    else:
                        player.status = 1
        if player.inputActive:
            checkInput(player)
            checkMovePoint(player)
            if player.movex or player.movey:
                inputLock()
                sounds.pi1.play()
                animate(player, pos=(player.x + player.movex, player.y + player.movey), duration=1/SPEED, tween='linear', on_finished=inputUnLock)
    if player.status == 1:
        i = checkInput(player)
        if i == 1:
            player.status = 0
            player.x = 290
            player.y = 570
    if player.status == 2:
        i = checkInput(player)
        if i == 1:
            init()

def init():
    global player, level
    initDots()
    initFlames()
    player.x = 290
    player.y = 570
    player.status = 0
    inputUnLock()
    level += 1
    music.play("pm1")
    music.set_volume(0.2)

def drawLives():
    for l in range(player.lives): screen.blit("piman_o", (10+(l*32),40))

def getPlayerImage():
    global player
    dt = datetime.now()
    a = player.angle
    tc = dt.microsecond%(500000/SPEED)/(100000/SPEED)
    if tc > 2.5 and (player.movex != 0 or player.movey !=0):
        if a != 180:
            player.image = "piman_c"
        else:
            player.image = "piman_cr"
    else:
        if a != 180:
            player.image = "piman_o"
        else:
            player.image = "piman_or"
    player.angle = a

def drawFlames():
    for g in range(len(flames)):
        if flames[g].x > player.x:
            if flames[g].status > 200 or (flames[g].status > 1 and flames[g].status%2 == 0):
                flames[g].image = "flame"+str(g+1)+"-"
            else:
                flames[g].image = "flame"+str(g+1)+"r"
        else:
            if flames[g].status > 200 or (flames[g].status > 1 and flames[g].status%2 == 0):
                flames[g].image = "flame"+str(g+1)+"-"
            else:
                flames[g].image = "flame"+str(g+1)
        flames[g].draw()

def moveFlames():
    global moveFlamesFlag
    dmoves = [(1,0),(0,1),(-1,0),(0,-1)]
    moveFlamesFlag = 0
    for g in range(len(flames)):
        dirs = getPossibleDirection(flames[g])
        if inTheCentre(flames[g]):
            flames[g].dir = 3
        else:
            if g == 0: followPlayer(g, dirs)
            if g == 1: ambushPlayer(g, dirs)

        if dirs[flames[g].dir] == 0 or randint(0,50) == 0:
            d = -1
            while d == -1:
                rd = randint(0,3)
                if aboveCentre(flames[g]) and rd == 1:
                    rd = 0
                if dirs[rd] == 1:
                    d = rd
            flames[g].dir = d
        animate(flames[g], pos=(flames[g].x + dmoves[flames[g].dir][0]*20, flames[g].y + dmoves[flames[g].dir][1]*20), duration=1/SPEED, tween='linear', on_finished=flagMoveFlames)

def followPlayer(g, dirs):
    d = flames[g].dir
    if d == 1 or d == 3:
        if player.x > flames[g].x and dirs[0] == 1: flames[g].dir = 0
        if player.x < flames[g].x and dirs[2] == 1: flames[g].dir = 2
    if d == 0 or d == 2:
        if player.y > flames[g].y and dirs[1] == 1 and not aboveCentre(flames[g]): flames[g].dir = 1
        if player.y < flames[g].y and dirs[3] == 1: flames[g].dir = 3


def ambushPlayer(g, dirs):
    d = flames[g].dir
    if player.movex > 0 and dirs[0] == 1: flames[g].dir = 0
    if player.movex < 0 and dirs[2] == 1: flames[g].dir = 2

    if player.movey > 0 and dirs[1] == 1 and not aboveCentre(flames[g]): flames[g].dir = 1
    if player.movey < 0 and dirs[3] == 1: flames[g].dir = 3

def inTheCentre(ga):
    if ga.x > 220 and ga.x < 380 and ga.y > 320 and ga.y < 420:
        return True
    return False

def aboveCentre(ga):
    if ga.x > 220 and ga.x < 380 and ga.y > 300 and ga.y < 320:
        return True
    return False

def flagMoveFlames():
    global moveFlamesFlag
    moveFlamesFlag += 1

def flameCollided(ga,gn):
    for g in range(len(flames)):
        if flames[g].colliderect(ga) and g != gn:
            return True
    return False

def initDots():
    global piDots
    piDots = []
    a = x = 0
    while x < 30:
        y = 0
        while y < 29:
            d = checkDotPoint(10+x*20, 10+y*20)
            if d == 1:
                piDots.append(Actor("dot",(10+x*20, 90+y*20)))
                piDots[a].status = 0
                piDots[a].type = 1
                a += 1
            if d == 2:
                piDots.append(Actor("power",(10+x*20, 90+y*20)))
                piDots[a].status = 0
                piDots[a].type = 2
                a += 1
            y += 1
        x += 1

def initFlames():
    global flames, moveFlamesFlag
    moveFlamesFlag = 4
    flames = []
    g = 0
    while g < 4:
        flames.append(Actor("flame"+str(g+1),(270+(g*20), 370)))
        flames[g].dir = randint(0, 3)
        flames[g].status = 0
        g += 1

def inputLock():
    global player
    player.inputActive = False

def inputUnLock():
    global player
    player.movex = player.movey = 0
    player.inputActive = True

init()
pgzrun.go()