[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Lousy FPS




--- Kris Schnee <kschnee@xxxxxxxxxx> wrote:

> In each case the underlying world data is the same. My thinking in doing
> the GL version was that I wouldn't have to draw those awkward diagonal
> tiles, and that I'd be able to rotate to any angle. I tested it just now
> and got 12 FPS (using a time.sleep(.05) call so the max would be 20).
> OK, I said, the tradeoff is that the Pygame isometric version would be 
> faster than the OpenGL.
> 
> So I tested the isometric version. 6 FPS, even with the logo and 
> interface turned off. Not good. How can my pasting tiles on a 2D surface 
> be slower than calling an OpenGL list of lists of 3D cube-drawing 
> instructions?
 
Your server appears to be down right now, but I'm familiar with the old Pygame
engine screenshots already. My main question would be "how many tiles are you
trying to draw, and how are you trying to draw them?" Python's performance
plummets when it's calling hundreds of tile-drawing functions through a
for-loop, and I assume that that's what you're doing in both versions. My rough
rule of thumb would be to stay under 1000 tiles per frame, and preferably under
500 if you want to have lots of cpu headroom. Performance is particularly bad
if you're using a nested sequence type with a corresponding for-loop for each
dimension, like this:

for x in tilemap:
    for y in x:
        for x in z:
            drawtile(z)

(Presumably, since this is an isometric engine, you'd have a z loop.)

Running the draw routine with only one loop nets a surprisingly large gain in
performance. I do this by setting up a "drawing cache" that is a list of
tuples, with each entry pointing to the original data structure and adding
positioning info:

cache = [(foo[0][0][0],0,0,0),(foo[0][0][1],0,0,1),....]

[drawtile(c[0],c[1],c[2],c[3]) for c in cache]

Pygame alone is always going to have trouble drawing a full-screen game. The
only things you can really do to solve the problem are limit resolution or
carefully minimize the amount drawn(eg. no smooth scrolling). A render loop in
C could help, but blits take the majority of the cpu time in Pygame and it
would be no different with C.

Under OpenGL, if you run the cache into a display list outside of your main
loop, you can call the display list once per frame and it will draw all the
tiles very quickly, quickly enough so that performance is a non-issue. Pygame
can get some of the same benefit by rendering the entire map to a "background"
surface and drawing that every frame. The only problem is that you have to
recreate the display list each time your tiles change. For scrolling, you can
simply overdraw(draw everything, even offscreen stuff) without major penalties
both in Pygame and OpenGL, if the map isn't too big. If you want the tiles to
change dynamically, then you have to redraw at some point, and to optimize
performance implies the use of some kind of culling mechanism. It could easily
get VERY complicated to do that for an isometric engine.

Hopefully that's enough to get you started with some optimization. I'm sure
it's possible to get decent performance; but depending on what you've done it
might take some major reworking of the renderer design.

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com