Menu

Pygame Text: Render Text on the Screen

Draw text in pygame: make a Font, render() the text into a Surface, then blit it. Learn centering, a live score, text with a background, several lines, and why text should be rendered only when it changes.

This page includes runnable editors. Edit, run, and see output instantly.

Pygame does not draw text directly. You render the text with a font, which gives you a Surface, and then blit that Surface like any image:

The three steps

  1. Make a font once, before the loop: pygame.font.Font(None, 36). None means pygame's built-in font; 36 is the size in pixels. Pygame fonts covers system fonts and font files.
  2. Render: font.render(text, antialias, color, background=None) returns a Surface with the text on it. antialias=True smooths the edges.
  3. Blit that Surface at a position or a Rect.

text.get_rect(center=(x, y)) centers it; get_rect(topright=(470, 10)) puts it in the corner, and so on.

A changing score

Text that changes, such as a score, is rendered again when it changes. Rendering is slower than blitting, so a common pattern is to render only when the value is different:

Press Play, click the game and press Space to add points. For a few labels, rendering every frame is fine too; the cache matters when a game shows many changing numbers.

Background, outline and shadow

The fourth argument of render paints a solid box behind the text:

label = font.render("PAUSED", True, "white", (0, 0, 0))

For a drop shadow, render the text twice in two colors and blit the dark copy a couple of pixels down and right first:

shadow = font.render("Game Over", True, (0, 0, 0))
text = font.render("Game Over", True, (255, 80, 80))
screen.blit(shadow, (102, 102))
screen.blit(text, (100, 100))

Several lines

pygame-ce's render() breaks lines at \n, and its fifth argument, wraplength, wraps long text at that many pixels:

The original pygame does not break lines at \n and has no wraplength. There, split the text yourself and blit one line under the other:

for i, line in enumerate(lines):
    surface = font.render(line, True, "white")
    screen.blit(surface, (40, 44 + i * font.get_linesize()))

Measuring text

font.size("Hello") returns the width and height the text would take, without rendering it, which helps to lay out menus. font.get_linesize() is the recommended distance between lines.

Frequently Asked Questions

How do I display text in pygame?

Make a font once, font = pygame.font.Font(None, 36), render the text into a Surface, text = font.render("Hello", True, (255, 255, 255)), and blit it: screen.blit(text, (20, 20)).

How do I center text in pygame?

Get a Rect from the rendered text placed by its center, then blit at that Rect: screen.blit(text, text.get_rect(center=(240, 180))).

What does the True in font.render mean?

Anti-aliasing. True smooths the edges of the letters; False draws hard pixel edges, which suits pixel fonts.

How do I show text on several lines?

In pygame-ce, render() breaks lines at \n and can wrap long text with its wraplength argument. In the original pygame, render each line separately and blit them one below the other, stepping by font.get_linesize().

Coddy programming languages illustration

Learn to code with Coddy

Get started