0

First off, I have researched this topic on stackoverflow beforehand, but I would like more information about it so I'm asking a new question.

So basically, I've been working in Pygame 1.9.3 and I've succeeded in making a simple 2D game with graphics. I am using the Sprite class, and thus I use Group() methods often. I draw my graphics to the screen using groupName.draw(screen).

A component of my game is the ability to interact with the terrain, such as removing tiles and placing tiles. Each tile is a part of my block Sprite Group that is drawn to the screen.

However, my program begins to visibly lag as the number of block tiles increases. Here's what I have done to try to counteract the problem:

  • Used .convert_alpha() for all of my loaded images
  • Load images only once
  • Change the target FPS (using 60 atm)
  • Change my program such that the blockGroup.draw() command is ONLY called when the environment changes. Basically, if the environment changes, I redraw the blocks, screenshot my window, then blit this image until the environment changes again (this, as expected, causes lag when screenshots are taken)

However, my game continues to lag.

Naturally, if I increase the size of my block sprites (meaning how I resize them when loading their respective images), I can end up placing more blocks without lag occurring until later, since there are less sprites total, but this is not ideal for what I want to accomplish.

Furthermore, I have implemented 2 teams of NPCs who interact with this terrain. Thus, it is understandable that my program needs to check a lot of collisions in my main game loop, but nonetheless, I wasn't expecting my program to lag unless I added in a team of ~30 NPCs (I am currently working with only 10 NPCs, 5 on each team).

When my program begins to lag, I calculated the number of sprites total (adding up all the sprites in each group) to be 170.

So, finally, my question: if I plan to have a program that uses multiple sprites (multiple being ~170) at the same time, is pygame simply not cut out for the job in terms of speed?

I believe I have used good implementation practices, such as deleting sprites from their respective groups after they are removed and the brief list above.

I have had a request to provide some code, so here are some important parts that I have included.

The Main Game Loop:

# Main Game Loop
while gameRunning:
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        gameRunning = False

    keys = pygame.key.get_pressed()
    if keys[LEFT_KEY]:
        player1.goLeft()

    if keys[RIGHT_KEY]:
        player1.goRight()

    if keys[JUMP_KEY]:
        player1.jump()

    if keys[DOWN_KEY]:
        player1.ducking = True

    if keys[SPRINT_KEY] and player1.movementKeyPressed:
        player1.startSprinting()

    if keys[SHOW_SCORES_KEY]:
        Screen.DISPLAY_SCORES = True

    # KEYUP EVENT
    elif event.type == pygame.KEYUP:
        if event.key == LEFT_KEY or event.key == RIGHT_KEY or event.key == SPRINT_KEY:
            player1.stopMovingX()
            player1.isSprinting = False

        if event.key == DOWN_KEY:
            player1.ducking = False

        if event.key == SHOW_SCORES_KEY:
            Screen.DISPLAY_SCORES = False

    # MOUSE
    if event.type == pygame.MOUSEBUTTONDOWN:
        # Left Click
        if event.button == ATTACK_KEY:
            player1.attack()

        # Right Click
        elif event.button == PLACE_BLOCK_KEY:
            player1.requestToPlaceBlock()

# Clear the screen
Screen.gameScreen.fill(Colors.WHITE)

# Update Sprites
EntityLists.npcGroup.update()
EntityLists.redTeamGroup.update()
EntityLists.blackTeamGroup.update()
EntityLists.corpseGroup.update()

# Update Blocks
EntityLists.blockGroup.update()

#
print(len(EntityLists.blockGroup) + len(EntityLists.redTeamGroup) + len(EntityLists.blackTeamGroup) +
      len(EntityLists.npcGroup) + len(EntityLists.wallGroup))

if Screen.takeScreenShot:
    # Blit background first
    Screen.gameScreen.blit(background, (0, 0))
    # Draw blocks and wall next
    EntityLists.wallGroup.draw(Screen.gameScreen)
    EntityLists.blockGroup.draw(Screen.gameScreen)

    # Next, take screenshot
    pygame.image.save(Screen.gameScreen, "BACKGROUND_AND_BLOCKS.png")
    backgroundAndBlocks = pygame.image.load('BACKGROUND_AND_BLOCKS.png')
    # Reset variable
    Screen.takeScreenShot = False

# Blit
Screen.gameScreen.blit(backgroundAndBlocks, (0, 0))

# Draw Entities
EntityLists.npcGroup.draw(Screen.gameScreen)
EntityLists.redTeamGroup.draw(Screen.gameScreen)
EntityLists.corpseGroup.draw(Screen.gameScreen)
EntityLists.blackTeamGroup.draw(Screen.gameScreen)

# Player names
Screen.drawNames()

# Draw Death Messages
Screen.displayDeathMessages()

# Draw scores if viable
if Screen.DISPLAY_SCORES:
    Screen.displayScores()

# Update screen
pygame.display.flip()

# FPS
clock.tick(Screen.TARGET_FPS)

pygame.quit()

Thank you so much for your time.

11
  • show us the code, preferably a MCVE Commented Apr 27, 2018 at 19:19
  • @depperm will do my best, one minute Commented Apr 27, 2018 at 19:21
  • Do you make use of dirty sprites? And did you time the different aspects of the code (with, for example the time library, or just profile) to find out where the delays actually happen? Commented Apr 27, 2018 at 19:29
  • @Martijn I had never heard about dirty sprites until now. So no, I do not use dirty sprites. As for time, no, but I do use the clock.tick() for my FPS. I will attempt to implement dirty sprites and see if that makes a difference. Commented Apr 27, 2018 at 19:33
  • @Martijn So do I understand this correctly concerning dirty sprites? I do the following: get the return value of the draw function, then call pygame.display.update() passing in the return val as a parameter Commented Apr 27, 2018 at 19:40

1 Answer 1

0

Im working on pygame, and the lag is noticeable when you don't use spritesheets....try and use spritesheets, that way you only upload a single image containing all your sprites ONCE.

Whay happens if your main character has 20 different images (frames) that include, idle, running, walking, jump, shoot etc and you dont use a spritesheet?

Pygame NEEDS to upload in every loop all those images one by one, creating lag.

Instead, a spritesheet is a single image, containing ALL sprites with an (x,y,width,height) each sprite, so pygame knows the boundaries of each sprite when that specific sprite frame is needed.

Try and use spritesheets, it will make you game run smooth, less processing power and less graphics card usage etc, less heat etc.

100 images, each one weighing 100kb...thats a lot, but a single spritesheet image only weighing 100kb....hmmm

If your game has only 5 sprites, use images if no lag is present, but if your game has more than that and presents lag, use spritesheets, also it helps keep your work more organized, and when you want to pack it up, convert it to .exe or whatever, it will weigh less.

note: I posted my answera while ago, but I just wanted to add that when you load your images, try to load them ONCE, inside the init method and in the update method just reference them. Do not "pygame.image.load(filename)" inside a loop, it will lag.

Good luck.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.