Pygame Tutorial

Introduction – Pygame Tutorial

This Pygame Tutorial will help you understand the basics and help you to get started with Pygame.

Python is the most advanced and widely-used programming language. There are libraries in python that make it so much flexible and make it thrive in every field of Machine Learning (Numpy, Pandas, Matplotlib), Artificial intelligence (Pytorch, TensorFlow), and Game development (Pygame, Pyglet).

What is Pygame?

Pygame is a set of python modules that were designed to help in writing video games and other multimedia applications.

Before starting to build any kind of game, you need to ask yourself some questions mentioned below:

  1. What sort of game do you want to build?
  2. What kind of language do you want to use to build a game?
  3. What kind of platform do you want to deploy your game to?

For PyGame, let’s assume you have the following answers for the above three questions:

  • You want to create a graphical game, not 3D.
  • As you already know the basics of python, you want to program it in Python as well.
  • You’d like to make a client programme that could be packaged as a standalone executable.

Once you have answers to all the questions mentioned above, you are ready to dive into the world of pygame.

Pygame requires Python. You can download it from python.org.

Command to install pygame:

pip install pygame

Syntax Definitions

Here is a definition of some syntax we will:

import pygame —  This is often, in fact, needed to access the PyGame framework.

pygame.init() — Used to initialises all the modules required for pygame. It must be called just after the importing pygame.

pygame.display.set_mode((width, height)): Make a window the size you want. The return value might be a Surface object, which is the object on which you’ll perform graphical operations.

pygame.event.get(): The event queue is now empty. If you do not call this, the windows messages will begin to accumulate, and your game will become sluggish in the OS’s viewpoint.

pygame.QUIT : This is often the event type that’s fired once you click on the close button within the corner of the window.

pygame.display.flip(): This swaps the buffers.  All you would like to understand is that this call is required to make any updates that you simply make to the sport Screen appear.

In this Pygame Tutorial blog, we’ll mainly talk about the following topics:

  • Geometric Designs
  • Fonts and Text
  • Input Modules
  • Scene Logic

Before diving into the basics of pygame, let’s understand how we can install it into our system. We, generally, prefer PyCharm; however, you can continue with any IDE you are comfortable with.

Geometric Designs

Here, we will discuss the different designs we can create using pygame. It’s pretty simple with just a few lines of code.

  • Drawing Rectangle

The syntax for creating the Rectangle:

Pygame.draw.rect(surface, color, pygame.Rect(left, top, width, height)

Let’s start with creating a Rectangle. The command we use:

#importing libraries
import pygame

# initializing the pygame
pygame.init()

# drawing the surface
surface= pygame.display.set_mode((400,300))

#initializing the color
color = (255,0,0)

# drawing the rectangle
pygame.draw.rect(surface, color,pygame.Rect(100,150,200,150))
pygame.display.flip()
  • Drawing the circle

  The syntax to create a circle:

pygame.draw.circle(surface, color, (150,150), 30)
pygame.display.flip()

Here, after drawing the rectangle and circle in the pygame, there is a small thing on which we need to focus on. It is the thickness of the boundaries. 

We can also control the thickness by just adding the parameter at the end of the syntax:

pygame.draw.circle(surface, color, (300, 60), 50, 20)
  • Drawing the Polygon

Drawing a polygon is straightforward. It is just the coordinates X and Y of the polygon.

Syntax for polygon:

pygame.draw.polygon(surface, color, point_list)

points = [(200, 200), (150, 120), (250, 120), (280, 140), (210, 150)]
pygame.draw.polygon(surface, (0,255,0), points)
pygame.display.flip()
  • Drawing a line

Drawing lines just takes only a few parameters, start point, endpoint and thickness of the line.

The syntax for drawing a line:

pygame.draw.line(surface, (255,0,0), (100, 100), (300, 200), 5)

This will create a line with starting position (100,100), end position (300,200) and thickness of 5.

Fonts and Texts

Rule #1: Never assume that a user’s machine already has a particular font installed. There is a way to define a font hierarchy with CSS as well. If the font of our choice is not available, we can use the alternate one. You should follow the same pattern. Luckily, PyGame has a smart way to enumerate all the fonts available on the system:

all_fonts = pygame.font.receive_fonts()

There’s also a way to have the default system font appear:

font = pygame.font.Font(None, size)
font = pygame.font.Font(None, 50)

Instead of None, you can pass in the name of a font file you include along with your code to guarantee the existence of the font:

pygame.font.Font("myresources/fonts/Papyrus.ttf", 26)

Using a combination of the above, you can easily write a better font creation function. 

For example, we will write a function that takes a list of font names, size and will create a font instance for the first available font in the list. If none of the fonts is available, it’ll use the default system font.

def make_font(fonts, size):
    available = pygame.font.receive_fonts()
    # get fonts() provides a list of lowercase font names with no spaces.
    options = map(lambda x:x.lower().replace(' ', ''), fonts)
    for option in options:
        if options in options:
            return pygame.font.SysFont(choice, size)
    return pygame.font.Font(None, size)

You can also improve it by caching the font instance by font name and size.

cached_font= {}
def receive_font(font_preferences, size):
    global _cached_fonts
    key = str(font_preferences) + '|' + str(size)
    font = _cached_fonts.get(key, None)
    if font == None:
        font = make_font(font_preferences, size)
        _cached_fonts[key] = font
    return font

You can take it a step further and cache the rendered text itself. Storing an image is always cheaper than creating a new one. 

def create_texts(text, fonts, size, color):
    global _cached_text
    key = '|'.join(map(str, (fonts, size, color, text)))
    image = _cached_text.get(key, None)
    if image == None:
        font = receive_font(fonts, size)
        image = font.render(text, True, color)
        _cached_text[key] = image
    return image

Now, putting everything together, here is the “Hello, World” code but with improvised code.

import pygame 	
def make_font(fonts, size):
    available = pygame.font.receive_fonts()
    # receive_fonts()return fontnames
    choices = map(lambda x: x.lower().replace(' ', ''), fonts)
    for choice in choices:
        if choice in available:
            return pygame.font.SysFont(choice, size)
    return pygame.font.Font(None, size)


cached_font= {}


def receive_font(font_preferences, size):
    global _cached_fonts
    key = str(font_preferences) + '|' + str(size)
    font = _cached_fonts.get(key, None)
    if font == None:
        font = make_font(font_preferences, size)
        _cached_fonts[key] = font
    return font


_cached_text = {}


def create_texts(text, fonts, size, color):
    global _cached_text
    key = '|'.join(map(str, (fonts, size, color, text)))
    image = _cached_text.get(key, None)
    if image == None:
        font = receive_font(fonts, size)
        image = font.render(text, True, color)
        _cached_text[key] = image
    return image


pygame.init()
Surface = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
done = False

font_preferences = [
                   & quot;
Bizarre - Ass
Font
Sans
Serif & quot;,
& quot;
They
definitely
dont
have
this
installed
Gothic & quot;,
& quot;
Papyrus & quot;,
& quot;
Comic
Sans
MS & quot;]

text = create_texts( & quot;
Hello, World & quot;, font_preferences, 72, (0, 128, 0))

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            done = True

    Surface.fill((255, 255, 255))
    Surface.blit(text,
                (320 - text.get_width() // 2, 240 - text.get_height() // 2))

    pygame.display.flip()
    clock.tick(60)

Input Models

There are two techniques to determine the state of any input device: Polling or event queueing. Every time we press any key or button or release it, or the mouse is moved, an event is automatically added to the event queue. We must ensure to empty this event queue each frame by either calling pygame.event.get() or pygame.event.pump().

pygame.event.get()-  This will return the list of all the events. How we handle those events depends on the event type a well. We can check the event type by the event.type field

The other way to check events is to poll for the state of key or buttons.

pygame.key.get_pressed() —  This will provide a list of Booleans (True/False) that describes the state of each keyboard key. 

ame.mouse.get_pos() — Returns the coordinates (x,y) of the mouse cursor. Will return (0, 0) if there is no change in the mouse cursor position.

pygame.mouse.get_pressed(): This returns the status of each mouse button, similar to the pygame.key.get pressed(). A tuple of size 3 is returned, corresponding to the left, middle, and right buttons. Below a little program that has a bit of everything:

  • Sliding the mouse causes a trail after it.
  • Ctrl + W will close the window. Same for Alt + F4.
  • The close (x) button will close the window.
  • R, G, B keys will make the trail red, green, and blue, respectively.

 • Using the left mouse button will thicken the trail.

 • Use the right mouse button to make the trail thinner.

import pygame


def main():
    pygame.init()
    Surface = pygame.display.set_mode((640, 480))
    clock = pygame.time.Clock()

    radius = 15
    x = 0
    y = 0
    mode = 'blue'
    points = []

    while True:

        pressed = pygame.key.get_pressed()

        alt_held = pressed[pygame.K_LALT] or pressed[pygame.K_RALT]
        ctrl_held = pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]

        for event in pygame.event.get():

            # determin if X was clicked, or Ctrl+W or Alt+F4 was used
            if event.type == pygame.QUIT:
                return
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w and ctrl_held:
                    return
                if event.key == pygame.K_F4 and alt_held:
                    return
                if event.key == pygame.K_ESCAPE:
                    return

                # determine if a letter key was pressed 
                if event.key == pygame.K_r:
                    mode = 'red'
                elif event.key == pygame.K_g:
                    mode = 'green'
                elif event.key == pygame.K_b:
                    mode = 'blue'

            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:  # left click grows radius 
                    radius = min(200, radius + 1)
                elif event.button == 3:  # right click shrinks radius
                    radius = max(1, radius - 1)

            if event.type == pygame.MOUSEMOTION:
                # if mouse moved, add point to list 
                position = event.pos
                points = points + [position]
                points = points[-256:]

        Surface.fill((0, 0, 0))

        # draw all points 
        i = 0
        while i & lt; len(points) - 1:
            makealinebetween(Surface, i, points[i], points[i + 1], radius, mode)
            i += 1

        pygame.display.flip()

        clock.tick(60)


def makealinebetween(Surface, index, start, end, width, mode_color):
    c1 = max(0, min(255, 2 * index - 256))
    c2 = max(0, min(255, 2 * index))

    if mode_color == 'blue':
        color = (c1, c1, c2)
    elif mode_color == 'red':
        color = (c2, c1, c1)
    elif mode_color == 'green':
        color = (c1, c2, c1)

    dx = start[0] - end[0]
    dy = start[1] - end[1]
    iteration = max(abs(dx), abs(dy))

    for i in range(iteration):
        progress = 1.0 * i / iteration
        aprogress = 1 - progress
        x = int(aprogress * start[0] + progress * end[0])
        y = int(aprogress * start[1] + progress * end[1])
        pygame.draw.circle(Surface, color, (x, y), width)


main()

Scene Logic

If you are not aware of the OOP concept ( object-Oriented Programming ) in python, you should be definitely aware of that.

Here is a class for BaseScene:

class BaseScene:
    def __init__(self):

        self.next = self


def ProcessInput(self, events):
    print( & quot;
    uh - oh, you
    didn
    't override this in the child class")


def Update(self):
    print( & quot;
    uh - oh, you
    didn
    't override this in the child class")


def Render(self, Surface):
    print( & quot;
    uh - oh, you
    didn
    't override this in the child class")


def SwitchToScene(self, next_scene):
    self.next = next_scene

When you override this class, you’ve got three method implementations to fill in.

  • ProcessInput — this will receive all the events that happened since the last frame.
  • Update — your game logic goes here for the scene. 
  • Render — your render code goes here. It will receive the most Surface Surface as input.

Yes, this class needs the appropriate harness to work. Let’s try an example that does a simple task: It executes the pygame pipeline with a scene with blank red background. When we hit enter, it changes its color to blue.

The code may seem plenty, but at the same time, it does lots of other subtle things while keeping the complexity of your game logic contained into a snazzy OO model.

Once you continue to add more complexity to your game, this model will save you lots of time from debugging and changing code.

def main():
    pygame.init()
    Surface = pygame.display.set_mode((640, 480))
    watch = pygame.time.Clock()

    radius = 15
    x = 0
    y = 0
    mode = 'blue'
    points = []

    while True:

        pressed = pygame.key.get_pressed()

        alt_held = pressed[pygame.K_LALT] or pressed[pygame.K_RALT]

        ctrl_held = pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]

        for event in pygame.event.get():

            # Checks if the X button was pressed, or if Ctrl + W or Alt+F4 was pressed.
            if event.type == pygame.QUIT:
                return
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w and ctrl_held:
                    return
                if event.key == pygame.K_F4 and alt_held:
                    return
                if event.key == pygame.K_ESCAPE:
                    return

                # to see if a letter key has been pushed
                if event.key == pygame.K_r:
                    mode = 'red'
                elif event.key == pygame.K_g:
                    mode = 'green'
                elif event.key == pygame.K_b:
                    mode = 'blue'

            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:  # The radius is increased by clicking the left mouse button.
                    radius = min(200, radius + 1)
                elif event.button == 3:  # Right-clicking reduces the radius.
                    radius = max(1, radius - 1)

            if event.type == pygame.MOUSEMOTION:
                # if the mouse moves, add a new point to the list
                position = event.pos
                points = points + [position]
                points = points[-256:]

        Surface.fill((0, 0, 0))

        # make a diagram of all the points
        i = 0
        while i & lt; len(points) - 1:
            makealinebetween(Surface, i, points[i], points[i + 1], radius, mode)
            i += 1

        pygame.display.flip()

        clock.tick(60)


def 	(Surface, index, start, end, width, mode_color):
    c1 = max(0, min(255, 2 * index - 256))
    c2 = max(0, min(255, 2 * index))

    if mode_color == 'blue':
        color = (c1, c1, c2)
    elif mode_color == 'red':
        color = (c2, c1, c1)
    elif mode_color == 'green':
        color = (c1, c2, c1)

    dx = start[0] - end[0]
    dy = start[1] - end[1]
    iteration = max(abs(dx), abs(dy))

    for i in range(iteration):
        progress = 1.0 * i / iteration
        aprogress = 1 - progress
        X = int(aprogress * start[0] + progress * end[0])
        Y = int(aprogress * start[1] + progress * end[1])
        pygame.draw.circle(Surface, color, (X, Y), width)


main()

We hope this basic PyGame Tutorial helps you to understand the basics of the Pygame. We hope that you have understood the concept comprehensively. To learn more such concepts, join Great Learning’s PGP Artificial Intelligence and Machine Learning Course and upskill today.

The PGP- AIML Course also offers Online Mentorship and Career Support to help you power ahead of your career.

→ Explore this Curated Program for You ←

Avatar photo
Great Learning Editorial Team
The Great Learning Editorial Staff includes a dynamic team of subject matter experts, instructors, and education professionals who combine their deep industry knowledge with innovative teaching methods. Their mission is to provide learners with the skills and insights needed to excel in their careers, whether through upskilling, reskilling, or transitioning into new fields.

Full Stack Software Development Course from UT Austin

Learn full-stack development and build modern web applications through hands-on projects. Earn a certificate from UT Austin to enhance your career in tech.

4.8 ★ Ratings

Course Duration : 28 Weeks

Cloud Computing PG Program by Great Lakes

Enroll in India's top-rated Cloud Program for comprehensive learning. Earn a prestigious certificate and become proficient in 120+ cloud services. Access live mentorship and dedicated career support.

4.62 ★ (2,760 Ratings)

Course Duration : 8 months

Scroll to Top