Logo Search packages:      
Sourcecode: magicor version File versions  Download package

__init__.py

00001 """
Sprites animation library.

Copyright 2006  Peter Gebauer. Licensed as Public Domain.
(see LICENSE for more info)
"""

import pygame.sprite

from magicor.resources import getResources

00012 class Frame(object):
    """
    Base type for animation frames.
    """

    def __str__(self):
        return "<Frame>"

00020 class ResourceFrame(Frame):
    """
    Any type of animation frame resource.    
    """

    def __init__(self, resource):
        self.resource = resource

    def __str__(self):
        return "<ResourceFrame>"

class ImageFrame(ResourceFrame):

    def __init__(self, surface, width, height):
        ResourceFrame.__init__(self, surface)
        self.width = width
        self.height = height

    def __str__(self):
        return "<ImageFrame %dx%d>"%(self.width, self.height)


class SoundFrame(ResourceFrame):

    def __init__(self, sound):
        ResourceFrame.__init__(self, sound)

    def __str__(self):
        return "<SoundFrame>"


class JumpFrame(Frame):

    def __init__(self, index):
        Frame.__init__(self)
        self.index = index

    def __str__(self):
        return "<JumpFrame %d>"%self.index


class MoveFrame(Frame):

    def __init__(self, x, y):
        Frame.__init__(self)
        self.x = x
        self.y = y

    def __str__(self):
        return "<MoveFrame %.2f, %.2f>"%(self.x, self.y)
    

class AnimationFrame(Frame):

    def __init__(self, frame, delay):
        Frame.__init__(self)
        self.frame = frame
        self.delay = delay

    def __str__(self):
        return "<AnimationFrame %d %d>"%(self.frame, self.delay)


class SetFrame(Frame):

    def __init__(self, animationName):
        Frame.__init__(self)
        self.animationName = animationName

    def __str__(self):
        return "<SetFrame '%s'>"%self.animationName


class KillFrame(Frame):

    def __str__(self):
        return "<KillFrame>"


class AttributeFrame(Frame):

    def __init__(self, attr, value):
        Frame.__init__(self)
        self.attr = attr
        self.value = value

    def __str__(self):
        return "<AttributeFrame %s=%s>"%(self.attr, self.value)


class CallbackFrame(Frame):

    def __init__(self, callback, *args, **kwargs):
        Frame.__init__(self)
        self.callback = callback
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        return "<CallbackFrame %s>"%self.callback.func_name


00122 class AnimationGroup(pygame.sprite.Group):
    """
    A group of animated objects.
    """

    def __init__(self, *sprites):
        pygame.sprite.Group.__init__(self, *sprites)
        self.r = pygame.Rect((0, 0, 0, 0))

    def draw(self, surface):
        for sprite in self.sprites():
            sprite.draw(surface)

    def sort(self, f = None):
        if not f:
            f = self.sortFunc
        self.sprites().sort(f)

    def sortFunc(self, a, b):
        if a.y == b.y:
            return cmp(a.x, b.x)
        return cmp(a.y, b.y)
    
    def add(self, *sprites):
        pygame.sprite.Group.add(self, *sprites)
        #self.sprites().sort(self.sortFunc)

    def remove(self, *sprites):
        pygame.sprite.Group.remove(self, *sprites)

    def getSpriteAt(self, x, y, exclude, type_ = None):
        for sprite in self.sprites():
            if (sprite != exclude
                and sprite.x == x
                and sprite.y == y
                and (not type_ or isinstance(sprite, type_))
                ):
                return sprite
        return None

    def count(self):
        return len(self.sprites())

    def getSprite(self, x, y, width, height, exclude = None, type_ = None):
        return self._getSprites(x, y, width, height, exclude, type_)

    def getSprites(self, x, y, width, height, exclude = None, type_ = None):
        return self._getSprites(x, y, width, height, exclude, type_, False)

    def _getSprites(self, x, y, width, height, exclude, type_, single = True):
        ret = []
        self.r.left = x
        self.r.top = y
        self.r.width = width
        self.r.height = height
        for sprite in self.sprites():
            if (sprite != exclude
                and self.r.colliderect(sprite.rect)
                and (not type_ or isinstance(sprite, type_))
                ):
                if single:
                    return sprite
                ret.append(sprite)
        if single:
            return None
        return ret

    def animate(self):
        for s in self.sprites():
            s.animate()

    def update(self):
        for s in self.sprites():
            s.update()

00197 class AnimatedSprite(pygame.sprite.Sprite):
    """
    A sprite type that animates.
    """

00202     def __init__(self, x, y, w, h, animations, default = None):
        """
        Arguments:
        animations          A dictionary containing lists of animation frames.
        groups              Sequence of sprite groups.
        default             Default animation key.
        """
        pygame.sprite.Sprite.__init__(self)
        self.resources = getResources()
        self._animations = animations
        self.width = w
        self.height = h
        self.x = x
        self.y = y
        self._frameIndex = 0
        self.rect = pygame.Rect((x, y, w, h))
        if default:
            self.setAnimation(default)
        else:
            self.setAnimation("default")

    def isDone(self):
        animation = self._animations[self._animationName]
        return bool(not animation or self._index >= len(animation))

00227     def setAnimation(self, name):
        """
        Use specified set of animation.
        Raises KeyError if the animation set is not found.
        """
        if not self._animations.has_key(name):
            raise KeyError("no animation named '%s' for sprite %s"
                           %(name, type(self)))
        self._animationName = name
        self._index = 0
        self._count = 0
        self.image = None
        self.flags = {}
        self._srcRect = pygame.Rect((0, 0, 0, 0))
        for frame in self._animations[name]:
            if isinstance(frame, ImageFrame):
                self.image = self.resources[frame.resource]
                self.rect.left = self.x
                self.rect.top = self.y
                self.rect.width = frame.width
                self.rect.height = frame.height
                if self.width is None:
                    self.width = frame.width
                if self.height is None:
                    self.height = frame.height
            elif self.image and isinstance(frame, AnimationFrame):
                self._frameIndex = frame.frame
                break
            
00256     def animate(self):
        """
        Animates the sprite.
        """
        name = self._animationName
        animation = self._animations[self._animationName]
        while self._index < len(animation):
            if name != self._animationName:
                name = self._animationName
                animation = self._animations[self._animationName]
            frame = animation[self._index]
            if isinstance(frame, ImageFrame):
                self.image = self.resources[frame.resource]
                self.rect.left = self.x
                self.rect.top = self.y
                self.rect.width = frame.width
                self.rect.height = frame.height
                self._index += 1
            elif isinstance(frame, SetFrame):
                self.setAnimation(frame.animationName)
            elif isinstance(frame, JumpFrame):
                self._index = frame.index
            elif isinstance(frame, KillFrame):
                self.kill()
                break
            elif isinstance(frame, AnimationFrame):
                if self._count == 0:
                    self._frameIndex = frame.frame
                self._count += 1
                if self._count > frame.delay:
                    self._index += 1
                    self._count = 0
                else:
                    break
            elif isinstance(frame, MoveFrame):
                self.x += frame.x
                self.y += frame.y
                self._index += 1
            elif isinstance(frame, SoundFrame):
                self.resources.playSound(frame.resource)
                self._index += 1
            elif isinstance(frame, AttributeFrame):
                if hasattr(self, frame.attr):
                    setattr(self, frame.attr, frame.value)
                self._index += 1
            elif isinstance(frame, CallbackFrame):
                frame.callback(*frame.args, **frame.kwargs)
                self._index += 1
            else:
                raise TypeError("invalid frame, %s in sprite %s"
                                %(frame, self))

    def physics(self):
        pass

    def update(self):
        if self.alive():
            self.physics()
            self.animate()
        self.rect.x = self.x
        self.rect.y = self.y
        self.rect.width = self.width
        self.rect.height = self.height

00320     def draw(self, surface, offsetX = 0, offsetY = 0):
        """
        Draw the sprite using animation specs.
        """
        surface.blit(self.image,
                     (self.x + offsetX, self.y + offsetY),
                     (self._frameIndex * self.width,
                      0, self.width, self.height)
                     )

    def colliding(self, group):
        ret = []
        for s in self.group.sprites():
            if (s != self
                and ((self.x >= s.x
                      and self.x <= s.x + s.width
                      and self.y >= s.y
                      and self.y <= s.y + s.height)
                     or
                     (s.x >= self.x
                      and s.x <= self.x + self.width
                      and s.y >= self.y
                      and s.y <= self.y + self.height)
                     )):
                ret.append(s)
        return ret
                

class PhysicsSprite(AnimatedSprite):

    def __init__(self, level, x, y, w, h, animations, blocksGroup,
                 default = None):
        AnimatedSprite.__init__(self, x, y, w, h, animations, default)
        self.blocksGroup = blocksGroup
        self.moving = 0
        self.tubed = False
        self.falling = False
        self.level = level

    def testFall(self):
        return (not self.blockedBelow())

    def eventFalling(self):
        pass

    def eventStop(self):
        pass

    def physics(self):
        x, y = self.x / 32, self.y / 32
        right, bottom = (self.x + 32) / 32, (self.y + 32) / 32
        if self.falling:
            if self.blockedBelow() or not self.testFall():
                self.falling = False
                self.eventStop()
            else:
                self.y += 4
        else:
            if (y >= self.level.height * 32 or self.testFall()):
                self.falling = True
                self.moving = 0
                self.eventFalling()
            elif self.moving > 0:
                if (x >= self.level.width - 1
                    or self.tubed
                    or not self.blockedRight()):
                    self.x += 4
                self.moving -= 1
            elif self.moving < 0:
                if (x <= 0
                    or self.tubed
                    or not self.blockedLeft()):
                    self.x -= 4
                self.moving += 1

    def blockedLeft(self):
        x, y = (self.x - 1) / 32, self.y / 32
        if (self.x <= 0
            or self.level[x, y]
            or self.blocksGroup.getSprite(self.x - 1,
                                          self.y,
                                          0,
                                          self.height,
                                          self)
            ):
            return True
        return False
    
    def blockedRight(self):
        x, y = (self.x + self.width) / 32, self.y / 32
        if (self.x + self.width >= self.level.width * 32
            or self.level[x, y]
            or self.blocksGroup.getSprite(self.x + self.width,
                                          self.y, 0, self.height,
                                          self)
            ):
            return True
        return False

    def blockedLeftAbove(self):
        x, y = (self.x - 1) / 32, (self.y - 1) / 32
        if (self.x <= 0
            or self.level[x, y]
            or self.blocksGroup.getSprite(self.x - 1, self.y - 1,
                                          0, 0, self)
            ):
            return True
        return False
    
    def blockedRightAbove(self):
        x, y = (self.x + self.width) / 32, (self.y - 1) / 32
        if (self.x + self.width >= self.level.width * 32
            or self.level[x, y]
            or self.blocksGroup.getSprite(self.x + self.width,
                                          self.y - 1, 0, 0, self)
            ):
            return True
        return False

    def blockedBelow(self):
        x, y = self.x / 32, (self.y + self.height) / 32
        xr = (self.x + self.width - 1) / 32
        if (xr < 0 or xr > 19):
            return True
        elif (y < self.level.height
            and (self.level[x, y]
                 or self.level[xr, y]
                 or self.blocksGroup.getSprite(self.x,
                                               self.y + self.height,
                                               self.width, 0, self)
                 )
            ):
            return True
        return False

    def blockedAbove(self):
        x, y = self.x / 32, (self.y - 1) / 32
        xr = (self.x + self.width - 1) / 32
        if (xr < 0 or xr > 19 or self.level[xr, y]):
            return True
        elif (y >= 0
              and (self.level[x, y]                   
                   or self.blocksGroup.getSprite(self.x,
                                                 self.y - 1,
                                                 self.width, 0, self)
                 )
            ):
            return True
        return False

    def blockedRightBelow(self):
        x, y = (self.x + self.width) / 32, (self.y + self.height) / 32
        if (y < self.level.height
            and (self.x + self.width >= self.level.width * 32
                 or x > 19
                 or self.level[x, y]
                 or self.blocksGroup.getSprite(self.x + self.width,
                                               self.y + self.height,
                                               0, 0, self)
                 )
            ):
            return True
        return False

    def blockedLeftBelow(self):
        x, y = (self.x - 1) / 32, (self.y + self.height) / 32
        if (y < self.level.height
            and (self.x <= 0
                 or x < 0
                 or self.level[x, y]
                 or self.blocksGroup.getSprite(self.x - 1,
                                               self.y + self.height,
                                               0, 0, self)
                 )
            ):
            return True
        return False


Generated by  Doxygen 1.6.0   Back to index