Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Python (pygame) Slow Blit?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
8 replies to this topic

#1 TreeSaaaaap   Members   -  Reputation: 139

Like
1Likes
Like

Posted 24 February 2014 - 05:38 PM

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()



Sponsor:

#2 dejaime   Crossbones+   -  Reputation: 4119

Like
1Likes
Like

Posted 24 February 2014 - 06:01 PM

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.

Edited by dejaime, 24 February 2014 - 06:04 PM.


#3 TreeSaaaaap   Members   -  Reputation: 139

Like
1Likes
Like

Posted 24 February 2014 - 06:11 PM

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



#4 dejaime   Crossbones+   -  Reputation: 4119

Like
1Likes
Like

Posted 24 February 2014 - 06:16 PM

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.

#5 TreeSaaaaap   Members   -  Reputation: 139

Like
0Likes
Like

Posted 24 February 2014 - 06:32 PM

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...



#6 dejaime   Crossbones+   -  Reputation: 4119

Like
1Likes
Like

Posted 24 February 2014 - 06:45 PM


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!



#7 TreeSaaaaap   Members   -  Reputation: 139

Like
0Likes
Like

Posted 24 February 2014 - 07:04 PM

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

#8 ferrous   Members   -  Reputation: 2146

Like
0Likes
Like

Posted 24 February 2014 - 07:18 PM

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()
       }



#9 dejaime   Crossbones+   -  Reputation: 4119

Like
0Likes
Like

Posted 24 February 2014 - 07:21 PM

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.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS