Fred's Bad Day
Attribution
Essentials - Make Games with Python, pages 94 - 113.
Licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported.
Original Python code
import pygame, sys, random, math
import pygame.locals as GAME_GLOBALS
import pygame.event as GAME_EVENTS
import pygame.time as GAME_TIME
class FredClass():
x = 0
y = 625
isHit = False
timeHit = 0
health = 100
leftImage = None
rightImage = None
leftImageHit = None
rightImageHit = None
direction = 1
speed = 8
pygame = None
def reset(self, x):
self.x = x
self.y = 625
self.isHit = False
self.timeHit = 0
self.health = 100
self.direction = 1
self.speed = 8
self.pygame = None
def moveLeft(self, leftBound):
if self.direction is not 0:
self.direction = 0
if((self.x - self.speed) > leftBound):
self.x -= self.speed
def moveRight(self, rightBound):
if self.direction is not 1:
self.direction = 1
if((self.x + self.speed) + 58 < rightBound):
self.x += self.speed
def loadImages(self, pygame):
self.leftImage = pygame.image.load("assets/Fred-Left.png")
self.rightImage = pygame.image.load("assets/Fred-Right.png")
self.leftImageHit = pygame.image.load("assets/Fred-Left-Hit.png")
self.rightImageHit = pygame.image.load("assets/Fred-Right-Hit.png")
def draw(self, surface, time):
if time - self.timeHit > 800:
self.timeHit = 0
self.isHit = False
if self.direction is 1:
if self.isHit is False:
surface.blit(self.rightImage, (self.x, self.y))
else :
surface.blit(self.rightImageHit, (self.x, self.y))
else :
if self.isHit is False:
surface.blit(self.leftImage, (self.x, self.y))
else :
surface.blit(self.leftImageHit, (self.x, self.y))
def __init__(self, x):
self.x = x
class Barrel():
slots = [(4, 103), (82, 27), (157, 104), (234, 27), (310, 104), (388, 27), (463, 104), (539, 27), (615, 104), (691, 27), (768, 104), (845, 27), (920, 104)]
slot = 0
x = 0
y = 0
image = None
brokenImage = None
isBroken = False
timeBroken = 0
needsRemoving = False
size = [33,22]
ratio = 0.66
vy = 1.5
gravity = 1.05
maxY = 20
def split(self, time):
self.isBroken = True
self.timeBroken = time
self.vy = 5
self.x -= 10
def checkForCollision(self, fred):
hitX = False
hitY = False
if fred.x > self.x and fred.x < self.x + 75:
hitX = True
elif fred.x + 57 > self.x and fred.x + 57 < self.x + 75:
hitX = True
if fred.y + 120 > self.y and fred.y < self.y:
hitY = True
elif fred.y < self.y + 48:
hitY = True
if hitX is True and hitY is True:
return True
def loadImages(self, pygame):
self.image = pygame.image.load("assets/Barrel.png")
self.brokenImage = pygame.image.load("assets/Barrel_break.png")
def move(self, windowHeight):
if self.vy < self.maxY:
self.vy = self.vy * self.gravity
self.y += self.vy
if self.y > windowHeight:
self.needsRemoving = True
def draw(self, surface, pygame):
if self.isBroken is True:
surface.blit(self.brokenImage, (self.x, self.y))
else :
surface.blit(self.image, (self.x, self.y))
def __init__(self, slot):
self.slot = slot
self.x = self.slots[slot][0]
self.y = self.slots[slot][1] + 24
windowWidth = 1000
windowHeight = 768
pygame.init()
pygame.font.init()
clock = pygame.time.Clock()
surface = pygame.display.set_mode((windowWidth, windowHeight), pygame.FULLSCREEN)
pygame.display.set_caption('Fred\'s Bad Day')
textFont = pygame.font.SysFont("monospace", 50)
gameStarted = False
gameStartedTime = 0
gameFinishedTime = 0
gameOver = False
startScreen = pygame.image.load("assets/startgame.png")
endScreen = pygame.image.load("assets/gameover.png")
background = pygame.image.load("assets/background.png")
Fred = FredClass(windowWidth / 2)
Barrels = []
lastBarrel = 0
lastBarrelSlot = 0
barrelInterval = 1500
goLeft = False
goRight = False
def quitGame():
pygame.quit()
sys.exit()
def newBarrel():
global Barrels, lastBarrel, lastBarrelSlot
slot = random.randint(0, 12)
while slot == lastBarrelSlot:
slot = random.randint(0, 12)
theBarrel = Barrel(slot)
theBarrel.loadImages(pygame)
Barrels.append(theBarrel)
lastBarrel = GAME_TIME.get_ticks()
lastBarrelSlot = slot
Fred.loadImages(pygame)
# 'main' loop
while True:
timeTick = GAME_TIME.get_ticks()
if gameStarted is True and gameOver is False:
surface.blit(background, (0, 0))
Fred.draw(surface, timeTick)
barrelsToRemove = []
for idx, barrel in enumerate(Barrels):
barrel.move(windowHeight)
barrel.draw(surface, pygame)
if barrel.isBroken is False:
hasCollided = barrel.checkForCollision(Fred);
if hasCollided is True:
barrel.split(timeTick)
Fred.isHit = True
Fred.timeHit = timeTick
if Fred.health >= 10:
Fred.health -= 10
else :
gameOver = True
gameFinishedTime = timeTick
elif timeTick - barrel.timeBroken > 1000:
barrelsToRemove.append(idx)
continue
if barrel.needsRemoving is True:
barrelsToRemove.append(idx)
continue
pygame.draw.rect(surface, (175,59,59), (0, windowHeight - 10, (windowWidth / 100) * Fred.health , 10))
for index in barrelsToRemove:
del Barrels[index]
if goLeft is True:
Fred.moveLeft(0)
if goRight is True:
Fred.moveRight(windowWidth)
elif gameStarted is False and gameOver is False:
surface.blit(startScreen, (0, 0))
elif gameStarted is True and gameOver is True:
surface.blit(endScreen, (0, 0))
timeLasted = (gameFinishedTime - gameStartedTime) / 1000
if timeLasted < 10:
timeLasted = "0" + str(timeLasted)
else :
timeLasted = str(timeLasted)
renderedText = textFont.render(timeLasted, 1, (175,59,59))
surface.blit(renderedText, (495, 430))
# Handle user and system events
for event in GAME_EVENTS.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
quitGame()
elif event.key == pygame.K_LEFT:
goLeft = True
goRight = False
elif event.key == pygame.K_RIGHT:
goLeft = False
goRight = True
elif event.key == pygame.K_RETURN:
if gameStarted is False and gameOver is False:
gameStarted = True
gameStartedTime = timeTick
elif gameStarted is True and gameOver is True:
Fred.reset(windowWidth / 2)
Barrels = []
barrelInterval = 1500
gameOver = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
goLeft = False
if event.key == pygame.K_RIGHT:
goRight = False
if event.type == GAME_GLOBALS.QUIT:
quitGame()
clock.tick(60)
pygame.display.update()
if GAME_TIME.get_ticks() - lastBarrel > barrelInterval and gameStarted is True:
newBarrel()
if barrelInterval > 150:
barrelInterval -= 50