Pygame (Python) Scale Transform Slow - python

I'm writing a simple program in python which takes in data over the serial port and updates the screen.
Because I want this program to look the same on whatever computer it runs on, and it needs to be fullscreen, I had the idea that I wanted to draw everything in a small 640, 480 window, and then scale it to a fullscreen window every time I update the frame.
This allows me to keep all the offsets the same for text, etc. It also turns out this is really slow.
Here's about what the important part of the code looks like:
window = pygame.display.set_mode((1920, 1080),pygame.FULLSCREEN)
screenPrescaled=pygame.Surface((640,480))
clock=pygame.time.Clock()
while iterations<400:
#Blit all the stuff to the prescaled surface here
screenPostscaled=pygame.transform.scale(screenPrescaled,(1920, 1080))
window.blit(screenPostscaled,(0,0))
pygame.display.flip()
iterations+=1
clock.tick(40)
This runs a WHOLE lot slower than 40fps.
Everything on the screen is either text or lines, there are no images loaded.
I suspect I'm doing something stupid.
I know I can update "dirty rectangles" only, but I wonder if I'm missing something more fundamental.
Thanks in advance!

You can save one blit by using window as destination surface:
pygame.transform.scale(screenPrescaled, (1920, 1080), window)
If it continues being too slow, you should use update rectangles, you can scale them using the same factor as you scale the image 1920/640 and 1080/480.

The simplest thing is instead of using
pygame.display.flip()
is to use
pygame.display.update()
It's not that big of a difference but it worked pretty well for me on my game, especially when it uses a lot of pictures.

You are updating a huge screen by display.flip(). In SDL (and that's behind pygame) that is not a good idea (try removing everything put the flip, and see how fast that runs, it shouldn't by to much faster).
I have no way to measure, but I would guess the reason your code takes a long time is a problem with the .flip().
Since you are only working with data in 640x480, why are you scaling it up to such a huge dimension? Try setting your screen to 640x480, and take a look at how fast it will be then. It should run four or five times faster, I would think.

Related

Replacing a surface instead of blitting to it

I'm having some performance issues in pygame, so I'm trying to optimize the rendering.
Currently, I'm blitting the background image to the display buffer:
self.display.blit(self.bg, (0, 0))
Instead, I'm looking for a way to replace the buffer with a copy of the background surface, and draw over that. This way, I don't have to blit a large image every frame, saving me some time.
Is there any way to do so?
It doesn't matter that much how often you blit something to the screen surface, since the display does only get updated once you call pygame.display.update or pygame.display.flip.
If you're sure that blitting the whole background image to the screen surface is a bottle neck in your game, you can try the following things:
a) Instead of blitting the whole background every frame, use the clear() function to "erase" your sprites from the screen.
b) Instead of calling pygame.display.flip or pygame.display.update without an argument, call pygame.display.update with the list of the areas on the screen that have been changed, which is returned by the draw() function (maybe in combination with clear()).
c) Create your display surface with the FULLSCREEN, DOUBLEBUF and HWSURFACE flags.
But as I already said: make sure you know where your bottle neck is. Some common performance pitfalls are: loading images multiple times from disk, font rendering, using different pixel formats (e.g. not calling convert/convert_alpha on surfaces created from images) and generally the lack of caching.
(also note that python/pygame is generally not the first choice when creating graphically demanding games)
Without seeing your code it will be hard to really see where the bottleneck is. Sloth is correct on his points as a way to optimize. in my experience all images should be pre-processed outside of the main game loop by drawing them onto their own surfaces. Blitting surfaces to surfaces is much faster than blitting images to surfaces.
img_surface = pygame.Surface((img_rect.width, img_rect.height), pygame.SRCALPHA)
img_surface.fill((0, 0, 0, 0))
img_surface.blit(get_image("my_image.png"), img_rect)
This happens outside the game loop. In the game loop you blit the image surface to your surface. If you really want to evaluate you code, use cProfile. This will help you nail down exactly where the bottleneck is. Do as much pre-processing outside the main game loop as possible.
Python getting meaningful results from cProfile
This link really helped me understand cProfile. Sloth is also correct in that pygame is limited, so you are going to need to optimize everything as much as you can. That is where cProfile comes in.
...Also, make sure you are only drawing things that are visible to the user. That can really help improve performance.

PyGame Lag when blitting background

I am trying to reduce the lag in my game as it is unbearable. I understand that when blitting large images I should expect some lag, but I don't see any ways to reduce it. I have the code here: https://gist.github.com/Mrmeguyme/ce1a844af21695d1b853ef88fe8de5aa
The background is 1280x720px, the ground is 1280x100px, and my character is 50x50px.
See http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert_alpha
This is what I do for all my programs:
def loadify(img):
return pygame.image.load(img).convert_alpha()
I just replace pygame.image.load with loadify to save typing. This converts the image to the proper pixel format for faster and easier blitting.
Your images likely have per-pixel transparency. Convert them to opaque.
faster_surface = surface_loaded_directly_from_png.convert()
Of course this isn't applicable to the character, but for the background it will improve things a bit.
EDIT: I also notice you're not calling clock.tick() anywhere. That should smooth things out and removed perceived slowdowns that are actually just the CPU naturally speeding up and slowing down.

Is there a way to stretch the whole display image to fit a given resolution?

I've been using pygame to make a game recently, and have ran into a little problem...
Basically, I would like to be able to stretch the whole image that is on the screen (all the things that I have blitted to it) into the resolution which the user has resized the window to. I've searched a lot on the documentation for pygame and on stack overflow and I can't seem to find an answer... Is it even possible? The source code for my game is pretty big atm, if anyone needs it I'll be willing to post it. Sorry if I made my question a little unclear :)
Blit everything to a separate surface (not directly to the screen), let's call it main_surface. Then blit the main_surface to the screen.
Call pygame.transform.scale(main_surface, (width, height) with the new width and height that you get from the VIDEORESIZE event to scale the main_surface and everything in it to the new window dimensions.

How to optimize tile rendering in pygame?

I am making a tile based game, and the map needs to be rendered every frame. Right now, each tile is 32X32, and the visible map is 28X28 tiles. The performance is dreadful. I recently made it only render the visible tiles, but this still did not improve the FPS much. Right now I'm looking for a way to speed up the rendering. I attribute the slowness to the way I am rendering ; every tile is individually blitted to the screen. What would be a more effective was of doing this?
In pygame (afaik), updating the screen is always one hell of a bottle neck. Since I could not see your code, I don't know, how you are updating the screen. Only blitting the the sprites that changed is a start, but you need to only update those parts that changed, on the screen.
Basically it is the difference between using display.flip() or using update_rects() with only the changed rects. I know, that does not help at all, when you are scrolling the map.
Take a look at this question: Why is this small (155 lines-long) Pacman game on Python running so slow?, it has a similiar topic.
One thing I tried when I had a map compiled of tiles and some sprites on it, I tried always having a precompiled image of the map for an area containing the currently displayed part and some 200 or so pixels around that, so that I could blit the prepared "ground" (still only in updated parts) without the need of blitting all those tiles contained in it. That, of course, is quite some thinking you have to put into that, espacially if you have multiple layers and parts of the map that can be above your active sprites. It is interesting to think and work that through, but I cannot tell you, how much you will gain by that.
One totally different possible solution: I began with pygame once (since I did SDL in C++ prior to that). Recently I was directed to another python gaming library: pyglet. This does not suffer from the problems of updating the whole screen as much as pygame (I think it's because of usage of OpenGL acceleration; it still works on my not at all accelerated eee-Netbook). If you are not bound to pygame in any way, it might be interesting to take a look at pyglet.

Pygame: Blitting a moving background creates too much blur

What I am trying to do is create a viewport to view a small portion of a background. (And later put sprites in).
However the problem I have noticed is there seems to be an issue of the background blurring when it starts moving. I was not sure if this is because blitting is slow or because of a problem in the code. I was looking for examples on how others blit or create scrolling backgrounds and found this article: Scrolling Games
I used their simple example and sure enough the background appears blurry as you scroll (aka blit the background with an offset). I also thought it might be the FPS dropping for whatever reason however it doesn't deviate at all. I can't recall an issue like this with other 2D games. I understand there may be some motion blur due to it constantly shifting. Just wondering if I can do anything to alleviate this. Can someone chime in on anything I may be missing? I would appreciate any feedback or help. Thank you
I couldn't know what caused the problem you faced, but I guess it is related to double buffering.
Did you use at least two surfaces?
# preparing two surfaces in __init__()
screen = pygame.display.set_mode((800,600))
background = pygame.Surface(screen.get_size())
background.fill((250, 250, 250))
# called at every step in main loop
# draw images on the background surface
background.blit(image, position)
....
# blit background to screen
screen.blit(background, (0, 0))
pygame.display.flip()
If images are drawn on the screen surface directly, flicking occurs.
By "blurry" do you mean that the background appears "doubled"? Do you get the same effect when moving a normal-sized (e.g., 64x64) sprite?
If you are seeing double, then it's probably a refresh rate problem. Turning on vsync may help.
What frame rate are you getting?
If you slow down the animation to around 10 FPS, do you have the same problem?

Categories