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

Re: [pygame] sprite engine




Thanks for your fast response. It's ok to not show the code if it will be a commercial product. So lets talk a bit about theory.

I though that to be fast, the screen update area has to be as minimal as posible (so, essentially this means that do not update a pixel twice). So far this is still a problem to solve for me because I do not know how to do this in a fast way.

The second thing was that most information (especially not changing) has to be stored by the renderer to have fast acces ( dereferencing can slow things down).

And the other thing is to minimize the information needed. I think one need following thing to know about a sprite:

image
rect
oldrect
dirty
area (attention to when rect/image size changes!!)
layer
lostrects (only for renderer)
(perhaps in future: blendmode)

In my code I store oldrect, layer and lostrects in the renderer itself.


But I wanted also that one could use the pygame.sprite.groups (except draw() and clear() ), so that one could code the same way as till now. But perhaps this has to change altough so far it was not a big problem.



I finally came up with following way to implement my sprite engine (very general):


1. find screen update area (area on screen that has to be updated, as minimal as possible)
2. blit any sprite that has a part in a screen update area (in the right order of layers!)



The area in point 1. are all areas where sprites has to be removed (cleared) from screen and area that has to be redrawen (essentially oldrect and rect). Also the sprite that has been removed (lostsprites) generates a screen update area.


The 2. point is easier. Check every sprite on collision with a screen update area and if so blit it.

Perhaps it can be done in a better way. So what do you say to me algorithme?

~DR0ID





Yeah, that's a good start. You're right, you need to keep the picture as an object attribute somewhere, you can't be loading it from disk every time you need to draw it. I call this routine 'Paint' in my code; some might call it 'Refresh.' But it IS different from 'Draw', and should be called as little as possible.

Avoid keeping both oldrect and newrect. I did that in old versions of my sprite engine, and it was overkill, and led to difficult-to-detect dirty rectangle bugs. Instead, maintain a single rectangle. Whenever the sprite changes size or position, call a routine to handle most of the scut work for you. This routine shouuld first dirty the area of the screen of the EXISTING rectangle, update the rectangle based on the current size/position, then dirty the screen for the UPDATED rectangle. I haven't had a dirty rectangle bug since implementing this method.

When adding rectangles to the dirty rectangle list, do some optimization. Check to see if there's a rectangle in the list that the new rectangle collides with - if so, enlarge that rectangle to accommodate both. It saves lots of redrawing.

Finally, the 'Draw' routine should be based on the dirty rectangles. For each dirty rectangle, it goes through each sprite on the screen from lowest to highest zorder, and if it touches the dirty rectangle, redraws the sprit there.

I don't know what 'lostrects' would be for... or 'blendmode.' I use pixel-level alpha on all game sprites, so there's I don't use a single 'surface alpha'.

Finally - the use of the 'dirty' flag. I also use that, but only for 'paint.' It's a whopper of an enhancement! Instead of repainting the sprite any time the text changes, the color changes, the font changes, the picture changes, etc., I only 'mark it' as dirty - I don't repaint right then. Marking it as dirty, sets the dirty flag to 1, and dirties that area of the screen. In the main draw routine, IF the picture is 'dirty', I 'Paint' it (the expensive operation), reset the dirty flag to 0, then blit it. This allows 20 different routines to affect the sprite, yet only have a single expensive 'paint' routine called at the end. It makes the engine work well even on slower machines.

Though I don't generally pass out code, I sometimes pass on suggestions. I hope you find them helpful.

--Kamilche