Fred's Bad Day

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

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