pygamespritelagpygame-surfaceblit

In Pygame, can you draw many sprites to the screen each loop without significant delay?


In my map editing program, I have 3 key features.

  1. Adding sprites
  2. Removing sprites
  3. Currently selected sprite follows the mouse

Issue I'm having is that I use a loop that iterates through all of the "added sprites" and draws them to the screen. The delay gets significant and drawing becomes harder the more sprites on the screen due to the MS delay from this loop

    while item_list_item_amount > item_list_iterator:
        display.blit(pygame.image.load("imgs\\tiles\\" + sprite_list[item_list_iterator]), (x_list[item_list_iterator] * 16, y_list[item_list_iterator] * 16))
        item_list_iterator += 1

Each "Mainloop" cycle draws the background over these sprites, to make removing / replacing sprites possible. This makes re-drawing the sprites every loop necessary currently.

Loop looks like this:

while main_loop == True:
    #Main starts loop here
    #Update the currently selected tile
    display.fill(BGC)
    display_listed_tiles()
    
    #Uses mouse coordinates to blit tile over current mouse location
    display.blit(tile, (row * 16, col * 16))
    
    screen.blit(pygame.transform.scale(display, WINDOW_SIZE), (0, 0))

    #Updates screen
    pygame.display.update()

I've tried making a comparison list and only drawing the background once, but the lag remains on removing sprites and I couldn't get the mouse function to work.

Any thoughts on if this situation is resolvable? Any way to compress the "sprite list" that needs to be drawn to one object rather than having to iterate the entire list of hundreds? Any help is appreciated!


Solution

  • The major issue is that you load the images in every frame. pygame.image.load is a very expensive operation, because it has to read the images from the data store.
    Load the images once at initialization and use them when drawing:

    surface_list = [pygame.image.load("imgs\\tiles\\" + name) for name in sprite_list]
    
    for item_list_iterator in range(item_list_item_amount):
        display.blit(surface_list[item_list_iterator], (x_list[item_list_iterator] * 16, y_list[item_list_iterator] * 16))