Any way to speed up Python and Pygame?

2019-02-04 18:59发布

问题:

I am writing a simple top down rpg in Pygame, and I have found that it is quite slow.... Although I am not expecting python or pygame to match the FPS of games made with compiled languages like C/C++ or event Byte Compiled ones like Java, But still the current FPS of pygame is like 15. I tried rendering 16-color Bitmaps instead of PNGs or 24 Bitmaps, which slightly boosted the speed, then in desperation , I switched everything to black and white monochrome bitmaps and that made the FPS go to 35. But not more. Now according to most Game Development books I have read, for a user to be completely satisfied with game graphics, the FPS of a 2d game should at least be 40, so is there ANY way of boosting the speed of pygame?

回答1:

Use Psyco, for python2:

import psyco
psyco.full()

Also, enable doublebuffering. For example:

from pygame.locals import *
flags = FULLSCREEN | DOUBLEBUF
screen = pygame.display.set_mode(resolution, flags, bpp)

You could also turn off alpha if you don't need it:

screen.set_alpha(None)

Instead of flipping the entire screen every time, keep track of the changed areas and only update those. For example, something roughly like this (main loop):

events = pygame.events.get()
for event in events:
    # deal with events
pygame.event.pump()
my_sprites.do_stuff_every_loop()
rects = my_sprites.draw()
activerects = rects + oldrects
activerects = filter(bool, activerects)
pygame.display.update(activerects)
oldrects = rects[:]
for rect in rects:
    screen.blit(bgimg, rect, rect)

Most (all?) drawing functions return a rect.

You can also set only some allowed events, for more speedy event handling:

pygame.event.set_allowed([QUIT, KEYDOWN, KEYUP])

Also, I would not bother with creating a buffer manually and would not use the HWACCEL flag, as I've experienced problems with it on some setups.

Using this, I've achieved reasonably good FPS and smoothness for a small 2d-platformer.



回答2:

When loading images, if you absolutely require transparency or other alpha values, use the Surface.convert_alpha() method. I have been using it for a game I've been programming, and it has been a huge increase in performance. E.G: In your constructor, load your images using:

self.srcimage = pygame.image.load(imagepath).convert_alpha() 

As far as I can tell, any transformations you do to the image retains the performance this method calls. E.G:

self.rotatedimage = pygame.transform.rotate(self.srcimage, angle).convert_alpha()

becomes redundant if you are using an image that has had convert_alpha() ran on it.



回答3:

All of these are great suggestions and work well, but you should also keep in mind two things:

1) Blitting surfaces onto surfaces is faster than drawing directly. So pre-drawing fixed images onto surfaces (outside the main game loop), then blitting the surface to the main screen will be more efficient. For exmample:

# pre-draw image outside of main game loop
image_rect = get_image("filename").get_rect()
image_surface = pygame.Surface((image_rect.width, image_rect.height))
image_surface.blit(get_image("filename"), image_rect)
......
# inside main game loop - blit surface to surface (the main screen)
screen.blit(image_surface, image_rect)

2) Make sure you aren't wasting resources by drawing stuff the user can't see. for example:

if point.x >= 0 and point.x <= SCREEN_WIDTH and point.y >= 0 and point.y <= SCREEN_HEIGHT:
    # then draw your item

These are some general concepts that help me keep FPS high.



回答4:

First, always use 'convert()' because it disables alpha which makes bliting faster. Then only update the parts of the screen that need to be updated.

global rects

rects = []

rects.append(pygame.draw.line(screen, (0, 0, 0), (20, 20), (100, 400), 1)) 

pygame.display.update(rects) # pygame will only update those rects

Note:

When moving a sprite you have to include in the list the rect from their last position.



回答5:

When using images it is important to convert them with the convert()-function of the image. I have read that convert() disables alpha which is normally quite slow. I also had speed problems until I used a colour depth of 16 bit and the convert function for my images. Now my FPS are around 150 even if I blit a big image to the screen.

image = image.convert()#video system has to be initialed

Also rotations and scaling takes a lot of time to calculate. A big, transformed image can be saved in another image if it is immutable.

So the idea is to calculate once and reuse the outcome multiple times.



回答6:

You could try using Psyco (http://psyco.sourceforge.net/introduction.html). It often makes quite a bit of difference.