[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[pygame] y-Sorted RenderGroup



Hello,

   I've developed a RenderUpdate group that sorts it's sprites on their 
y position, useful for things like Japaneese style RPGs where sprites 
closer to the bottom of the screen are drawn first, and sprites near the 
top of the screen are drawn last.

   As you can see, I sort when I paint the sprites, because Python's 
dictionaries return their items in random order, sorting the dictionary 
would be pointless (you can't anyways).  After I sort, I paint the 
sorted list of sprites instead of spritedict.items(), #3 below.  I use 
my own sorting routine called y_sort(a, b).

   My question is, is creating an iternal list inside draw(), "y" in #1 
below, the right way of doing this?  Since draw is called so frequently, 
should I worry about garbage, and make this sorted list a class variable 
(self.y)?  Is there a better way of doing this within the existing 
Sprite classes, or am I on track here?

   Run this program within pygame's examples directory, it uses two of 
the images there for the test.


   TIA: Thanks in advance,
   Steve


------------------------------------------------------------------------


"""
    This is my implementation of a RenderUpdate group that sorts its 
sprites by
y-value before painting them.  This test program puts two sprites down, 
and moves
one "down" the screen over the one that stands still.  When the sprite is
"in front of" the non-moving sprite, you'll see it jump in front of it.

    Run this program in the pygame examples directory, it uses images 
from the example
programs; most notably, the player1.gif and liquid.bmp in the data 
subdirectory.

    This sort of a render group is what I need for isometric or RTS 
games, where sprites
closer to the bottom of the screen are "closer" to the viewer's point of 
view, like
Diablo or Japaneese-style RPG's.
"""


#import everything
import os, pygame
from pygame.locals import *


#***************** My new RenderYSort Group BEGIN ******************
def y_sort(a, b):
    """
        Compare two sprites, if the 'a' sprite's rect is "higher" than
    the 'b' sprite, it return's 1, just like a normal sort function.
    """
    if a[0].rect.top < b[0].rect.top:
        return -1
    elif a[0].rect.top == b[0].rect.top:
        return 0
    else:
        return 1

class RenderYSort(pygame.sprite.RenderUpdates):
    """
        This is the new group type that sorts its sprites before it 
paints them.  The
    only lines that really have changed from a normal RenderUpdates 
group are the three
    commented lines below.
    """
    def draw(self, surface):
        spritedict = self.spritedict
        surface_blit = surface.blit
        dirty = self.lostsprites
        self.lostsprites = []
        dirty_append = dirty.append
        y = spritedict.items()  #1: get a list of the spritedict's items
        y.sort(y_sort)          #2: sort it
        for s, r in y:          #3: use that sorted list
            newrect = surface_blit(s.image, s.rect)
            if r is 0:
                dirty_append(newrect)
            else:
                dirty_append(newrect.union(r))
            spritedict[s] = newrect
        return dirty
#***************** My new RenderYSort Group END ******************
   

#quick function to load an image
def load_image(name):
    path = os.path.join('data', name)
    return pygame.image.load(path).convert()


class Mover(pygame.sprite.Sprite):
    """ A sample sprite."""
    def __init__(self, dx, dy, pos, image):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.midbottom = pos
        self.dx = dx
        self.dy = dy

    def update(self):
        self.rect.move_ip(self.dx, self.dy)
       

#here's the full code
def main():
    pygame.init()
    screen = pygame.display.set_mode((640, 480))
    clock = pygame.time.Clock()

    player = load_image('player1.gif')
    background = load_image('liquid.bmp')
    screen.blit(background, (0, 0))
    pygame.display.flip()

    #set up the all the groups
    all = RenderYSort()
    movers = pygame.sprite.Group()
    Mover.containers = movers, all

    #give me two sample sprites
    Mover(0, 0, (100,100), player)
    Mover(0, 1, (110,50), player)

    while 1:
        for event in pygame.event.get():
            if event.type in (QUIT, KEYDOWN):
                return

        all.clear(screen, background)
        all.update()

        dirty = all.draw(screen)       
        pygame.display.update(dirty)
        clock.tick(20)


if __name__ == '__main__': main()



____________________________________
pygame mailing list
pygame-users@seul.org
http://pygame.seul.org