Tufts OpenCourseware
Search
Author: Ming Y Chow

Tufts OpenCourseWare
Introduction to Game Development
M. Chow
Spring 2012

 

Sprites and Animation

Last Week

  • Image rendering
  • Exception handling
  • Storytelling

Drawing

  • Screen.blit()
  • Change background color or clear the background:
    • background = pygame.Surface(screen.get_size())
    • background = background.convert()
    • background.fill((255, 0, 0))
    • screen.blit(background, (0, 0))
    • Or simply do screen.fill()

Font and Drawing Strings

  • Font = pygame.font.Font(). The constructor takes in a truetype font file or None which will use the default Pygame font, and font size
  • Text = font.render(). The render() method takes in three arguments: the text string, a flag (0 or 1) to use antialiased text, and RGB color tuple
  • Draw the text onto surface via background.blit()
  • Documentation: http://www.pygame.org/docs/ref/font.html
  • Example:
    font = pygame.font.Font(None, 28)
    text = font.render("Score: 1000", 1, (0, 0, 0))
    screen.blit(text, (10, 10))
    

Sound

  • Sound = pygame.mixer.Sound()
  • Like images, Sound() takes in one parameter: sound file name
  • sound.play()
  • Sound types supported: .ogg, .wav. mp3
  • Like images, sounds must be in the same folder as the .py file. You can also specify path to sound.
  • Example:
    boing_sound = pygame.mixer.Sound("boing.wav")
    boing_sound.play()
    

Exception Handling

  • Exception - Errors detected during execution
  • What if the image or sound file could not be found?
  • In fact if image could not be loaded, your game hangs
  • Try except block
  • The equivalent in Java is try catch
  • Example 1, bad input:
    try:
    	x = int(raw_input("Please enter a number: "))
    	break
    except ValueError:
    	print "Oops!  That was no valid number.  Try again..."
    
  • Example 2, the proper way to load an image:
    def load_image(image_name):
    	try:
    		image = pygame.image.load(image_name)
    	except pygame.error, message:
    		print "Cannot load image: " + image_name
    		raise SystemExit, message
    	return image.convert_alpha()
    
  • Example 3, the proper way to load a sound:
    def load_sound(sound_name):
    	try:
    		sound = pygame.mixer.Sound(sound_name)
    	except pygame.error, message:
    		print "Cannot load sound: " + sound_name
    		raise SystemExit, message
    	return sound
    

Sprites

  • Sprite - Any object that appears on the screen
  • Overlayed on background
  • Can be an image or drawing
    • Can be motionless (dull)
    • Can be animated: move around the screen randomly
    • Even better: can respond to the environment
  • Hopefully, your sprite images have transparent pixels
  • We have already did most of the work for creating a sprite. Relatively easy:
    • Keep track of the x and y coordinates
    • Images should be optimized (with transparent background)
    • Draw the sprite
    • Update the sprite (e.g., coordinates, speed)
    • Keep track of it's state (e.g., hidden/shown)

Pygame's Sprite Class

  • Base class
  • Documentation: http://www.pygame.org/docs/ref/sprite.html
  • All sprites must have an update() method and a draw() method. These function is typically called once per frame!
  • Several different kind of sprite classes: pygame.sprite.Sprite (simple) pygame.sprite.DirtySprite (advanced)
  • Very lightweight
  • Contains collision detection methods (more later)
  • To use the pygame.sprite.Sprite base class:
    class MySprite(pygame.sprite.Sprite):
    	def __init__(self):
    		pygame.sprite.Sprite.__init__(self) #call Sprite intializer
    	...
    	...
    	...
    

Example: SimpleSprite

class SimpleSprite(pygame.sprite.Sprite):
	''' A simple sprite that bounces off the walls '''
	
	def load_image(self, image_name):
		''' The proper way to load an image '''
		try:
			image = pygame.image.load(image_name)
		except pygame.error, message:
			print "Cannot load image: " + image_name
			raise SystemExit, message
		return image.convert_alpha()

	def __init__(self, screen, img_filename, init_x, init_y, init_x_speed, init_y_speed):
		''' Remember to pass the surface to the sprite for updating and drawing! '''
		pygame.sprite.Sprite.__init__(self) #call Sprite intializer
		self.screen = screen
		
		# Load the image
		self.image = self.load_image(img_filename)
		self.rect = self.image.get_rect() # Set the rect attribute for the sprite (absolutely necessary for collision detection)

		# Get the image's width and height
		self.image_w, self.image_h = self.image.get_size()
				
		# Set the (x, y)
		self.x = init_x
		self.y = init_y
		
		# Set the default speed (dx, dy)
		self.dx = init_x_speed
		self.dy = init_y_speed
				
	def update(self):
		''' Move the sprite; bounce off the walls '''
		if ((self.x + self.dx) <= 0):
			self.dx = self.dx * -1
		if ((self.x + self.dx) >= self.screen.get_size()[0]):
			self.dx = self.dx * -1
		if ((self.y + self.dy) <= 0):
			self.dy = self.dy * -1
		if ((self.y + self.dy) >= self.screen.get_size()[1]):
			self.dy = self.dy * -1
		self.x = self.x + self.dx
		self.y = self.y + self.dy
	
	def draw(self):
		''' Draw the sprite on the screen '''
		draw_pos = self.image.get_rect().move(self.x - self.image_w / 2, self.y - self.image_h / 2)
		self.screen.blit(self.image, draw_pos)

Handling Frames Per Second (FPS)

  • A frame is one pass through the update-render-sleep loop
  • Theoretically, the loop's execution speed should be about the same on all platforms
    • On a slow machine => too slow => unplayable game
    • On a fast machine => too fast => unplayable game
  • Compute the estimated required delay between frames based on the current time. Keep track of the starting time.
  • There are many ways to optimize the FPS and thread sleeping times
  • The rule of thumb is that anything 30 updates per second or faster is good enough and looks smooth to the average person

The Timer in Pygame

  • Times in pygame are represented in milliseconds (1/1000 seconds)
  • clock = pygame.time.Clock()
  • clock.tick(). This is to be called once per frame. Important: the required parameter to tick() function is a framerate!
  • Example (30 FPS):
    clock = pygame.time.Clock()
    clock.tick(30)
    

Question: How Do You Animate A Sprite?