Python (pygame) Slow Blit?

Started by
7 comments, last by DejaimeNeto 10 years, 1 month ago

Hello Everyone,

This is my first post here, but I plan on spending a lot of time here trying to learn (and help others).

I've dabbled in c++ off and on for the last few years, but I found myself struggling to find a project that wasn't too challenging (or too easy) and I stepped away for a bit.

Recently, I started teaching myself a bit about Python. Apparently, it's a simpler language (that can do a lot) and I figure I'll give it a shot, maybe I can accomplish something. So I set out the other day and now I'm here...

I've attempted to render a background image (or terrain) with another image on top that can move to the location of a mouse click. I'm having trouble understanding why the image won't move precisely when I click, every time. For instance, if I click in quick succession, the image may only change locations once every second or more.

I have a feeling like it has something to do with constantly having to redraw the images, perhaps slowing it down? If that's the case, I wouldn't understand why because I thought that the game loop would iterate many times a second.... Or maybe my loop isn't working right? Can I just "move" an image instead of the constant "blit-ing"? If not, then this kind of concerns me with what I plan on doing in the future. (When I click a point on the terrain, I want to move, or walk, the image to that point).

Obviously, this is a very simple task, especially for some of you, but I can't really tell if it's a problem with the way I'm coding it or if it's really how slow python/pygame is?

Here is the code:



import sys, pygame

pygame.init()

SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800
BLACK = (0, 0, 0)

screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption("TTB")
screen.fill(BLACK)

#set cursor here somewhere

terrain = pygame.image.load("terrain.jpg")
terrainRect = terrain.get_rect()
terrain = pygame.transform.scale(terrain, (SCREEN_WIDTH, SCREEN_HEIGHT))
screen.blit(terrain, terrainRect)

oPC = pygame.image.load("amishdude.png")
oPC = pygame.transform.scale(oPC, (75, 75))                                     
oPCrect = oPC.get_rect()
screen.blit(oPC, oPCrect)

pygame.display.flip()

running = True #initialize the main game loop

while running == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False #break loop and close 
        

    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
                mouseRect = pygame.mouse.get_pos()              
                screen.fill(BLACK)
                screen.blit(terrain, terrainRect)
                screen.blit(oPC, mouseRect)
                pygame.display.update()
                
                
  

pygame.quit()
#sys.exit()

Advertisement
I don't understand why you used two separate for loops...
You are probably skipping events, checking them on only one of these loops.

You could try to turn them in one like:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False #break loop and close
        elif event.type == pygame.MOUSEBUTTONDOWN: #is it elif?
                mouseRect = pygame.mouse.get_pos()              
                screen.fill(BLACK)
                screen.blit(terrain, terrainRect)
                screen.blit(oPC, mouseRect)
                pygame.display.update()
That will make sure you always check all events against the two possibilities, mouse or quit.
I am assuming that the event.get() function actually removes them from the queue.

Wow. That was exactly it. I'm not even sure what I was thinking now... Thank you for pointing that out though. Apologies.

No need to apologize! btdt
The good news is that the blit wasn't slow, the game just wasn't detecting the mouse clicks correctly.

That is good news! For clarity purposes though, do we constantly have to blit images (including the terrain) every time something changes? If that's the case, won't it eventually slow down with thousands of image objects moving (and terrain reloading)? Or...say for instance, we have a multiplayer game where we're having to blit all of these images for everyone....Wouldn't that really slow it down?

I realize I have much to learn if I ever choose to go the multiplayer route, but I suppose I'm asking out of curiousity...


For clarity purposes though, do we constantly have to blit images (including the terrain) every time something changes?
You could render only the part of the screen that changed.

The function pygame.display.update() does just that, but you need to pass a list of the rectangles that changed to it.

Using it without this list is just the same as pygame.display.flip().

In your case, you'd want to pass both, the old and the new rectangles of your Amish dude, to your update function.

Mostly, it won't be worth it, probably too much trouble to keep track of what changed. If you really start to have problems with performance, there'll probably be a culprit somewhere else in your code.


If that's the case, won't it eventually slow down with thousands of image objects moving (and terrain reloading)? Or...say for instance, we have a multiplayer game where we're having to blit all of these images for everyone....Wouldn't that really slow it down?
Certainly, thousands of images are sure to slow your game down. Actually, thousands of anything will slow it down.

There's not much you can do to prevent this. Sure, good architecture and minimal redundancy is the ideal case, but it is hard to get it right on the first shot... make it ten shots.

Don't worry about performance until you see a reason to worry about it; just keep on making them!

Ahh.. I see. Thanks again for the info!

That is good news! For clarity purposes though, do we constantly have to blit images (including the terrain) every time something changes? If that's the case, won't it eventually slow down with thousands of image objects moving (and terrain reloading)? Or...say for instance, we have a multiplayer game where we're having to blit all of these images for everyone....Wouldn't that really slow it down?

I realize I have much to learn if I ever choose to go the multiplayer route, but I suppose I'm asking out of curiousity...

I'm not intimately familiar with pygame, but couldn't you just toggle a flag if you've hit an event that will require a redraw, and then wait til all events have been iterated over, then do one set of blits of everything.

Excuse my pseudocode


       UpdateDisplay=FALSE
       for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False #break loop and close
        elif event.type == pygame.MOUSEBUTTONDOWN: #is it elif?
                UpdateMouseRect
                UpdateDisplay=TRUE
        elisf event.type == pygame.WHATEVER
                UpdateWhatever
                UpdateDisplay=TRUE


       if(UpdateDisplay)  # Note this is OUTSIDE the loop
       {         
                screen.fill(BLACK)
                screen.blit(terrain, terrainRect)
                screen.blit(oPC, mouseRect)
                pygame.display.update()
       }

I'm not intimately familiar with pygame, but couldn't you just toggle a flag if you've hit an event that will require a redraw, and then wait til all events have been iterated over, then do one set of blits of everything.

Actually, his code only redraws when it detects a mouse down event.

This topic is closed to new replies.

Advertisement