1

When i try to blit images for a parallax background in my game i run into FPS issues.

I tried .convert(), .convert_alpha(), i made sure that the images are loaded and transformed just once - not in the loop. The only thing looping is movement processing and blitting the image.

About the images:

  • format = .png
  • resolution = 1940x1080x
  • more than 50% transparent pixels
  • 100 KB - 450 KB each.

I want to run the game with 120 FPS, however blitting just 4 of these images result in a drop to 80 FPS. I heard of dirtyRect updating, but since my images are screen-sized i have to update the whole screen anyway. Thanks for your help!

# IMPORT --------------------------------------------------------------------------------------------------------------#
import pygame
import random
from math import cos, sin, radians
# SETUP ---------------------------------------------------------------------------------------------------------------#
WIDTH, HEIGHT = 1940, 1080
SIZE = (WIDTH, HEIGHT)
scCenterX, scCenterY = WIDTH//2, HEIGHT//2
SC = pygame.display.set_mode(SIZE)
pygame.display.set_caption("Space and Void")
FPS = 120
CLOCK = pygame.time.Clock()
pygame.mixer.init()
pygame.init()


img_clouds_path = [f"assets/clouds/{i}.png" for i in range(0, 7)]
img_clouds = [pygame.image.load(i).convert_alpha() for i in img_clouds_path]


class PARALAX:
    def __init__(self, i, j, x, y):
        self.img1 = img_clouds[i]
        self.img2 = img_clouds[j]

    self.x1 = x
    self.y1 = y
    self.x2 = self.x1 + WIDTH/2
    self.y2 = self.y1 + HEIGHT/2

def blit(self):

    self.x1 -= scrollingBG.xScroll / 2
    self.y1 += scrollingBG.yScroll / 2

    self.x2 -= scrollingBG.xScroll / 4
    self.y2 += scrollingBG.yScroll / 4

    SC.blit(self.img1, (self.x1, self.y1))
    SC.blit(self.img2, (self.x2, self.y2))


backgroundStart = PARALAX(5, 2, 0, 0)
backgroundStart2 = PARALAX(3, 5, 0-WIDTH, 0)


def main():  # MAIN --- MAIN --- MAIN --- MAIN --- MAIN --- MAIN --- MAIN --- MAIN --- MAIN --- MAIN --- MAIN --- MAIN #
    run = True
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:  # QUITTING -----------------------------------------------------------------#
                run = False

        #  MAIN GAME LOOP ---------------------------------------------------------------------------------------------#
        SC.fill(BLACK)

        backgroundStart.blit()
        backgroundStart2.blit()



        #  UPDATE -----------------------------------------------------------------------------------------------------#
        scrollingBG.update()
        pygame.display.update()
        CLOCK.tick(FPS)

########################################################################################################################
# EXECUTION -----------------------------------------------------------------------------------------------------------#
main()
pygame.quit()
exit()
vuvuwe
  • 11
  • 1
  • Short answer: don't blit them. Modern computer use an accelerated GPU-based rendering step since decade and it is very fast. Doing it on the CPU using Python is not efficient. A good rendering Python library should just provide the information to the GPU which does all the expensive work. GPUs have hardware units specifically design to do rasterisation and it is very very fast nowadays. What is slow now is the GPU drawcalls (drawing requests) but there are some framework/library to reduce their cost. Blitting just ignore >20 years of computer improvements. – Jérôme Richard Jul 21 '22 at 17:18
  • I don't know about the recent versions of PyGame, but a few years ago the libraries still used SDL 1.0, which doesn't use shaders (GPU) to render the images on the window. You must check it out if that's the real problem here. If it is, it doesn't matter how much you try to optimize your script, the script will only execute slower, especially if the image is too large and transparent. – Carl HR Jul 21 '22 at 17:21
  • The performance of blit scales with the pixel count. A 1940x1080 image contains a little over 2 million pixels. Since you've already converting alpha (good), I think the only way to increase performance is to decrease the number of pixels you need to blit. Can the images be cropped or if they are particularly sparse, can clouds be blitted separately? Are images being continuously blit on top of each other, can that be cached? I'm legitimately asking these things, I don't have the images, and the code doesn't look to be in a runnable state as you've pasted it here. – Starbuck5 Jul 22 '22 at 07:28
  • Also, despite 80 fps seeming much closer to 60 fps than to 120 fps, it is actually in the middle. At 120 fps, there are only 8.3 milliseconds per frame. At 80 fps, that number rises to 12.5 milliseconds per frame, and at 60 it is 16.7 milliseconds per frame. (Not that that is particularly helpful, I just frequently see people thinking of FPS linearly, when the amount of work doesn't scale that way) – Starbuck5 Jul 22 '22 at 07:32
  • Thanks a lot so far, it's been very informative. @ Starbuck5, you're right the pasted code actually isn't runnable and the reason for that is, that the whole thing has around 1000 lines of code, so i tried to cherry pick just the functions related to the issue - i shall work on that and make more precise code examples in the future. Yes i cropped the images a bit and it helped. The images are blitted on top of each other, but i'll have to read into how caching actually works. – vuvuwe Jul 23 '22 at 11:23

0 Answers0