Listing30_FinalGame
Attribution
Make your own retro platformer, pages 50-55, by Jordi Sontanja.
Licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported.
Original Python code
# Player movement prototype program:
# - Cursor left-right: move player
# - Cursor up: player jump
# - Space: shoot a rainbow
import pgzrun
from pgzero.builtins import Actor
from shapely.geometry import LineString, Polygon
from shapely.affinity import translate
import math
from random import randint
platformNames = ['platform_rock_1', 'platform_rock_2', 'platform_rock_3', 'platform_rock_4',
'platform_grass_1', 'platform_grass_2', 'platform_grass_3', 'platform_grass_4',
'platform_tree_1', 'platform_tree_2', 'platform_tree_3', 'platform_tree_4', 'platform_tree_5',
'platform_cloud_1', 'platform_cloud_2', 'platform_cloud_3']
platformLines = [[(-194, -23), (-182, -32), (-138, -35), (-104, -38), (-80, -43), (-15, -34), (34, -36), (59, -42), (93, -37), (126, -28), (181, -26), (192, -24)],
[(-134, -25), (-98, -31), (-37, -37), (25, -35), (98, -34), (131, -25)], [(-59, -10), (-29, -27), (-1, -34), (36, -29), (56, -15)],
[(-174, -19), (-137, -35), (-93, -34), (-1, -28), (78, -38), (171, -30)], [(-145, -8), (-129, -22), (-89, -37), (-18, -29), (52, -36), (104, -28), (146, -8)],
[(-153, -8), (-131, -16), (-100, -16), (-22, -10), (44, -16), (95, -8), (150, -1)],
[(-166, -12), (-152, -23), (-97, -29), (-22, -17), (24, -18), (82, -29), (142, -25), (166, -17)], [(-51, 1), (-39, -12), (-13, -21), (22, -22), (51, -9)],
[(-166, -38), (-135, -46), (-96, -40), (-62, -20), (-30, 9), (-8, 20), (16, 25), (92, 16), (145, 18), (166, 23)],
[(-165, 10), (-110, -5), (-66, -21), (-23, -41), (16, -51), (63, -51), (124, -29), (162, -25)],
[(-47, -9), (-5, -25), (66, -30)], [(-134, -18), (-84, 2), (-57, 1), (25, -20), (62, -18), (85, -12), (133, -14)],
[(-147, -45), (-122, -48), (-66, -59), (-21, -58), (18, -42), (53, -13), (109, 13), (143, 20)],
[(-114, -4), (-82, -14), (-39, -17), (-12, -33), (37, -35), (52, -22), (87, -18), (113, -8)],
[(-158, -4), (-119, -8), (-72, -23), (-45, -19), (-4, -35), (24, -23), (61, -22), (84, -8), (130, -11), (159, 1)],
[(-237, -5), (-216, -15), (-168, -14), (-139, -29), (-92, -27), (-49, -42), (7, -21), (31, -40), (61, -41), (84, -22), (141, -33), (180, -12), (237, 1)]]
platforms = [(3,676,599),(3,403,597),(3,90,599),(0,663,433),(0,119,429),(0,121,273),(0,654,278),(1,386,122),
(3,243,-23),(3,547,-25),(3,391,-203),(2,98,-337),(2,684,-339),(2,289,-403),(2,505,-404),(2,90,-537),
(2,684,-546),(1,391,-594),(6,147,-728),(6,454,-731),(6,697,-736),(6,258,-878),(6,559,-878),(6,109,-1039),
(6,704,-1036),(5,400,-1219),(7,113,-1335),(7,708,-1334),(6,400,-1439),(7,166,-1533),(7,647,-1535),
(4,396,-1622),(7,110,-1719),(7,680,-1729),(6,119,-1841),(6,676,-1833),(4,402,-1983),(6,128,-2144),
(6,429,-2146),(6,720,-2149),(9,153,-2310),(11,677,-2302),(12,665,-2511),(8,161,-2536),(10,131,-2594),
(11,687,-2701),(9,154,-2779),(12,660,-2841),(10,700,-2919),(10,284,-2851),(15,219,-3039),(15,659,-3036),
(14,192,-3219),(14,618,-3221),(14,397,-3378),(13,125,-3501),(13,668,-3511),(14,396,-3614),(15,120,-3774),
(15,690,-3766),(13,409,-3921),(14,181,-4025),(14,645,-4034),(14,404,-4173),(15,183,-4361),(15,621,-4356),]
maxHeightPlatform = 124
class AllPlatforms():
def __init__(self):
self.platformActors = [Actor(platformNames[platforms[i][0]], (platforms[i][1], platforms[i][2])) for i in range(len(platforms))]
self.platformLineStrings = []
for i in range(len(platforms)):
points = [(platformLines[platforms[i][0]][j][0] + platforms[i][1],
platformLines[platforms[i][0]][j][1] + platforms[i][2])
for j in range(len(platformLines[platforms[i][0]]))]
self.platformLineStrings.append(LineString(points))
def draw(self):
for platform in self.platformActors:
if platform.y > -maxHeightPlatform/2 and platform.y < 600+maxHeightPlatform/2:
platform.draw()
def update(self, screenPosition):
for i in range(len(platforms)):
self.platformActors[i].x = platforms[i][1]
self.platformActors[i].y = platforms[i][2] - screenPosition
def getMaxScreenPosition(self):
return -platforms[-1][2] - maxHeightPlatform/2
def RectanglesIntersect(centreA, halfSizeA, centreB, halfSizeB):
if centreA[0] - halfSizeA[0] < centreB[0] + halfSizeB[0] and centreA[0] + halfSizeA[0] > centreB[0] - halfSizeB[0]:
if centreA[1] - halfSizeA[1] < centreB[1] + halfSizeB[1] and centreA[1] + halfSizeA[1] > centreB[1] - halfSizeB[1]:
return True
return False
rainbowHalfSize = 39
rainbowTimeLife = 200
class Rainbow:
def __init__(self, centreX, centreY, creationTime):
self.centre = [centreX, centreY]
self.timeFromCreation = creationTime
self.rainbowActor = Actor('rainbow', (centreX, centreY - rainbowHalfSize/2))
points = []
for i in range(0, 180+20, 20):
points.append((self.centre[0] + rainbowHalfSize*math.cos(math.pi*i/180)*0.75, self.centre[1] - rainbowHalfSize*math.sin(math.pi*i/180)))
self.lineString = LineString(points)
def draw(self, screenPosition):
if self.timeFromCreation >= 0:
self.rainbowActor.y = self.centre[1] - rainbowHalfSize/2 - screenPosition
self.rainbowActor.draw()
def update(self, allEnemies, allCollectables):
if self.timeFromCreation == 0:
for i in reversed(range(len(allEnemies.enemies))):
if self.lineString.intersects(allEnemies.enemies[i].lineString):
allEnemies.killEnemy(i, allCollectables)
self.timeFromCreation += 1
rainbowAccelerationDown = 1
class FallingRainbow:
def __init__(self, centreX, centreY):
self.centre = [centreX, centreY]
self.rainbowActor = Actor('falling_rainbow', (centreX, centreY - rainbowHalfSize/2))
self.speedY = 0
def draw(self, screenPosition):
self.rainbowActor.y = self.centre[1] - rainbowHalfSize/2 - screenPosition
self.rainbowActor.draw()
def update(self, allEnemies, allRainbows, allCollectables):
self.speedY += rainbowAccelerationDown
self.centre[1] += self.speedY
centerCollision = [self.centre[0], self.centre[1] + self.speedY * 2]
halfSizeCollision = [rainbowHalfSize, (rainbowHalfSize + self.speedY) / 2]
for i in reversed(range(len(allEnemies.enemies))):
if RectanglesIntersect(centerCollision, halfSizeCollision, allEnemies.enemies[i].centre, [allEnemies.enemyHalfSize(), allEnemies.enemyHalfSize()]):
allEnemies.killEnemy(i, allCollectables)
for i in reversed(range(len(allRainbows.rainbows))):
if RectanglesIntersect(centerCollision, halfSizeCollision, allRainbows.rainbows[i].centre, [rainbowHalfSize, rainbowHalfSize/2]):
allRainbows.rainbowFall(i)
class AllRainbows:
def __init__(self):
self.rainbows = []
self.fallingRainbows = []
def restart(self):
self.rainbows = []
self.fallingRainbows = []
def draw(self, screenPosition):
for rainbow in self.rainbows:
rainbow.draw(screenPosition)
for fallingRainbow in self.fallingRainbows:
fallingRainbow.draw(screenPosition)
def update(self, allEnemies, allCollectables, screenPosition):
for i in reversed(range(len(self.rainbows))):
self.rainbows[i].update(allEnemies, allCollectables)
if self.rainbows[i].timeFromCreation > rainbowTimeLife:
self.rainbowFall(i)
for i in reversed(range(len(self.fallingRainbows))):
self.fallingRainbows[i].update(allEnemies, self, allCollectables)
if self.fallingRainbows[i].centre[1]-screenPosition-rainbowHalfSize > 600:
del self.fallingRainbows[i]
def rainbowFall(self, index):
self.fallingRainbows.append(FallingRainbow(self.rainbows[index].centre[0], self.rainbows[index].centre[1]))
del self.rainbows[index]
def append(self, posX, posY, time):
self.rainbows.append(Rainbow(posX, posY, time))
def addRainbows(self, numberOfRainbows, posX, posY, directionX):
for i in range(numberOfRainbows):
self.append(posX + directionX * rainbowHalfSize + directionX * i * (rainbowHalfSize-2)*2, posY, -i*10)
enemyNames = [['green_worm_right', 'green_worm_left'],
['red_worm_right', 'red_worm_left'],
['bee_1_right', 'bee_1_left',
'bee_2_right', 'bee_2_left',
'bee_3_right', 'bee_3_left']]
enemies = [(0,1,111,379),(0,-1,645,227),(0,-1,383,69),(0,-1,228,-67),(0,1,548,-69),(0,1,387,-247),(0,1,378,-647),(0,1,449,-921),
(0,-1,334,-920),(1,-1,218,-1083),(1,1,603,-1080),(0,-1,396,-1247),(0,1,399,-1473),(0,-1,390,-1666),(0,-1,343,-2033),
(0,-1,457,-2034),(0,1,74,-1879),(0,1,174,-1880),(0,-1,619,-1874),(0,-1,737,-1876),(1,-1,196,-2379),(1,1,717,-2339),
(0,-1,181,-2640),(0,-1,333,-2896),(2,-1,623,-2798),(2,1,169,-2724),(2,1,132,-3378),(2,-1,675,-3376),(2,-1,674,-3624),
(2,1,120,-3621),(2,1,136,-3914),(2,-1,647,-3930),(2,1,132,-4189),(2,-1,690,-4193),(1,1,57,-3536),(1,-1,743,-3552),
(1,-1,779,-3814),(1,1,23,-3826),(1,-1,393,-4229),(1,1,414,-4228)]
enemyHalfSize = 12
enemyAccelerationDown = 0.5
enemyTerminalSpeed = 8
enemyLateralSpeed = 2
enemyFlyingVerticalSpeed = 1
class Enemy:
def __init__(self, centreX, centreY, indexEnemy, directionX):
self.centre = [centreX, centreY]
self.centredLineString = LineString([(-enemyHalfSize,-enemyHalfSize),
(-enemyHalfSize,enemyHalfSize),
(enemyHalfSize,enemyHalfSize),
(enemyHalfSize,-enemyHalfSize)])
self.lineString = translate(self.centredLineString, self.centre[0], self.centre[1])
self.speedX = directionX * enemyLateralSpeed
self.speedY = 0
if indexEnemy == 2:
self.speedY = enemyFlyingVerticalSpeed
self.index = indexEnemy
self.actors = [Actor(name) for name in enemyNames[indexEnemy]]
self.active = False
def draw(self, screenPosition):
if self.active and self.centre[1] - screenPosition > -enemyHalfSize and self.centre[1] - screenPosition < 600+enemyHalfSize:
indexActor = ((self.centre[0]//6) % (len(enemyNames[self.index])//2))*2
if self.speedX < 0:
indexActor += 1
self.actors[indexActor].x = self.centre[0]
self.actors[indexActor].y = self.centre[1] - screenPosition
self.actors[indexActor].draw()
def update(self, allPlatforms, allRainbows, screenPosition):
if self.centre[1] - screenPosition > -enemyHalfSize/2:
self.active = True
if not self.active or self.centre[1] - screenPosition > 600+enemyHalfSize:
return
if self.index == 0:
if self.speedX > 0:
lineIntersection = LineString([(self.centre[0]+enemyHalfSize, self.centre[1]-6),
(self.centre[0]+enemyHalfSize, self.centre[1]+enemyHalfSize+16)])
else:
lineIntersection = LineString([(self.centre[0]-enemyHalfSize, self.centre[1]-6),
(self.centre[0]-enemyHalfSize, self.centre[1]+enemyHalfSize+16)])
else:
lineIntersection = LineString([(self.centre[0]-enemyHalfSize, self.centre[1]-enemyHalfSize),
(self.centre[0]-enemyHalfSize, self.centre[1]+enemyHalfSize+self.speedY+2),
(self.centre[0]+enemyHalfSize, self.centre[1]+enemyHalfSize+self.speedY+2),
(self.centre[0]+enemyHalfSize, self.centre[1]-enemyHalfSize)])
intersectionFound = False
for platform in allPlatforms.platformLineStrings:
intersection = lineIntersection.intersection(platform)
if not intersection.is_empty:
if self.index != 2:
if intersection.geom_type == 'MultiPoint':
self.centre[1] = min(intersection.geoms, key=lambda x: x.coords[0][1]).coords[0][1] - enemyHalfSize
elif intersection.geom_type == 'Point':
self.centre[1] = intersection.coords[0][1] - enemyHalfSize
intersectionFound = True
if self.index != 2:
self.speedY = 0
for rainbow in allRainbows.rainbows:
intersection = lineIntersection.intersection(rainbow.lineString)
if not intersection.is_empty:
if self.index == 0 or self.index == 2:
self.speedX = -self.speedX
elif self.index == 1 and self.speedY < 1:
self.speedX = -self.speedX
else:
if intersection.geom_type == 'MultiPoint':
self.centre[1] = min(intersection.geoms, key=lambda x: x.coords[0][1]).coords[0][1] - enemyHalfSize
elif intersection.geom_type == 'Point':
self.centre[1] = intersection.coords[0][1] - enemyHalfSize
if not intersectionFound and self.index == 0:
self.speedX = -self.speedX
elif intersectionFound and self.index == 2:
self.speedY = -self.speedY
elif self.centre[0] >= 800 - enemyHalfSize:
self.speedX = -enemyLateralSpeed
elif self.centre[0] <= enemyHalfSize:
self.speedX = enemyLateralSpeed
if self.centre[1] > 600 - enemyHalfSize:
self.centre[1] = 600 - enemyHalfSize
if self.index != 2:
self.speedY = 0
elif self.index == 1:
self.speedY += enemyAccelerationDown
if self.speedY > enemyTerminalSpeed:
self.speedY = enemyTerminalSpeed
self.centre[0] += self.speedX
self.centre[1] += self.speedY
self.lineString = translate(self.centredLineString, self.centre[0], self.centre[1])
class AllEnemies:
def __init__(self):
self.restart()
def restart(self):
self.enemies = [Enemy(enemies[i][2], enemies[i][3], enemies[i][0], enemies[i][1]) for i in range(len(enemies))]
def draw(self, screenPosition):
for enemy in self.enemies:
enemy.draw(screenPosition)
def update(self, allPlatforms, allRainbows, screenPosition):
for enemy in self.enemies:
enemy.update(allPlatforms, allRainbows, screenPosition)
def killEnemy(self, index, allCollectables):
allCollectables.addCollectable(self.enemies[index].centre[0], self.enemies[index].centre[1])
del self.enemies[index]
def enemyHalfSize(self):
return enemyHalfSize
collectableNames = ['collectable_1', 'collectable_2', 'collectable_3', 'collectable_4', 'collectable_5', 'collectable_rainbow']
flyingCollectableNames = ['flying_candy_1', 'flying_candy_2', 'flying_candy_3', 'flying_candy_4']
collectableHalfSize = 10
class CollectableFlying:
def __init__(self, startX, startY):
self.centre = [startX, startY]
self.speedX = randint(-startX,800-startX)/100
self.speedY = randint(-6,-4)
self.accelerationDown = 0.1
self.actors = [Actor(name, (startX, startY)) for name in flyingCollectableNames]
self.indexActor = 0
def draw(self, screenPosition):
index = (self.indexActor // 4) % len(flyingCollectableNames)
self.actors[index].x = self.centre[0]
self.actors[index].y = self.centre[1] - screenPosition
self.actors[index].draw()
def update(self, screenPosition):
self.centre[0] += self.speedX
if self.centre[0] < collectableHalfSize or self.centre[0] > 800 - collectableHalfSize:
self.centre[0] -= self.speedX
self.speedX = 0
self.speedY += self.accelerationDown
self.centre[1] += self.speedY
self.indexActor += 1
def checkCollission(self, allPlatforms):
if self.speedY > 1:
bottomLine = LineString([(self.centre[0]-collectableHalfSize, self.centre[1]),
(self.centre[0], self.centre[1]+collectableHalfSize),
(self.centre[0]+collectableHalfSize, self.centre[1])])
for platform in allPlatforms.platformLineStrings:
intersection = bottomLine.intersection(platform)
if not intersection.is_empty:
point = [self.centre[0], self.centre[1]]
if intersection.geom_type == 'MultiPoint':
point[1] = min(intersection.geoms, key=lambda x: x.coords[0][1]).coords[0][1] - collectableHalfSize
elif intersection.geom_type == 'Point':
point[1] = intersection.coords[0][1] - collectableHalfSize
return True, point
return False, [0,0]
class Collectable:
def __init__(self, startX, startY):
self.centre = [startX, startY]
self.creationTime = 0
self.actor = Actor(collectableNames[randint(0, 5)], (startX, startY))
def draw(self, screenPosition):
self.actor.y = self.centre[1] - screenPosition
self.actor.draw()
def update(self):
self.creationTime += 1
def isRainbow(self):
if self.actor.image == 'collectable_rainbow':
return True
return False
class Collectables:
def __init__(self):
self.collectablesFlying = []
self.collectables = []
def restart(self):
self.collectablesFlying = []
self.collectables = []
def addCollectable(self, startX, startY):
self.collectablesFlying.append(CollectableFlying(startX, startY))
def draw(self, screenPosition):
for collectable in self.collectablesFlying:
collectable.draw(screenPosition)
for collectable in self.collectables:
collectable.draw(screenPosition)
def update(self, allPlatforms, player, screenPosition):
for collectable in self.collectablesFlying:
collectable.update(screenPosition)
for collectable in self.collectables:
collectable.update()
for i in reversed(range(len(self.collectablesFlying))):
collission, point = self.collectablesFlying[i].checkCollission(allPlatforms)
if collission:
self.collectables.append(Collectable(point[0], point[1]))
del self.collectablesFlying[i]
elif self.collectablesFlying[i].centre[1] > 600 + collectableHalfSize:
del self.collectablesFlying[i]
for i in reversed(range(len(self.collectables))):
if RectanglesIntersect(player.centre, player.playerHalfSize(), self.collectables[i].centre, [collectableHalfSize, collectableHalfSize]):
if self.collectables[i].isRainbow():
player.addRainbow()
self.removeCollectable(i)
def removeCollectable(self, index):
del self.collectables[index]
playerHalfSizeX = 10
playerHalfSizeY = 18
playerAccelerationDown = 0.5
playerJumpSpeed = 14
playerTerminalSpeed = 12
playerLateralSpeed = 4
coyoteTimeVerticalSpeed = 4
playerVerticalSpeedToDestroyRainbow = 5
playerMinTimeBetweenRainbows = 16
playerImageNames = ['player_stand_right', 'player_walk_1_right', 'player_stand_right', 'player_walk_2_right', 'player_jump_up_right', 'player_jump_down_right',
'player_stand_left', 'player_walk_1_left', 'player_stand_left', 'player_walk_2_left', 'player_jump_up_left', 'player_jump_down_left',
'player_collided_1', 'player_collided_2']
class Player:
def __init__(self):
self.centre = [400, 500]
self.centredLineString = LineString([(-playerHalfSizeX,-playerHalfSizeY*0),
(-playerHalfSizeX,playerHalfSizeY),
(playerHalfSizeX,playerHalfSizeY),
(playerHalfSizeX,-playerHalfSizeY*0)])
self.lineString = translate(self.centredLineString, self.centre[0], self.centre[1])
self.polygon = Polygon(self.lineString)
self.speedY = 0
self.walking = False
self.directionX = -1
self.jumping = False
self.actors = [Actor(name) for name in playerImageNames]
self.numberOfRainbows = 1
self.lastRainbowShot = playerMinTimeBetweenRainbows
self.active = True
self.lives = 3
def draw(self, screenPosition):
indexImage = 0
if self.active:
if self.jumping:
if self.speedY < 0:
indexImage = 4
else:
indexImage = 5
elif self.walking:
indexImage = (self.centre[0]//13) % 4
if self.directionX < 0:
indexImage += 6
else:
indexImage = 12 + (self.centre[0]//13) % 2
self.actors[indexImage].x = self.centre[0]
self.actors[indexImage].y = self.centre[1] - screenPosition
self.actors[indexImage].draw()
def intersectPlatform(self, platform, collidingObject):
intersection = collidingObject.intersection(platform)
if not intersection.is_empty:
newPositionY = self.centre[1]
if intersection.geom_type == 'MultiPoint':
newPositionY = min(intersection.geoms, key=lambda x: x.coords[0][1]).coords[0][1] - playerHalfSizeY
elif intersection.geom_type == 'Point':
newPositionY = intersection.coords[0][1] - playerHalfSizeY
elif intersection.geom_type == 'LineString':
newPositionY = min(intersection.coords, key=lambda x: x[1])[1] - playerHalfSizeY
if self.centre[1] > newPositionY:
self.centre[1] = newPositionY
self.speedY = 0
self.jumping = False
return True
return False
def intersectEnemy(self, allEnemies):
for enemy in allEnemies.enemies:
if enemy.active:
if RectanglesIntersect(self.centre, [playerHalfSizeX, playerHalfSizeY], enemy.centre, [allEnemies.enemyHalfSize(), allEnemies.enemyHalfSize()]):
return True
return False
def addRainbow(self):
if self.numberOfRainbows < 3:
self.numberOfRainbows += 1
def update(self, allPlatforms, allRainbows, allCollectables, allEnemies):
if self.lives == 0:
return
if not self.active:
self.speedY += playerAccelerationDown
self.centre[0] += self.speedX // 2
self.centre[1] += self.speedY // 2
if self.centre[1] > 600 + playerHalfSizeY*6:
self.lives -= 1
if self.lives > 0:
self.centre = [400, 500]
self.speedX = 0
self.speedY = 0
self.numberOfRainbows = 1
self.lineString = translate(self.centredLineString, self.centre[0], self.centre[1])
self.polygon = Polygon(self.lineString)
allRainbows.restart()
allCollectables.restart()
allEnemies.restart()
self.active = True
return
if self.speedY >= 0:
if not self.jumping:
collidingObject = self.polygon
else:
collidingObject = LineString([(self.centre[0]-playerHalfSizeX, self.centre[1]+playerHalfSizeY-2),
(self.centre[0]-playerHalfSizeX, self.centre[1]+playerHalfSizeY+self.speedY+2),
(self.centre[0]+playerHalfSizeX, self.centre[1]+playerHalfSizeY+self.speedY+2),
(self.centre[0]+playerHalfSizeX, self.centre[1]+playerHalfSizeY-2)])
for platform in allPlatforms.platformLineStrings:
self.intersectPlatform(platform, collidingObject)
previousSpeed = self.speedY
for i in reversed(range(len(allRainbows.rainbows))):
if allRainbows.rainbows[i].timeFromCreation >= 0:
if self.intersectPlatform(allRainbows.rainbows[i].lineString, collidingObject):
if previousSpeed >= playerVerticalSpeedToDestroyRainbow:
allRainbows.rainbowFall(i)
if not self.jumping and self.speedY >= coyoteTimeVerticalSpeed:
self.jumping = True
if self.centre[1] > 600 - playerHalfSizeY:
self.centre[1] = 600 - playerHalfSizeY
self.speedY = 0
self.jumping = False
else:
self.speedY += playerAccelerationDown
if self.speedY > playerTerminalSpeed:
self.speedY = playerTerminalSpeed
self.centre[1] += self.speedY
if self.intersectEnemy(allEnemies):
self.active = False
self.speedY = -playerJumpSpeed
if self.centre[0] > 400:
self.speedX = -playerLateralSpeed
else:
self.speedX = playerLateralSpeed
self.lineString = translate(self.centredLineString, self.centre[0], self.centre[1])
self.polygon = Polygon(self.lineString)
self.lastRainbowShot += 1
def jump(self):
if not self.jumping:
self.speedY = -playerJumpSpeed
self.jumping = True
def stopJump(self):
if self.jumping and self.speedY < -playerJumpSpeed/2:
self.speedY = -playerJumpSpeed/2
def left(self):
self.centre[0] -= playerLateralSpeed
self.directionX = -1
if self.centre[0] < playerHalfSizeX:
self.centre[0] = playerHalfSizeX
self.walking = True
def right(self):
self.centre[0] += playerLateralSpeed
self.directionX = 1
if self.centre[0] > 800 - playerHalfSizeX:
self.centre[0] = 800 - playerHalfSizeX
self.walking = True
def still(self):
self.walking = False
def playerHalfSize(self):
return [playerHalfSizeX, playerHalfSizeY]
def shootRainbow(self, allRainbows):
if self.lastRainbowShot > playerMinTimeBetweenRainbows:
self.lastRainbowShot = 0
allRainbows.addRainbows(self.numberOfRainbows, self.centre[0] + self.directionX * (playerHalfSizeX + 2), self.centre[1] + playerHalfSizeY, self.directionX)
def ScreenPositionUpdate(player, screenPosition):
if player.centre[1] - screenPosition < 150:
screenPosition = player.centre[1] - 150
elif player.centre[1] - screenPosition > 600 - 150:
screenPosition = player.centre[1] - (600 - 150)
if screenPosition > 0:
screenPosition = 0
return screenPosition
backgroundBaseColour = (95, 148, 255)
backgroundColour = (0,0,0)
def BackgroundColour(screenPosition, maxScreenPosition):
colourScale = -screenPosition / maxScreenPosition
if colourScale > 1:
colourScale = 1
return (backgroundBaseColour[0]*colourScale,
backgroundBaseColour[1]*colourScale,
backgroundBaseColour[2]*colourScale)
allPlatforms = AllPlatforms()
allRainbows = AllRainbows()
player = Player()
allEnemies = AllEnemies()
allCollectables = Collectables()
screenPosition = 0
maxScreenPosition = allPlatforms.getMaxScreenPosition()
levelClear = False
def draw():
screen.fill(BackgroundColour(screenPosition, maxScreenPosition))
allPlatforms.draw()
allEnemies.draw(screenPosition)
allRainbows.draw(screenPosition)
allCollectables.draw(screenPosition)
player.draw(screenPosition)
for i in range(player.lives):
screen.blit('player_icon', (10+i*14, 10))
if player.lives == 0:
screen.draw.text("GAME OVER", center=(400, 260), fontsize=55, color=(255,0,0))
if levelClear:
screen.draw.text("LEVEL CLEAR", center=(400, 260), fontsize=55, color=(0,0,255))
def update(dt):
global screenPosition, levelClear
if keyboard.left:
player.left()
elif keyboard.right:
player.right()
else:
player.still()
if keyboard.up:
player.jump()
else:
player.stopJump()
player.update(allPlatforms, allRainbows, allCollectables, allEnemies)
screenPosition = ScreenPositionUpdate(player, screenPosition)
allRainbows.update(allEnemies, allCollectables, screenPosition)
allEnemies.update(allPlatforms, allRainbows, screenPosition)
allCollectables.update(allPlatforms, player, screenPosition)
allPlatforms.update(screenPosition)
if player.centre[1] < -maxScreenPosition:
levelClear = True
def on_key_down(key):
if key == keys.SPACE:
player.shootRainbow(allRainbows)
pgzrun.go()