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

Re: [pygame] Dirty Rect Animation



Hello

Yes I do dirty rect animation. If you read the code of the RenderUpdate (in pygame.sprite.Sprite.RenderUpdates) then you will see that this group does something like this:

dirty = [ ]
if old rect and new rect overlap:
     dirty_rect = old_rect.union(new_rect)
    dirty.append(dirty_rect)
else
    dirty.append(old_rect)
    dirty.append(new_rect

This is done fore each sprite and give an performance boost. But if you have many sprite that overlap then the code above lead still to many overlapping areas. Therefore I use little different approach:

# 1. I have to find out the dirty areas on screen because you have to know the old_rect and the new_rect rect_list = [old_rect, new_rect, .... ] # all rect that affect the screen, afterward it will contain the dirty rects
for rect in rect_list:
_unionR = pygame.Rect(rect) # make a copy because _uionR will be modified i = _unionR.collidelist(rect_list) # find first other rect that collides while -1< i: # repeat it as long there is an colliding rect _unionR.union_ip(rect_list[i]) # union the overlapping rects in place del rect_list[i] #remove the on from the list i = _unionR_collidelist(rect_list) # check if there are still overlapping rects in the list rect_list.append(_unionR.clip(_clip)) # at the end append the new rect to the rect_list (dirty rects now)

This code will handle any overlapping rects on screen. There is one draw back though. If you have a high and small rect and a another with a small hight and a big width then nearly the entire screen will be updated. Parts of the screen will be updated too, which did not change, so you will have to redraw them again (that is a strong reason against that update() should optimize the rects in that way, if it should do it then it should split the overlapping rects into two or three different rects such that only areas in the rects will be updated on screen, see below).

Especially in combination of a dirty flag the second code snippet is useful. I have used it in the FastRenderGroup I have written, here it goes (if you subscribe to the RSS feed then you will stay informed about updates):

http://www.mypage.bluewin.ch/DR0ID/pygame_projects.html#fast_dirty1

In the new release (soon today) I have written a separated LayeredRenderGroup (which is somewhat untested! sorry, had no time to test it) and the FastRenderGroup. The FastRenderGroup can handle about 130 sprites doing dirty rects animation (on a PentiumM 1.5GHz), but with more sprites a full screen update will be faster, so it switches automatically to that mode.

Another approach would be to split the overlapping rects into single, non-overlapping rects. To know how to split rects see (some time ago I have found the following link, but have not tested it and I do not know how fast it really is):

http://barbieri-playground.googlecode.com/svn/pygame/smart_render/smart_render.py


I hope I could help.

~DR0ID





Peter Shinners schrieb:
John Cabral wrote:
I was working on some code for my game and read about the optimization
of feeding a list of rects to the update function.  I was curious if
it would be worthwhile to try to optimize the list that is fed to the
function.  Specifically, I would try to shorten the list by merging
rects that had significant areas of overlap.  However, I can't tell if
the function itself might perform this work itself.   Does anyone
know?

I've found that generally many small rectangles aren't slower than fewer big ones. The most important thing is the area effected.

And yes, overlapping rectangles are processed multiple times, so that can cost big on performance. A little effort to keep big areas from overlapping will pay off.