# Pygame - alternatives?

## Recommended Posts

@Julie.chan Well I'm fairly sure it's not because of floating point errors, as I usually try to avoid using floating point arithmetics for my stuff. I'm also not using "delta time" approaches, I have a fixed time step for my update methods. So for example the main character moves exactly 1 pixel per update. Also, the performance of my machine is high enough to handle much higher framerates, so my approach was to try to limit it to e.g. 60 FPS and also having 60 updates. However, it's not as stable as if I do the same in C++ (I once created a game prototype with a scrolling background in Python and then basically ported the whole thing over to C++ with SDL, and even though both games had basically the same framerate, the scrolling was far more smooth in the C++ version than in the Pygame version, which was jittering all the time).

@Astrofra Well I'm looking for something 2D actually.

I haven't profiled yet but as I said I assume no performance issues. As far as I'd assume, the reason for this all might be that the main loop of my game is written in Python (because I have to write it myself), and in some other engines/frameworks such as Love2D, the main loop is probably written in the C/C++ part. But not sure if that's really the reason. But as I said, when I coded the same thing in both Pygame and C++, the C++ version was much smoother and much more stable, whereas the Pygame version jittered.

Btw I have tried to use pygame.HWSURFACE but it seems like there happens no difference.

##### Share on other sites

In the few years or so I've spent optimizing the SGE Game Engine, I've found that the typical dogma regarding performance with Pygame is inaccurate. In particular, "dirty" sprites make almost no difference (and often none at all) in real-world applications; the real choke point is looping for things like collision detection, which is why the most important optimization I made with the SGE Game Engine was the "object areas" system, which groups all objects by general position so that looping is minimized.

Also, the performance of my machine is high enough to handle much higher framerates, so my approach was to try to limit it to e.g. 60 FPS and also having 60 updates. However, it's not as stable as if I do the same in C++ (I once created a game prototype with a scrolling background in Python and then basically ported the whole thing over to C++ with SDL, and even though both games had basically the same framerate, the scrolling was far more smooth in the C++ version than in the Pygame version, which was jittering all the time).

What framerate the machine can handle depends on the game. Have you verified the actual framerate the game is running at? You may be surprised if you haven't. I have this one game I developed (actually the first one I made with the SGE Game Engine) that's much, much slower than the rest, probably because I used scaling too much (though it's an unimportant game so I haven't investigated much).

##### Share on other sites

Of course I have tested this, otherwise I wouldn't say it. My games are retro pixel-style and they run with between 180 and 400 FPS on my system. My update calls and collision checks are certainly not the problem. However, when I limit such a game to 60 FPS using pygame.Clock, it will never be plain 60 but sometimes 58-59 and sometimes 61-62. There are times where sprites move smoothly (exactyl 1 pixel per frame) but sometimes it gets shaky and jittery in certain parts of the screen. It's no surprise to me however as VSync is not enabled and thus having a game with close-to-60 running on a monitor with exactly 60 Hz is of course going to yield this effect.

As I said, re-coding the whole game in C++ with SDL helps, as I have done that. But I don't want to do that with every game I have, as I prefer to code in Python.

##### Share on other sites

180 FPS? Have you considered reverse delta timing, then (slowing things down to run at a higher FPS)? That would surely help. I have my games configured with a "delta max" (as it's called in the SGE) of 4 times the target rate, and a "delta min" of half the target rate. It would avoid noticeable "jittering" and make the controls smoother at the same time, plus this is much easier for the computer to do than keeping the FPS at a precise rate (which, like I said, isn't 100% reliable anyway since some refresh rates can differ from 60 Hz).

Of course, you'll need to start using floats if you do this, so you'll want to store the "real" position separately from the displayed position. I just use floor() on the "real" position (and I'm not using Pygame's sprite system, so it's just a matter of calling floor() any time I blit a surface).

Edited by Julie.chan

##### Share on other sites
On 2/25/2019 at 1:31 PM, drwuro said:

@Astrofra Well I'm looking for something 2D actually.

HARFANG 3D is not "3D only" actually, but ok
https://github.com/harfang3d/game-winter-z

Edited by Astrofra

##### Share on other sites
Quote

As far as I'd assume, the reason for this all might be that the main loop of my game is written in Python

As a developer, with the tools that you should have available to you, you should not make assumptions. You should make assertions based on data like a responsible computer scientist

If you could, right before you enter your main-loop place the following two lines.

pr = cProfile.Profile()
pr.enable()

and at the end of your loop (or after the loop exits) you can place:

pr.print_stats(sort='time')

In addition, at the top of your .py file, you'll want to perform an import of cprofile, i.e. import cProfile. Ideally, you'll only call the print_stats method when pressing some key on your keyboard (using pygame or something) so your stdout isn't completely flooded, but isn't required.

If you could do that, and provide us the print out from the profiler, that'd would be awesome. Without this data, or code for us to review, we can only guess where your frametime is going. I've seen some amazing things done in PyGame with decent performance, so naturally I'm skeptical the reason for your slowdowns is the fact that you've written a, "loop in python"

CPython can be slow, but I'm sure the answer to your question is more nuanced than, "It's pythons fault"

Edited by markypooch

##### Share on other sites

I can and will do that. However, I have the feeling we're talking about different things here. I don't have performance issues or low framerates. I have the problem that the framerate is not rock-solid stable, it's a bit jittery. However that doesn't mean that the code is "slow" or whatever.

I will still provide the data as soon as I can, so we can make sure that's not the problem.

##### Share on other sites

yeah performance issues can be more subtle than just consistently low frametimes. Very interested to see what you get back from profiling!

##### Share on other sites

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
1    0.001    0.001    0.001    0.001 {pygame.display.flip}
1    0.001    0.001    0.001    0.001 {pygame.transform.scale}
16    0.001    0.000    0.001    0.000 {method 'blit' of 'pygame.Surface' objects}
2    0.000    0.000    0.000    0.000 {pygame.draw.rect}
1    0.000    0.000    0.001    0.001 gloomy.py:551(render)
1    0.000    0.000    0.002    0.002 __init__.py:275(flipBuffers)
9    0.000    0.000    0.000    0.000 __init__.py:832(drawText)
1    0.000    0.000    0.000    0.000 cProfile.py:79(print_stats)
4    0.000    0.000    0.000    0.000 gloomy.py:615(_renderCharacter)
1    0.000    0.000    0.000    0.000 pstats.py:62(__init__)
6    0.000    0.000    0.000    0.000 __init__.py:269(drawSprite)
1    0.000    0.000    0.000    0.000 pstats.py:106(load_stats)
1    0.000    0.000    0.000    0.000 pstats.py:84(init)
1    0.000    0.000    0.000    0.000 {isinstance}
1    0.000    0.000    0.000    0.000 cProfile.py:90(create_stats)
1    0.000    0.000    0.000    0.000 {method 'tick_busy_loop' of 'Clock' objects}
2    0.000    0.000    0.000    0.000 __init__.py:265(fillRect)
1    0.000    0.000    0.000    0.000 {method 'sort' of 'list' objects}
4    0.000    0.000    0.000    0.000 gloomy.py:203(isWalking)
1    0.000    0.000    0.000    0.000 __init__.py:194(clearScreen)
1    0.000    0.000    0.000    0.000 {time.time}
1    0.000    0.000    0.000    0.000 {len}
1    0.000    0.000    0.000    0.000 {hasattr}
1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

60 function calls in 0.003 seconds

##### Share on other sites

That test seems much too short and limited to gleam any useful information out of. What did you test, exactly? I usually prefer to test the entire main loop, for at least a minute or two.

## Create an account

Register a new account

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 21
• 15
• 33
• 12
• ### Forum Statistics

• Total Topics
634812
• Total Posts
3019403
×