PyGame for Game Development: Font and Sprites

PyGame is a library for Python that allows you to develop computer games. It is also useful for very graphical applications. This article will help you grasp the basics of PyGame.

Introduction

Though game development with Python and C++ is becoming more popular (take a look at Civilization IV), game development with Python alone is largely limited to hobbyist use. It is possible, however, with PyGame, a library written around the Simple DirectMedia Layer (SDL). PyGame isn’t limited to game development, either. It can also be used in applications that require very graphical interfaces. In this article, we’ll look into the basics of how PyGame is used.

PyGame may be obtained at its website, which also contains links to a number of projects written in PyGame:

http://pygame.org/

Download and install PyGame, and we’ll be ready to begin.

Getting Started

The first thing we’ll do with PyGame is open up a PyGame window with a certain size and caption. We’ll also fill it up with a background color and keep the window open until the user decides to quit:

import pygame
import sys

# Initialize pygame
pygame.init()

# Create the drawing screen
screen = pygame.display.set_mode((256, 256))

# Set the caption
pygame.display.set_caption(‘Application’)

# Set a background color
screen.fill((159, 182, 205))

# Update the screen
pygame.display.update()

# Wait for the user to quit
while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         sys.exit()

The above application is pretty simple to understand. We start out by initializing PyGame. Then, we create the window and a drawing screen, passing a tuple with the drawing screen dimensions. Next, we use the set_caption method to set a caption. We then fill the screen with a background color, passing a tuple of values for red, green and blue that generate a nice bluish color. When we make a change to the screen, we have to call update to display the change. Finally, we wait for the user to quit the application. The pygame.event.get method returns a list of events when called, and we examine this list for a pygame.QUIT event.

The pygame.QUIT constant is simply an integer. Each event type—whether it’s for a key push or a mouse click—is a unique integer. An Event object returned by pygame.event.get also has other attributes that we can examine, depending on what type of event it is. For example, an Event object that represents a key push, pygame.KEYDOWN, contains a key attribute that contains the key pushed.

It is important to note exactly what screen is in this example. The screen object is a Surface object, which may be drawn on. Here, we fill it with a color, but note that we could also create a Surface and load an image onto it. Every image you create will be a Surface. Knowing this is important because Surface objects will be the building blocks of your applications.

{mospagebreak title=Using Images}

A solid background might get a bit dull, however, so let’s create a graphical background by tiling an image across the screen. We’ll use a simple cross for our tile so that the end result will look something like a blank graph. Download this image and put it in the directory where you plan to create the next script:


Tiling the above image requires creating a rectangle the size of the image and moving it across the screen, drawing the image at every position:

import pygame
import sys

pygame.init()
screen = pygame.display.set_mode((256, 256))
pygame.display.set_caption(‘Tiled Background’)

# Load the background image
graphTile = pygame.image.load(‘graphbackground.bmp’).convert()

# Create a rectangle based on the image
graphRect = graphTile.get_rect()

# Determine the number of rows and columns of tiles
rows = int(256/graphRect.height) + 1
columns = int(256/graphRect.width) + 1

# Loop and draw the background
for y in xrange(rows):
   for x in xrange (columns):

      # Start a new row
      if x == 0 and y > 0:
         # Move the rectangle
         graphRect = graphRect.move([-(columns -1 ) * graphRect.width, graphRect.height])
      # Continue a row
      if x > 0:
         # Move the rectangle
         graphRect = graphRect.move([graphRect.width, 0])

      # Draw the tile
      screen.blit(graphTile, graphRect)

pygame.display.update()

while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         sys.exit()

The application starts the same as the previous one, but things change when we get to the background. The first thing we do is load our tile into graphTile. In the process, we call the convert method. This method basically prepares the image to be displayed. We can still draw the tile image without it, but the drawing speed will suffer. Next, we create a rectangle based on the tile image’s dimensions. This rectangle will be used to draw the tile on the screen. We then determine the number of rows and columns of tiles there will be, making sure to round up so that we don’t end up with less tiles than it takes to fill the screen completely. We loop through so that we can access each row and column, and we use the move method on graphRect, which simply moves the rectangle by the number of pixels specified, to put the rectangle in the appropriate row and column. The tile is drawn (“blitted”) into each position. Finally, we update the screen and wait for the user.

This same method of loading an image and drawing it inside of a rectangle is, of course, not limited to what we use it for here. This principle can be applied anytime you want to load an image. I just think that tiling is a much more productive way to demonstrate images, rather than simply rendering a Python logo in the middle of the screen.

{mospagebreak title=Adding Text}

PyGame also makes it easy to insert text into applications. The pygame.font module is responsible for this, and it can be done in just a few lines of Python:

import pygame
import sys

pygame.init()
screen = pygame.display.set_mode((256, 256))
pygame.display.set_caption(‘Application’)
screen.fill((159, 182, 205))

# Create a font
font = pygame.font.Font(None, 17)

# Render the text
text = font.render(‘Powered by Python and PyGame’, True, (255,
255, 255), (159, 182, 205))

# Create a rectangle
textRect = text.get_rect()

# Center the rectangle
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery

# Blit the text
screen.blit(text, textRect)

pygame.display.update()

while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         sys.exit()

We start by calling the Font method, passing two arguments. The first argument is the filename of the text to use, but since we pass None, a generic font is used. The second argument is simply the size of the font, which we set to 17. We must then render the text we want using the font. To do this, we pass four arguments to render. The first argument is, obviously, the text that is to be rendered. The second is a boolean value that indicate whether or not antialiasing is to be used. The third argument is the color of the font, and the fourth argument is the background color. If the fourth argument is missing, the background becomes transparent. However, this is slow, and since we know what color the background will be already, we can just pass the color as an argument. Next, we create a rectangle and use centerx and centery to center it in the screen. Finally, we blit the text.

PyGame also supports some text effects—bold text and italicized text. Bolding or italicizing a font involves calling a single method:


font.set_italic(True)
font.set_bold(True)

It’s possible to search for a specific font on the user’s computer, and it’s also possible to get a list of the user’s fonts. We can also specify a list of fonts and have PyGame return the first match. This way, your application can fall back on another font if the best font isn’t available:

import pygame
import random
import sys

pygame.init()
screen = pygame.display.set_mode((256,256))
pygame.display.set_caption(‘Application’)
screen.fill((159, 182, 205))

# Search for Verdana and create a Font object
verdana = pygame.font.match_font(‘Verdana’)
verdanaFont = pygame.font.Font(verdana, 13)

# Search for a font that does not exist and create a Font object
doesNotExist = pygame.font.match_font(‘doesNotExist’)
dNEFont = pygame.font.Font(doesNotExist, 13)

# Search for a font that does not exist, followed by Arial, and create a Font object
arial = pygame.font.match_font(‘doesNotExist,Arial’)
arialFont = pygame.font.Font(arial, 13)
print arial, arialFont

# Get a list of fonts
fonts = pygame.font.get_fonts()

# Create some random fonts
# get_fonts() merely returns a list of names, so we’ll have to
match them
font1 = pygame.font.Font(pygame.font.match_font(random.choice
(fonts)), 13)
font2 = pygame.font.Font(pygame.font.match_font(random.choice
(fonts)), 13)
font3 = pygame.font.Font(pygame.font.match_font(random.choice
(fonts)), 13)

# Render text in verdana, doesNotExist, arial and the random
fonts
text1 = verdanaFont.render(str(verdana), 1, (255, 255, 255),
(159, 182, 205))
text2 = dNEFont.render(str(doesNotExist), 1, (255, 255, 255),
(159, 182, 205))
text3 = arialFont.render(str(arial), 1, (255, 255, 255), (159,
182, 205))
text4 = font1.render(‘Random’, 1, (255, 255, 255), (159, 182,
205))
text5 = font2.render(‘Random’, 1, (255, 255, 255), (159, 182,
205))
text6 = font3.render(‘Random’, 1, (255, 255, 255), (159, 182,
205))

# Make some rectangles
rect1 = text1.get_rect()
rect2 = text2.get_rect()
rect3 = text3.get_rect()
rect4 = text4.get_rect()
rect5 = text5.get_rect()
rect6 = text6.get_rect()

# Position the rectangles
rect1.y, rect1.centerx = 0, screen.get_rect().centerx
rect2.y, rect2.centerx = 20, screen.get_rect().centerx
rect3.y, rect3.centerx = 40, screen.get_rect().centerx
rect4.y, rect4.centerx = 60, screen.get_rect().centerx
rect5.y, rect5.centerx = 80, screen.get_rect().centerx
rect6.y, rect6.centerx = 100, screen.get_rect().centerx

# Blit everything
screen.blit(text1, rect1)
screen.blit(text2, rect2)
screen.blit(text3, rect3)
screen.blit(text4, rect4)
screen.blit(text5, rect5)
screen.blit(text6, rect6)

pygame.display.update()

while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         sys.exit()

Here, we simply search for some fonts and then get three random fonts, displaying a string of text in each font. Notice how None is returned if a font does not exist. This is why it’s a good idea to either specify a list of fonts or include the fonts you’ll be using (provided that you are allowed to).

{mospagebreak title=Sprites}

Sprites are simply images that exist in the context of your background. They can be players, pickups or whatever. It’s possible to simply load regular images and use them instead. Either way, you end up with the same thing. However, sprites simplify this, especially in more complicated situations where you have various images on the screen, and provide an object-oriented approach to it all.

Let’s create a sprite by the name of StickMan based on this image:


We simply need to subclass pygame.sprite.Sprite, setting the image and the proper rectangle as an attribute. Then, we can blit it on to the screen:

import pygame
import sys

# Subclass pygame.sprite.Sprite
class StickMan(pygame.sprite.Sprite):

   def __init__(self, position):

      # Call pygame.sprite.Sprite.__init__ to do some internal
work
      pygame.sprite.Sprite.__init__(self)

      # Load the stickMan
      self.image = pygame.image.load(‘stickMan.gif’).convert()

      # Create a rectangle
      self.rect = self.image.get_rect()

      # Position the rectangle
      self.rect.x = position[0]
      self.rect.y = position[1]

pygame.init()
screen = pygame.display.set_mode((256, 256))
pygame.display.set_caption(‘Sprite Example’)
screen.fill((159, 182, 205))

# Create a StickMan sprite
character = StickMan((screen.get_rect().x, screen.get_rect().y))

# Blit the sprite
screen.blit(character.image, character.rect)

pygame.display.update()

while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         sys.exit()

The sprite is rendered, but what if we want to move the sprite when a user presses a key? This requires waiting for the user to press a key, moving the sprite and erasing its old location. Let’s extend our application to do this:

import pygame
import sys

class StickMan(pygame.sprite.Sprite):

   def __init__(self, position):

      pygame.sprite.Sprite.__init__(self)

      # Save a copy of the screen’s rectangle
      self.screen = pygame.display.get_surface().get_rect()

      # Create a variable to store the previous position of the
sprite
      self.old = (0, 0, 0, 0)

      self.image = pygame.image.load(‘stickMan.gif’).convert()
      self.rect = self.image.get_rect()
      self.rect.x = position[0]
      self.rect.y = position[1]

   def update(self, amount):

      # Make a copy of the current rectangle for use in erasing
      self.old = self.rect

      # Move the rectangle by the specified amount
      self.rect = self.rect.move(amount)

      # Check to see if we are off the screen
      if self.rect.x < 0:
         self.rect.x = 0
      elif self.rect.x > (self.screen.width – self.rect.width):
         self.rect.x = self.screen.width – self.rect.width
      if self.rect.y < 0:
         self.rect.y = 0
      elif self.rect.y > (self.screen.height – self.rect.height):
         self.rect.y = self.screen.height – self.rect.height

pygame.init()
screen = pygame.display.set_mode((256, 256))
pygame.display.set_caption(‘Sprite Example’)
screen.fill((159, 182, 205))

character = StickMan((screen.get_rect().x, screen.get_rect().y))
screen.blit(character.image, character.rect)

# Create a Surface the size of our character
blank = pygame.Surface((character.rect.width, character.rect.height))
blank.fill((159, 182, 205))

pygame.display.update()

while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         sys.exit()

      # Check for movement
      elif event.type == pygame.KEYDOWN:
         if event.key == pygame.K_LEFT:
            character.update([-10, 0])
         elif event.key == pygame.K_UP:
            character.update([0, -10])
         elif event.key == pygame.K_RIGHT:
            character.update([10, 0])
         elif event.key == pygame.K_DOWN:
            character.update([0, 10])

      # Erase the old position by putting our blank Surface on it
      screen.blit(blank, character.old)

      # Draw the new position
      screen.blit(character.image, character.rect)

      # Update ONLY the modified areas of the screen
      pygame.display.update([character.old, character.rect])

The first change in the StickMan class is the addition of screen. This is simply a copy of the screen’s rectangle and is used to check whether the sprite has gone off the screen. We also add old, which is also a rectangle. When the sprite is updated, we store its old rectangle here so that our program knows what to erase. The update method simply moves the sprite and checks to see if it has gone partially off the screen. If it has, then it’s bumped back on to the screen.

Further down, we define blank, a Surface object that is blitted over the old position of the character sprite each time the sprite moves. We then check for keyboard input, moving the sprite ten pixels in the appropriate direction if the user has pressed one of the arrow keys. This is done by calling the update method described above. Next, we erase the old position by blitting blank over it, and we draw the new position. Finally, we make a call to update. However, note that we supply a list as an argument. The list contains character’s old and new positions. By doing this, we tell PyGame only to update those areas of the screen. If we were to update the whole screen, then PyGame would have to redraw everything. This simply wastes resources since we have no need to update the entire screen when only two things have changed.

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort