The Practical Guide to Game Development with Pygame---2. Understanding the Surface Object

code_egg

code_egg

Posted on August 12, 2024

The Practical Guide to Game Development with Pygame---2. Understanding the Surface Object

In the previous article, we used the pygame.display.set_mode() function to get a window object and the pygame.image.load() function to load an image, resulting in an image object. Both the window object and the image object are actually of the Surface type, and we collectively refer to them as Surface objects. The concept of Surface is crucial in Pygame, and this article will provide a detailed introduction.

Project code download link: https://github.com/la-vie-est-belle/pygame_codes


What is a Surface?

We can think of a Surface object in Pygame as a canvas. We can fill the canvas with colors or draw any images, text, and lines on it. Let’s briefly look at how to add images to various Surface objects. See Example Code 2-1.

import sys
import pygame

pygame.init()
surface1 = pygame.display.set_mode((800, 600))              # 1
pygame.display.set_caption('Surface Demo')

surface2 = pygame.image.load('pygame_logo.png')             # 2
surface2_rect = surface2.get_rect()
surface2_rect.center = (400, 300)

surface3 = pygame.image.load('python_logo.png')             # 3
surface3_rect = surface3.get_rect()
surface3_rect.topleft = (0, 0)

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

    surface1.fill((0, 255, 0), (0, 0, 400, 600))            # 4
    surface1.blit(surface2, surface2_rect)                  # 5

    surface2.blit(surface3, surface3_rect)                  # 6

    pygame.display.flip()
Enter fullscreen mode Exit fullscreen mode

The result is as follows:
Code 2-1 result

Code Explanation:

#1 Call the pygame.display.set_mode() function to get a Surface object that represents the screen.

#2 Call the pygame.image.load() function to load the Pygame logo, resulting in a Surface object the same size as the loaded image. The Rect object's center attribute is used to set the position of the Surface object. center specifies the center of the Surface, so this actually centers the Pygame logo on the screen.

#3 Similarly, load the Python logo image to get a Surface object the same size as this image. The top-left corner of its coordinates is set to (0, 0). Since the Python logo is to be added on top of the Pygame logo, (0, 0) positions the top-left corner of the Python logo at the origin of the Pygame logo's coordinate system.

Note: The coordinate system in Pygame will be explained in the next section.

#4 Use the fill() function of the Surface object to fill the left half of the window with green. This function can take a rectangular region to specify where to fill.

#5 Use the blit() function of the Surface object to draw another Surface object. Here, the Pygame logo Surface object is added to the window Surface object.

#6 Add the Python logo Surface object onto the Pygame logo Surface object.

Note: The Surface objects that are added later will obscure those added earlier.


How to Create a Surface

In Example Code 2-1, we obtained Surface objects using the pygame.display.set_mode() and pygame.image.load() functions. Additionally, we can create a Surface object directly using pygame.Surface() by specifying its width and height.

surface = pygame.Surface((1000, 800)) # Create a Surface object with a width of 1000 and height of 800
Enter fullscreen mode Exit fullscreen mode

In Pygame, when we create text, we are essentially creating a Surface object where the text is rendered.

font = pygame.font.SysFont('Arial', 50)                 # Set the font
text = font.render('Hello pygame!', True, (0, 0, 0))    # Render the text; 'text' is a Surface object
Enter fullscreen mode Exit fullscreen mode

Common Surface Functions

Here are some commonly used Surface object functions and properties.
1.

Surface.blit(source, dest, area=None)
Enter fullscreen mode Exit fullscreen mode

The blit() function is used to draw one Surface object onto another. source is the source Surface object to be drawn, and dest is the target Surface object where the source will be drawn. The area parameter specifies the drawing region and defaults to None, meaning it will draw at the top-left corner with the width and height of the source Surface.

2.

Surface.blits(((source, dest, area), ...))
Enter fullscreen mode Exit fullscreen mode

The blits() function takes a sequence of tuples, each containing a source Surface, a destination Surface, and an optional area. This function allows drawing multiple Surface objects at once.

3.

Surface.convert(Surface=None)
Surface.convert_alpha(Surface=None)
Enter fullscreen mode Exit fullscreen mode

When you use pygame.image.load() to load an image and then draw it onto a target Surface using blit(), if the pixel format of the image does not match the pixel format of the target Surface, the blit() function performs an internal format conversion.

Since blit() is called every frame, performing format conversion every time can be performance-intensive. Therefore, you can call convert() to convert the pixel format of the image to match the screen Surface format when loading the image. If no Surface parameter is specified, it defaults to converting to the format of the screen Surface. For example:

surface1 = pygame.image.load('demo.jpg').convert()
surface3 = pygame.image.load('demo.png').convert_alpha()
Enter fullscreen mode Exit fullscreen mode

If the image has transparency, use convert_alpha() to preserve the image's transparency effects.

Note: Pixel format refers to the way pixel data is stored, including color channel arrangement and bit depth, not the file format (.jpg, .png, .gif).

4.

Surface.copy()
Enter fullscreen mode Exit fullscreen mode

Creates a copy of a Surface object. The copied Surface has the same pixel format as the original.

5.

Surface.fill(color, rect=None)
Enter fullscreen mode Exit fullscreen mode

Fills the target Surface object with a color. The rect parameter specifies the region to fill; if not provided, the entire Surface is filled.

6.

Surface.get_size()
Enter fullscreen mode Exit fullscreen mode

Gets the width and height of the Surface object in pixels, returning a tuple (width, height).

7.

Surface.get_width()
Enter fullscreen mode Exit fullscreen mode

Gets the width of the Surface object in pixels.

8.

Surface.get_height()
Enter fullscreen mode Exit fullscreen mode

Gets the height of the Surface object in pixels.

9.

Surface.get_rect()
Enter fullscreen mode Exit fullscreen mode

Gets the rectangle area of the Surface object, returning a Rect object.

In Example Code 2-2, we will demonstrate the use of these functions.

import sys
import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Surface Demo')

pygame_logo = pygame.image.load('pygame_logo.png').convert_alpha()  # 1
pygame_logo_rect = pygame_logo.get_rect()
pygame_logo_rect.center = (400, 300)
print(pygame_logo.get_size())                                       # 2
print(pygame_logo.get_width())
print(pygame_logo.get_height())

python_logo = pygame.image.load('python_logo.png').convert_alpha()
python_logo_rect = python_logo.get_rect()
python_logo_rect.topleft = (0, 0)
print(python_logo.get_size())
print(python_logo.get_width())
print(python_logo.get_height())

python_logo2 = python_logo.copy()                                   # 3
python_logo_rect2 = python_logo.get_rect()
python_logo_rect2.topright = (600, 100)
print(python_logo2.get_size())
print(python_logo2.get_width())
print(python_logo2.get_height())

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

    screen.fill((0, 255, 0), (0, 0, 400, 600))
    screen.blit(pygame_logo, pygame_logo_rect)

    pygame_logo.blits(((python_logo, python_logo_rect), (python_logo2, python_logo_rect2)))     # 4

    pygame.display.flip()
Enter fullscreen mode Exit fullscreen mode

The result is as follows:
Code 2-2 result

Code Explanation:
#1 Call the convert_alpha() function to convert the image's pixel format and retain its transparency.

#2 Use get_size(), get_width(), and get_height() functions to obtain the dimensions of the Surface object.

#3 Use the copy() function to create a copy of a Surface object and set its top-right corner to (600, 100).

#4 Use the blits() function to draw two Python logo images onto the Pygame logo. As observed, part of the Python logo on the right is not displayed because it is outside the rectangle area of the Pygame logo, so it is not rendered.


Summary

In this article, we introduced the Surface, including its concept, creation methods, and common functions, and demonstrated their usage with examples. The Surface is a key concept in Pygame, and understanding it will enhance your familiarity with Pygame.

Buy author a cup of coffee if you enjoyed this tutorial. :)

  • Donate for code_egg

  • enter image description here

  • Donate for code egg

💖 💪 🙅 🚩
code_egg
code_egg

Posted on August 12, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

What was your win this week?
weeklyretro What was your win this week?

November 29, 2024

Where GitOps Meets ClickOps
devops Where GitOps Meets ClickOps

November 29, 2024

How to Use KitOps with MLflow
beginners How to Use KitOps with MLflow

November 29, 2024

Modern C++ for LeetCode 🧑‍💻🚀
leetcode Modern C++ for LeetCode 🧑‍💻🚀

November 29, 2024