#! /usr/bin/python
import sys, pygame
# =====================================================================
# GLOBAL VARIABLES
# - list all variables that need to be globally accessible
# define the size of the pygame display window
scrSize = scrWidth, scrHeight = 640,480
gameScreen = None # the main display screen
backImage = None # the loaded background image
scrRefreshRate = 40 # the pause (in milliseconds) between updates
keepPlaying = True # flag to identify if the game should continue
# =====================================================================
# SETUP ROUTINE
# - initializes the pygame display screen and background image
def gameSetup():
# specify the global variables the setup routine needs to access
global gameScreen, scrSize, backImage
# initialize pygame
pygame.init()
# initialize the display screen
gameScreen = pygame.display.set_mode(scrSize)
# load and display the background image
backImage = pygame.image.load('backdrop.gif')
gameScreen.blit(backImage, (0,0))
# =====================================================================
# GAME OBJECT
# controls the basic movable in-game objects (ships in this case)
#
# Each game object has several properties:
#
# origImage: the loaded image to represent that object
# image: the current display image for the object
# (rotated and zoomed appropriately from the original)
# position = x,y: the x,y coordinates of the object
# facingDir: the direction the object is currently facing
# velocity: the horizontal/vertical distance covered
# by the object each game step
# scale: the scaling (zoom) factor currently used for the object
# selected: a true/false value indicating if the object is
# currently selected
#
# Each game object also has several actions that can be applied to it:
#
# __init__ : the initialization routine for the object
# update: the routine applied each step to update the
# object's current location and image
# changeFacing: a routine to provide a new facing direction
# for the object
# changeSpeed: a routine to increase or decrease the object's
# current velocity
# changeScale: a routine to zoom in/out on the object
# (scaling the size of its image)
class GameObject(pygame.sprite.Sprite):
# the constructor (initialization routine) for the
# movable game objects
def __init__(self, image, x, y, direction, speed):
# initialize a pygame sprite for the object
pygame.sprite.Sprite.__init__(self)
# load an image for the object
self.origImage = pygame.image.load(image)
self.image = self.origImage
# set up the initial position for the object
self.position = self.x, self.y = x, y
# set up the initial direction for the object
self.facingDir = direction
# set up the initial scale (zoom) for the object
self.scale = 1.0
# set up the initial speed for the object
self.velocity = 1
# initially treat the object as unselected
self.selected = False
# the update routine adjusts the object's current position and
# image based on its speed and direction
def update(self):
# calculate the object's new position based on its old position,
# and its current facing and velocity
if (self.facingDir == 0):
self.x = self.x + self.velocity
self.y = self.y - self.velocity
elif (self.facingDir == 90):
self.x = self.x - self.velocity
self.y = self.y - self.velocity
elif (self.facingDir == 180):
self.x = self.x - self.velocity
self.y = self.y + self.velocity
elif (self.facingDir == 270):
self.x = self.x + self.velocity
self.y = self.y + self.velocity
self.position = self.x, self.y
# update (rotate and zoom) the image for the object
self.image = pygame.transform.rotozoom(self.origImage, self.facingDir, self.scale)
# position the image correctly
self.rect = self.image.get_rect()
self.rect.center = self.position
# the turning routine turns the ship 90 degrees clockwise if
# the turning direction is right ('r') or 90 degrees
# counterclockwise if the turning direction is left ('l')
def changeFacing(self, dir):
# if the direction is left then
# turn the object 90 degrees counterclockwise
if (dir == 'l'):
self.facingDir = self.facingDir + 90
if self.facingDir >= 360:
self.facingDir = self.facingDir - 360
# otherwise, if the direction is right then
# turn the object 90 degrees counterclockwise
elif (dir == 'r'):
self.facingDir = self.facingDir - 90
if self.facingDir < 0:
self.facingDir = self.facingDir + 360
# the speed change routine increases the object's velocity
# if the change is '+', or decreases the velocity
# if the change is '-'
def changeSpeed(self, change):
# if the change is '+' then double the current speed
# (or increase to 1 if the speed used to be 0)
if (change == '+'):
self.velocity = self.velocity * 2
if self.velocity == 0:
self.velocity = 1
# otherwise, if the change is '-' then cut the
# current speed in half
elif (change == '-'):
self.velocity = self.velocity / 2
# the zoom routine zooms in on the object (makes it larger)
# if the scale is '+' or zooms out (makes it smaller)
# if the scale is '-'
def changeScale(self, scale):
# zoom in on the object if the scale is '+'
if (scale == '+'):
self.scale = self.scale * 1.25
# otherwise zoom out if the scale is '-'
elif (scale == '-'):
self.scale = self.scale / 1.25
# the object selection routine notifies the object
# that it has just been selected or deselected
def changeSelected(self, selFlag):
# if the passed flag is True then store the fact that
# this object is now the selected one
if selFlag:
self.selected = True
# otherwise store the fact that this object is no
# longer the selected one
else:
self.selected = False
# =====================================================================
# EVENT HANDLING ROUTINE
# - processes any pending in-game events,
# returns which object is currently selected
# (since this can be changed by some events)
# the routine expects to be given a list of the game objects
# currently available (objList) and which object is
# currently selected/controlled by the player (selObj)
def processEvents(objList, selObj):
# specify which global variables the routine needs access to
global keepPlaying
# process each pending event
for event in pygame.event.get():
# if the user closed the window set keepPlaying to False
# to tell the game to quit playing
if event.type == pygame.QUIT:
keepPlaying = False
# check if the user has pressed a key
elif event.type == pygame.KEYDOWN:
# the escape and q keys quit the game
if event.key == pygame.K_ESCAPE:
keepPlaying = False
elif event.key == pygame.K_q:
keepPlaying = False
# the left and right arrows turn the currently selected ship
# counterclockwise or clockwise, respectively
elif event.key == pygame.K_LEFT:
print 'turning left with ship ', selObj
objList[selObj].changeFacing('l')
elif event.key == pygame.K_RIGHT:
print 'turning right with ship ', selObj
objList[selObj].changeFacing('r')
# the up and down arrows cause the currently selected ship
# to speed up or slow down, respectively
elif event.key == pygame.K_UP:
print 'speeding up ship ', selObj
objList[selObj].changeSpeed('+')
elif event.key == pygame.K_DOWN:
print 'slowing down ship ', selObj
objList[selObj].changeSpeed('-')
# the plus and minus keys zoom in/out on the currently
# selected ship
elif event.key == pygame.K_EQUALS:
print 'zooming in on ship ', selObj
objList[selObj].changeScale('+')
elif event.key == pygame.K_MINUS:
print 'zooming out on ship ', selObj
objList[selObj].changeScale('-')
# the tab key scrolls through the list of ships,
# changing which one is currently selected
elif event.key == pygame.K_TAB:
objList[selObj].changeSelected(False)
selObj = selObj + 1
if (selObj >= len(objList)):
selObj = 0
objList[selObj].changeSelected(True)
print 'selected ship ', selObj
# return the currently selected object number
# (may have been updated by one of the events processed)
return selObj
# =====================================================================
# MAIN GAME CONTROL ROUTINE
# - sets up the game and runs the main game update loop
# until instructed to quit
def main():
# identify any global variables the main routine needs to access
global gameScreen, backImage, scrRefreshRate, keepPlaying
# initialize pygame and the game's display screen
gameSetup()
# create the list of screen update sections (rectangles)
updateSections = None
# create an array of objects to add to the display,
# giving each of them
# an image, xcoord, ycoord, facing, and speed
gameObjList = [
GameObject('ship.gif', 80, 60, 270, 2),
GameObject('ship.gif', 560, 60, 180, 0),
GameObject('ship.gif', 560, 420, 90, 1)
]
# indicate which game object is currently 'selected'
selectedObj = 0
gameObjList[selectedObj].changeSelected(True)
# create a group for the game objects
objGroup = pygame.sprite.RenderUpdates(*gameObjList)
# run the main game loop
keepPlaying = True
while keepPlaying:
# handle any pending events
# (processEvents needs the list of objects that might
# be affected, and which object is currently selected)
selectedObj = processEvents(gameObjList, selectedObj)
# update the display of the object groups
objGroup.clear(gameScreen, backImage)
# run the updates on each object in the group
objGroup.update()
# update the display rectangles
updateSections = objGroup.draw(gameScreen)
# update the buffered display
pygame.display.update(updateSections)
# switch to the new display image
pygame.display.flip()
# pause before initiating the next loop cycle
pygame.time.delay(scrRefreshRate)
# =====================================================================
# INITIATE THE GAME
# - calls the main() routine
if __name__ == "__main__":
main()
|