Random lag spikes with pygame parallax background

Question:

I’m trying to make a platformer with a parallax background. I managed the code and also made sure to add .convert.
It is running pretty well for the most part, but every now and then there are periodic lag spikes.

# Imports
from vars import *


# Background class
class Background(pygame.sprite.Sprite):
    def __init__(self, image, x):
        super(Background, self).__init__()
        self.surf = pygame.transform.smoothscale(pygame.image.load(image).convert_alpha(), (s_width, s_height))
        self.rect = self.surf.get_rect(center=(x, s_height/2))


# Cave Background
class BgSurface(pygame.sprite.Sprite):
    def __init__(self):
        super(BgSurface, self).__init__()
        self.surf = pygame.Surface((s_width, s_height))
        self.rect = self.surf.get_rect(center=(s_width/2, s_height/2))
        self.surf.fill((144, 156, 156))


# Background stuff
cave_air = BgSurface()
l1 = Background("layer1.png", s_width/2)
l2 = Background("layer2.png", s_width/2)
layer_list = [pygame.sprite.Group(l1), pygame.sprite.Group(l2)]
head_list = [pygame.sprite.Group(l1), pygame.sprite.Group(l2)]
bg_img_list = ["layer1.png", "layer2.png"]


def parallax(s_xdir, s_ydir):
    for i in range(len(layer_list)):
        ind = 0
        for x in layer_list[i]:
            ind += 1
            x.rect.move_ip(s_xdir * vel_list[i], s_ydir * vel_list[2])
            # Adding to left
            if x.rect.left > 0 and ind == len(layer_list[i]) and not x.rect.centerx > s_width:
                new_bg = Background(bg_img_list[i], x.rect.centerx - s_width)
                new_bg.rect.centery = x.rect.centery
                layer_list[i].add(new_bg)
            # Memory optimization
            if x.rect.left > s_width or x.rect.right < 1:
                if x in head_list[i]:
                    x.kill()
                    for a in layer_list[i]:
                        head_list[i] = pygame.sprite.Group(a)
                x.kill()

        # Adding to right side
        for a in head_list[i]:
            if a.rect.right < s_width:
                new_head = Background(bg_img_list[i], a.rect.centerx + s_width)
                new_head.rect.centery = a.rect.centery
                layer_list[i].add(new_head)
                head_list[i] = pygame.sprite.Group(new_head)

        # Experimental deletion of common centers
        for p in layer_list[i]:
            for q in layer_list[i]:
                if p.rect.centerx == q.rect.centerx and p != q:
                    p.kill()

(Stuff like s_width and s_height are defined in the vars module which I import)
I moved the last killing loop out of the function and checked how many sprites are there in the background every second, but it returns that there are no unnecessary sprites being added during the lag spikes.
The spikes don’t even coincide with the moments in which a new surface is added to fill the screen. Do any of you know why this is happening?

Answers:

Do not load the images in the application loop. Loading an image is very time consuming because the image file has to be read and interpreted. Load the images once at the begin of the application:

# Background class
class Background(pygame.sprite.Sprite):
    def __init__(self, image, x):
        super(Background, self).__init__()
        self.surf = pygame.transform.smoothscale(image, (s_width, s_height))
        self.rect = self.surf.get_rect(center=(x, s_height/2))
bg_img_filelist = ["layer1.png", "layer2.png"]
bg_img_list = [pygame.image.load(f).convert_alpha() for f in bg_img_filelist ]
l1 = Background(bg_img_list[0], s_width/2)
l2 = Background(bg_img_list[1], s_width/2)
Answered By: Rabbid76
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.