Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Squirrel Eat Squirrel (a 2D Katamari Damacy clone)
- # By Al Sweigart al@inventwithpython.com
- # http://inventwithpython.com/pygame
- # Released under a "Simplified BSD" license
- import random, sys, time, math, pygame
- from pygame.locals import *
- FPS = 30 # frames per second to update the screen
- WINWIDTH = 640 # width of the program's window, in pixels
- WINHEIGHT = 480 # height in pixels
- HALF_WINWIDTH = int(WINWIDTH / 2)
- HALF_WINHEIGHT = int(WINHEIGHT / 2)
- GRASSCOLOR = (24, 255, 0)
- WHITE = (255, 255, 255)
- RED = (255, 0, 0)
- CAMERASLACK = 90 # how far from the center the squirrel moves before moving the camera
- MOVERATE = 9 # how fast the player moves
- BOUNCERATE = 6 # how fast the player bounces (large is slower)
- BOUNCEHEIGHT = 30 # how high the player bounces
- STARTSIZE = 25 # how big the player starts off
- WINSIZE = 300 # how big the player needs to be to win
- INVULNTIME = 2 # how long the player is invulnerable after being hit in seconds
- GAMEOVERTIME = 4 # how long the "game over" text stays on the screen in seconds
- MAXHEALTH = 3 # how much health the player starts with
- NUMGRASS = 80 # number of grass objects in the active area
- NUMSQUIRRELS = 30 # number of squirrels in the active area
- SQUIRRELMINSPEED = 3 # slowest squirrel speed
- SQUIRRELMAXSPEED = 7 # fastest squirrel speed
- DIRCHANGEFREQ = 2 # % chance of direction change per frame
- LEFT = 'left'
- RIGHT = 'right'
- """
- This program has three data structures to represent the player, enemy squirrels, and grass background objects. The data structures are dictionaries with the following keys:
- Keys used by all three data structures:
- 'x' - the left edge coordinate of the object in the game world (not a pixel coordinate on the screen)
- 'y' - the top edge coordinate of the object in the game world (not a pixel coordinate on the screen)
- 'rect' - the pygame.Rect object representing where on the screen the object is located.
- Player data structure keys:
- 'surface' - the pygame.Surface object that stores the image of the squirrel which will be drawn to the screen.
- 'facing' - either set to LEFT or RIGHT, stores which direction the player is facing.
- 'size' - the width and height of the player in pixels. (The width & height are always the same.)
- 'bounce' - represents at what point in a bounce the player is in. 0 means standing (no bounce), up to BOUNCERATE (the completion of the bounce)
- 'health' - an integer showing how many more times the player can be hit by a larger squirrel before dying.
- Enemy Squirrel data structure keys:
- 'surface' - the pygame.Surface object that stores the image of the squirrel which will be drawn to the screen.
- 'movex' - how many pixels per frame the squirrel moves horizontally. A negative integer is moving to the left, a positive to the right.
- 'movey' - how many pixels per frame the squirrel moves vertically. A negative integer is moving up, a positive moving down.
- 'width' - the width of the squirrel's image, in pixels
- 'height' - the height of the squirrel's image, in pixels
- 'bounce' - represents at what point in a bounce the player is in. 0 means standing (no bounce), up to BOUNCERATE (the completion of the bounce)
- 'bouncerate' - how quickly the squirrel bounces. A lower number means a quicker bounce.
- 'bounceheight' - how high (in pixels) the squirrel bounces
- Grass data structure keys:
- 'grassImage' - an integer that refers to the index of the pygame.Surface object in GRASSIMAGES used for this grass object
- """
- def main():
- global FPSCLOCK, DISPLAYSURF, BASICFONT, L_SQUIR_IMG, R_SQUIR_IMG, GRASSIMAGES
- pygame.init()
- FPSCLOCK = pygame.time.Clock()
- pygame.display.set_icon(pygame.image.load('gameicon.png'))
- DISPLAYSURF = pygame.display.set_mode((WINWIDTH, WINHEIGHT))
- pygame.display.set_caption('Squirrel Eat Squirrel')
- BASICFONT = pygame.font.Font('freesansbold.ttf', 32)
- # load the image files
- L_SQUIR_IMG = pygame.image.load('squirrel.png')
- R_SQUIR_IMG = pygame.transform.flip(L_SQUIR_IMG, True, False)
- GRASSIMAGES = []
- for i in range(1, 5):
- GRASSIMAGES.append(pygame.image.load('grass%s.png' % i))
- while True:
- runGame()
- def runGame():
- # set up variables for the start of a new game
- invulnerableMode = False # if the player is invulnerable
- invulnerableStartTime = 0 # time the player became invulnerable
- gameOverMode = False # if the player has lost
- gameOverStartTime = 0 # time the player lost
- winMode = False # if the player has won
- # create the surfaces to hold game text
- gameOverSurf = BASICFONT.render('Game Over', True, WHITE)
- gameOverRect = gameOverSurf.get_rect()
- gameOverRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
- winSurf = BASICFONT.render('You have achieved OMEGA SQUIRREL!', True, WHITE)
- winRect = winSurf.get_rect()
- winRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
- winSurf2 = BASICFONT.render('(Press "r" to restart.)', True, WHITE)
- winRect2 = winSurf2.get_rect()
- winRect2.center = (HALF_WINWIDTH, HALF_WINHEIGHT + 30)
- # camerax and cameray are the top left of where the camera view is
- camerax = 0
- cameray = 0
- grassObjs = [] # stores all the grass objects in the game
- squirrelObjs = [] # stores all the non-player squirrel objects
- # stores the player object:
- playerObj = {'surface': pygame.transform.scale(L_SQUIR_IMG, (STARTSIZE, STARTSIZE)),
- 'facing': LEFT,
- 'size': STARTSIZE,
- 'x': HALF_WINWIDTH,
- 'y': HALF_WINHEIGHT,
- 'bounce':0,
- 'health': MAXHEALTH}
- moveLeft = False
- moveRight = False
- moveUp = False
- moveDown = False
- # start off with some random grass images on the screen
- for i in range(10):
- grassObjs.append(makeNewGrass(camerax, cameray))
- grassObjs[i]['x'] = random.randint(0, WINWIDTH)
- grassObjs[i]['y'] = random.randint(0, WINHEIGHT)
- while True: # main game loop
- # Check if we should turn off invulnerability
- if invulnerableMode and time.time() - invulnerableStartTime > INVULNTIME:
- invulnerableMode = False
- # move all the squirrels
- for sObj in squirrelObjs:
- # move the squirrel, and adjust for their bounce
- sObj['x'] += sObj['movex']
- sObj['y'] += sObj['movey']
- sObj['bounce'] += 1
- if sObj['bounce'] > sObj['bouncerate']:
- sObj['bounce'] = 0 # reset bounce amount
- # random chance they change direction
- if random.randint(0, 99) < DIRCHANGEFREQ:
- sObj['movex'] = getRandomVelocity()
- sObj['movey'] = getRandomVelocity()
- if sObj['movex'] > 0: # faces right
- sObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (sObj['width'], sObj['height']))
- else: # faces left
- sObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (sObj['width'], sObj['height']))
- # go through all the objects and see if any need to be deleted.
- for i in range(len(grassObjs) - 1, -1, -1):
- if isOutsideActiveArea(camerax, cameray, grassObjs[i]):
- del grassObjs[i]
- for i in range(len(squirrelObjs) - 1, -1, -1):
- if isOutsideActiveArea(camerax, cameray, squirrelObjs[i]):
- del squirrelObjs[i]
- # add more grass & squirrels if we don't have enough.
- while len(grassObjs) < NUMGRASS:
- grassObjs.append(makeNewGrass(camerax, cameray))
- while len(squirrelObjs) < NUMSQUIRRELS:
- squirrelObjs.append(makeNewSquirrel(camerax, cameray))
- # adjust camerax and cameray if beyond the "camera slack"
- playerCenterx = playerObj['x'] + int(playerObj['size'] / 2)
- playerCentery = playerObj['y'] + int(playerObj['size'] / 2)
- if (camerax + HALF_WINWIDTH) - playerCenterx > CAMERASLACK:
- camerax = playerCenterx + CAMERASLACK - HALF_WINWIDTH
- elif playerCenterx - (camerax + HALF_WINWIDTH) > CAMERASLACK:
- camerax = playerCenterx - CAMERASLACK - HALF_WINWIDTH
- if (cameray + HALF_WINHEIGHT) - playerCentery > CAMERASLACK:
- cameray = playerCentery + CAMERASLACK - HALF_WINHEIGHT
- elif playerCentery - (cameray + HALF_WINHEIGHT) > CAMERASLACK:
- cameray = playerCentery - CAMERASLACK - HALF_WINHEIGHT
- # draw the green background
- DISPLAYSURF.fill(GRASSCOLOR)
- # draw all the grass objects on the screen
- for gObj in grassObjs:
- gRect = pygame.Rect( (gObj['x'] - camerax,
- gObj['y'] - cameray,
- gObj['width'],
- gObj['height']) )
- DISPLAYSURF.blit(GRASSIMAGES[gObj['grassImage']], gRect)
- # draw the other squirrels
- for sObj in squirrelObjs:
- sObj['rect'] = pygame.Rect( (sObj['x'] - camerax,
- sObj['y'] - cameray - getBounceAmount(sObj['bounce'], sObj['bouncerate'], sObj['bounceheight']),
- sObj['width'],
- sObj['height']) )
- DISPLAYSURF.blit(sObj['surface'], sObj['rect'])
- # draw the player squirrel
- flashIsOn = round(time.time(), 1) * 10 % 2 == 1
- if not gameOverMode and not (invulnerableMode and flashIsOn):
- playerObj['rect'] = pygame.Rect( (playerObj['x'] - camerax,
- playerObj['y'] - cameray - getBounceAmount(playerObj['bounce'], BOUNCERATE, BOUNCEHEIGHT),
- playerObj['size'],
- playerObj['size']) )
- DISPLAYSURF.blit(playerObj['surface'], playerObj['rect'])
- # draw the health meter
- drawHealthMeter(playerObj['health'])
- for event in pygame.event.get(): # event handling loop
- if event.type == QUIT:
- terminate()
- elif event.type == KEYDOWN:
- if event.key in (K_UP, K_w):
- moveDown = False
- moveUp = True
- elif event.key in (K_DOWN, K_s):
- moveUp = False
- moveDown = True
- elif event.key in (K_LEFT, K_a):
- moveRight = False
- moveLeft = True
- if playerObj['facing'] != LEFT: # change player image
- playerObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (playerObj['size'], playerObj['size']))
- playerObj['facing'] = LEFT
- elif event.key in (K_RIGHT, K_d):
- moveLeft = False
- moveRight = True
- if playerObj['facing'] != RIGHT: # change player image
- playerObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (playerObj['size'], playerObj['size']))
- playerObj['facing'] = RIGHT
- elif winMode and event.key == K_r:
- return
- elif event.type == KEYUP:
- # stop moving the player's squirrel
- if event.key in (K_LEFT, K_a):
- moveLeft = False
- elif event.key in (K_RIGHT, K_d):
- moveRight = False
- elif event.key in (K_UP, K_w):
- moveUp = False
- elif event.key in (K_DOWN, K_s):
- moveDown = False
- elif event.key == K_ESCAPE:
- terminate()
- if not gameOverMode:
- # actually move the player
- if moveLeft:
- playerObj['x'] -= MOVERATE
- if moveRight:
- playerObj['x'] += MOVERATE
- if moveUp:
- playerObj['y'] -= MOVERATE
- if moveDown:
- playerObj['y'] += MOVERATE
- if (moveLeft or moveRight or moveUp or moveDown) or playerObj['bounce'] != 0:
- playerObj['bounce'] += 1
- if playerObj['bounce'] > BOUNCERATE:
- playerObj['bounce'] = 0 # reset bounce amount
- # check if the player has collided with any squirrels
- for i in range(len(squirrelObjs)-1, -1, -1):
- sqObj = squirrelObjs[i]
- if 'rect' in sqObj and playerObj['rect'].colliderect(sqObj['rect']):
- # a player/squirrel collision has occurred
- if sqObj['width'] * sqObj['height'] <= playerObj['size']**2:
- # player is larger and eats the squirrel
- playerObj['size'] += int( (sqObj['width'] * sqObj['height'])**0.2 ) + 1
- del squirrelObjs[i]
- if playerObj['facing'] == LEFT:
- playerObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (playerObj['size'], playerObj['size']))
- if playerObj['facing'] == RIGHT:
- playerObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (playerObj['size'], playerObj['size']))
- if playerObj['size'] > WINSIZE:
- winMode = True # turn on "win mode"
- elif not invulnerableMode:
- # player is smaller and takes damage
- invulnerableMode = True
- invulnerableStartTime = time.time()
- playerObj['health'] -= 1
- if playerObj['health'] == 0:
- gameOverMode = True # turn on "game over mode"
- gameOverStartTime = time.time()
- else:
- # game is over, show "game over" text
- DISPLAYSURF.blit(gameOverSurf, gameOverRect)
- if time.time() - gameOverStartTime > GAMEOVERTIME:
- return # end the current game
- # check if the player has won.
- if winMode:
- DISPLAYSURF.blit(winSurf, winRect)
- DISPLAYSURF.blit(winSurf2, winRect2)
- pygame.display.update()
- FPSCLOCK.tick(FPS)
- def drawHealthMeter(currentHealth):
- for i in range(currentHealth): # draw red health bars
- pygame.draw.rect(DISPLAYSURF, RED, (15, 5 + (10 * MAXHEALTH) - i * 10, 20, 10))
- for i in range(MAXHEALTH): # draw the white outlines
- pygame.draw.rect(DISPLAYSURF, WHITE, (15, 5 + (10 * MAXHEALTH) - i * 10, 20, 10), 1)
- def terminate():
- pygame.quit()
- sys.exit()
- def getBounceAmount(currentBounce, bounceRate, bounceHeight):
- # Returns the number of pixels to offset based on the bounce.
- # Larger bounceRate means a slower bounce.
- # Larger bounceHeight means a higher bounce.
- # currentBounce will always be less than bounceRate
- return int(math.sin( (math.pi / float(bounceRate)) * currentBounce ) * bounceHeight)
- def getRandomVelocity():
- speed = random.randint(SQUIRRELMINSPEED, SQUIRRELMAXSPEED)
- if random.randint(0, 1) == 0:
- return speed
- else:
- return -speed
- def getRandomOffCameraPos(camerax, cameray, objWidth, objHeight):
- # create a Rect of the camera view
- cameraRect = pygame.Rect(camerax, cameray, WINWIDTH, WINHEIGHT)
- while True:
- x = random.randint(camerax - WINWIDTH, camerax + (2 * WINWIDTH))
- y = random.randint(cameray - WINHEIGHT, cameray + (2 * WINHEIGHT))
- # create a Rect object with the random coordinates and use colliderect()
- # to make sure the right edge isn't in the camera view.
- objRect = pygame.Rect(x, y, objWidth, objHeight)
- if not objRect.colliderect(cameraRect):
- return x, y
- def makeNewSquirrel(camerax, cameray):
- sq = {}
- generalSize = random.randint(5, 25)
- multiplier = random.randint(1, 3)
- sq['width'] = (generalSize + random.randint(0, 10)) * multiplier
- sq['height'] = (generalSize + random.randint(0, 10)) * multiplier
- sq['x'], sq['y'] = getRandomOffCameraPos(camerax, cameray, sq['width'], sq['height'])
- sq['movex'] = getRandomVelocity()
- sq['movey'] = getRandomVelocity()
- if sq['movex'] < 0: # squirrel is facing left
- sq['surface'] = pygame.transform.scale(L_SQUIR_IMG, (sq['width'], sq['height']))
- else: # squirrel is facing right
- sq['surface'] = pygame.transform.scale(R_SQUIR_IMG, (sq['width'], sq['height']))
- sq['bounce'] = 0
- sq['bouncerate'] = random.randint(10, 18)
- sq['bounceheight'] = random.randint(10, 50)
- return sq
- def makeNewGrass(camerax, cameray):
- gr = {}
- gr['grassImage'] = random.randint(0, len(GRASSIMAGES) - 1)
- gr['width'] = GRASSIMAGES[0].get_width()
- gr['height'] = GRASSIMAGES[0].get_height()
- gr['x'], gr['y'] = getRandomOffCameraPos(camerax, cameray, gr['width'], gr['height'])
- gr['rect'] = pygame.Rect( (gr['x'], gr['y'], gr['width'], gr['height']) )
- return gr
- def isOutsideActiveArea(camerax, cameray, obj):
- # Return False if camerax and cameray are more than
- # a half-window length beyond the edge of the window.
- boundsLeftEdge = camerax - WINWIDTH
- boundsTopEdge = cameray - WINHEIGHT
- boundsRect = pygame.Rect(boundsLeftEdge, boundsTopEdge, WINWIDTH * 3, WINHEIGHT * 3)
- objRect = pygame.Rect(obj['x'], obj['y'], obj['width'], obj['height'])
- return not boundsRect.colliderect(objRect)
- if __name__ == '__main__':
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement