PyGame Text

The writing is on the screen!

Introduction

In this section we will look at how you include and manipulate text in Pygame. Text is valuable for many aspects of a good game. Text can be a little bit fiddly to set up in PyGame but once you have it set up it's fairly easy to work with.

Getting Set Up

Before we begin, let's create a new file (call it text.py) and copy in the template code from the previous section

Once you've saved your file with the template code in it, run the file to make sure you've copied it in ok. (You should get a blank white window.)

Including Text - The Simple Method

Including text in PyGame may be done as a three step process :

  • Load the font for the text
  • Render the text you want to a Text surface object
  • Blit the text to the display surface (window)

Let's start by adding a variable with a colour for our text (place it just below the existing BACKGROUND variable) :

  • # Colours
  • BACKGROUND = (255, 255, 255)
  • TEXTCOLOUR = (200, 100, 0)
  •  
  • # Game Setup

Next up we will add a few commands to render a basic text message in the center of the window :

  • pygame.display.set_caption('My Game!')
  •  
  • # set up Fonts
  • fontObj = pygame.font.Font(None, 32)
  • textSufaceObj = fontObj.render('blah blah', True, TEXTCOLOUR, None)
  •  
  • # The main function that controls the game

What this does is :

  • Create a font Object (fontObj) with the required font. (In this example we are just loading the PyGame default font by specifying it as 'None'). We also specify the size of the font here as well (32)
  • Create a surface object (textSurfaceObj) to hold the text we want to display. When we render we pass in four arguments :
    • The text to render ('blah blah')
    • If we are antialaising the text or not (True)
    • The colour of the text (TEXTCOLOUR)
    • The background colour of the surface (None - which means transparent)

Finally we will blit the surface to the window :

  •     WINDOW.fill(BACKGROUND)
  •     WINDOW.blit(textSufaceObj, (100, 100))
  •     pygame.display.update()

Basic PyGame TextIf you save and run the program now you should get a window with some text near the center.

See if you can change the size, location and colour of the text.

Which fonts are available

The default font is a little bit boring. Thankfully it is very easy to change this. Your system will have a heap of built in fonts (any of which may be used). If you want to see what fonts are already available on your system, create a simple script as follows :

Installed-fonts.py

  1. import pygame, sys, random
  2. from pygame.locals import *
  3. pygame.init()
  4.  
  5. fontsList = pygame.font.get_fonts()
  6. print (fontsList)

Any of the fonts in this list may then be utilised by replacing None (in the initial program) with the name of the font (within quotes) and changing Font to SysFont when loading the font. eg :

  • pygame.display.set_caption('My Game!')
  •  
  • # set up Fonts
  • # fontObj = pygame.font.Font(None, 32)
  • fontObj = pygame.font.SysFont('courier', 32)
  • textSufaceObj = fontObj.render('blah blah', True, TEXTCOLOUR, None)
  •  
  • # The main function that controls the game

Loading your own fonts

The system fonts provide some variability in the look of the fonts but for a game we often want something a bit more exciting / suited to the style of our game interface. Fortunately it is very simple to find and use other fonts.

Any font in the .ttf (True Type Font) can be used. Let's say we have a folder called fonts which is in the same location as our program. Including it is as simple as using the path to the font file :

  • pygame.display.set_caption('My Game!')
  •  
  • # set up Fonts
  • fontObj = pygame.font.Font(None, 32)
  • fontObj = pygame.font.Font('fonts/Bullpen3D.ttf', 32)
  • textSufaceObj = fontObj.render('blah blah', True, TEXTCOLOUR, None)
  •  
  • # The main function that controls the game

Basic PyGame Text with loaded fontIf you find and download a font then update the program with the name of the font and run the program now you should get a window with some text near the center in your chosen font.

There are many locations where you can obtain fonts to use in your games. Try doing a Google search for free fonts and you will find many websites to start from.

Including Text - Advanced Method

The simple method for including text works well enough but sometimes we need a bit more ability to manage placement of the text. We may achieve this by using a rect object to hold the text. Then we may use the features of the rect object to help with placement.

Text_Advanced.py

  1. import pygame, sys, random
  2. from pygame.locals import *
  3. pygame.init()
  4.  
  5. # Colours
  6. BACKGROUND = (255, 255, 255)
  7. TEXTCOLOUR = (200, 100, 0)
  8.  
  9. # Game Setup
  10. FPS = 60
  11. fpsClock = pygame.time.Clock()
  12. WINDOW_WIDTH = 400
  13. WINDOW_HEIGHT = 300
  14.  
  15. WINDOW = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
  16. pygame.display.set_caption('My Game!')
  17.  
  18. # Set up fonts
  19. fontObj = pygame.font.Font(None, 32)
  20. textSufaceObj = fontObj.render('blah blah', True, TEXTCOLOUR, None)
  21. textRectObj = textSufaceObj.get_rect()
  22. # The main function that controls the game
  23. def main () :
  24.   looping = True
  25.   
  26.   # The main game loop
  27.   while looping :
  28.     # Get inputs
  29.     for event in pygame.event.get() :
  30.       if event.type == QUIT :
  31.         pygame.quit()
  32.         sys.exit()
  33.     
  34.     # Processing
  35.     # This section will be built out later
  36.  
  37.     # Render elements of the game
  38.     WINDOW.fill(BACKGROUND)
  39.     WINDOW.blit(textSufaceObj, textRectObj)
  40.     pygame.display.update()
  41.     fpsClock.tick(FPS)
  42.  
  43. main()

Line 21 - we create a rect object which will have the same dimensions as the text surface.

Line 41 - we blit the textSurfaceObj but use the textRectObj to get the coordinates for where to place it.

If you run the script you will notice that the text is placed in the top left corner of the window. That is because we haven't moved the rect object from its default location yet.

The rect object isn't the actual text but a rectangle which has the same dimensions as the text. We may now use the rectangle's virtual attributes for location in order to more accurately place the text, or discover the width and height of the text. Here are the virtual attributes we can take advantage of :

  • x, y
  • top, left, bottom, right
  • topleft, bottomleft, topright, bottomright
  • midtop, midleft, midbottom, midright
  • center, centerx, centery
  • size, width, height
  • w, h

Let's say that part of the interface of our game is a line along the bottom of the screen, and we would like to place our text in the middle of that line, 15 pixels above it. This now becomes very easy.

  • pygame.display.set_caption('My Game!')
  •  
  • BOTTOMLINEHEIGHT = 20
  •  
  • # set up Fonts
  • fontObj = pygame.font.Font(None, 32)
  • textSufaceObj = fontObj.render('blah blah', True, TEXTCOLOUR, None)
  • textRectObj = textSufaceObj.get_rect()
  • textRectObj.midbottom = (WINDOW_WIDTH // 2, WINDOW_HEIGHT - BOTTOMLINEHEIGHT - 15)
  •  
  • # The main function that controls the game
  •     WINDOW.fill(BACKGROUND)
  •     WINDOW.blit(textSufaceObj, textRectObj)
  •     pygame.draw.line(WINDOW, TEXTCOLOUR, (0, WINDOW_HEIGHT - BOTTOMLINEHEIGHT), (WINDOW_WIDTH, WINDOW_HEIGHT - BOTTOMLINEHEIGHT), 3)
  •     pygame.display.update()

Advanced placement of textYou could have achieved the same outcome using the simple method for rendering text and trial and error with the coordinates. This method will save you time and effort however, especially if you have several items you want to accurately place.

A Simple Text Game

In this simple game we will print either Left or Right. The player has to press the opposite arrow key on the keyboard as fast as they can.

Simple_Text_Game.py

  1. import pygame, sys, random
  2. from pygame.locals import *
  3. pygame.init()
  4.  
  5. # Colours
  6. BACKGROUND = (255, 255, 255)
  7. TEXTCOLOUR = (200, 100, 0)
  8.  
  9. # Game Setup
  10. FPS = 60
  11. fpsClock = pygame.time.Clock()
  12. WINDOW_WIDTH = 400
  13. WINDOW_HEIGHT = 300
  14.  
  15. WINDOW = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
  16. pygame.display.set_caption('My Game!')
  17.  
  18. # Set up fonts
  19. rightText = fontObj.render('Right', True, TEXTCOLOUR, None)
  20. leftText = fontObj.render('Left', True, TEXTCOLOUR, None)
  21. rightTextRectObj = rightText.get_rect()
  22. leftTextRectObj = leftText.get_rect()
  23. # Center the text on the window
  24. rightTextRectObj.center = (WINDOW_WIDTH // 2, WINDOW_HEIGHT //2)
  25. leftTextRectObj.center = (WINDOW_WIDTH // 2, WINDOW_HEIGHT //2)
  26.  
  27.  
  28. # Selects ramdomly either Left or Right
  29. def select_side () :
  30.   side = ''
  31.   chosen = random.randint(0,1)
  32.   if chosen == 1 :
  33.     side = 'Right'
  34.   else :
  35.     side = 'Left'
  36.   
  37.   return side
  38.   
  39.  
  40. # The main function that controls the game
  41. def main () :
  42.   looping = True
  43.    
  44.   target = select_side() # Prime the target before the main loop
  45.   goes = 0 # How many goes the user has had
  46.   score = 0
  47.   rounds = 10 # How many rounds in the game
  48.   active = True # Used so that the next target won't be set until the user releases the key on the keyboard
  49.  
  50.   # The main game loop
  51.   while looping :
  52.     sideChosen = ''
  53.  
  54.     # Get inputs
  55.     for event in pygame.event.get() :
  56.       if event.type == QUIT :
  57.         pygame.quit()
  58.         sys.exit()
  59.       
  60.     pressed = pygame.key.get_pressed()
  61.     if pressed[K_RIGHT] :
  62.       sideChosen = 'Right'
  63.     elif pressed[K_LEFT] :
  64.       sideChosen = 'Left'
  65.  
  66.   
  67.     # Processing
  68.     if sideChosen != '' and sideChosen != target and active == True :
  69.       print ('Correct')
  70.       goes = goes + 1
  71.       score = score + 1
  72.       active = False
  73.     elif sideChosen == target and active == True :
  74.       print ('Incorrect')
  75.       goes = goes + 1
  76.       active = False
  77.     elif active == False and sideChosen == '' : # Enable the next round
  78.       active = True
  79.       target = select_side()
  80.     
  81.     if goes == rounds :
  82.       looping = False
  83.   
  84.   
  85.     # Render elements of the game
  86.     WINDOW.fill(BACKGROUND)
  87.     if target == 'Right' and active == True :
  88.       WINDOW.blit(rightText, rightTextRectObj)
  89.     elif target == 'Left' and active == True :
  90.       WINDOW.blit(leftText, leftTextRectObj)
  91.     pygame.display.update()
  92.     fpsClock.tick(FPS)
  93.   
  94.   print ('Game Over')
  95.   print (f'Your score was : {score}')
  96.  
  97. main()
  98.  

There is a lot that could be improved with this game. It is intended simply to illustrate including text within your games. Check out the activities below for ideas on how you could improve it.

Activities

Even though our program doesn't do too much just yet we can still tinker with a few elements to make sure we understand them.

Have a go at the following :

1. Can you improve your game so that it has up and down as well as left and right?

2. Can you make it to that the score is printed to the window as well? (instead of to the terminal)

3. Can you use shapes and other elements to create a more interesting interface for your game?

4. (extra challenging) The game in its current form doesn't actually incorporate how fast the user was to select their answer. Can you improve the game so that the score is also based upon how quickly the user enters the answer?