Important Note

Tufts ended funding for its Open Courseware initiative in 2014. We are now planning to retire this site on June 30, 2018. Content will be available for Tufts contributors after that date. If you have any questions about this please write to edtech@tufts.edu.

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?