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
from operator import itemgetter
from magicor import g_printkeys,g_devflags,dbgPrint

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

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

00021 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


00123 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()

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

00203     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))

00228     def setAnimation(self, name, bResetIndex=True):
        """
        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
            
00257     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

00321     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.veldir = [0,0]
        self.fasteness = 0
        self.level = level

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

    def eventFalling(self):
        pass

    def eventStop(self):
        pass

    def hack_info_vel(self):
        """build self.veldir and self.fasteness from native params"""
        pass

    def doAction(self,action):
        if action=='die':
            self.kill()

    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

##-> support functions for PhysicsStoneSprite

# bStop signals the cases where the sprite position must be updated to the last
#point where colision doenst occur; alternatively
# bNonBlockingInteraction = not bStop
00514 def getSpritesTouched( self,toTravel ):
    #move the sprite to the tentative position; if no colision: done, else
    #for each sprite do: move self from initial position to tentative position in
    #steps of one, when colision detected freeTravel can be calc. The min free travel
    #will be the final free travel ( counting only the sprites with bStop = True )
    #if both sprites are small and fasteness is not small collision
    #can be missed
    x0=self.x; y0=self.y
    #q: we need the pygame sprite moved, this really do it? Y. remember to
    #restore prior to return
    self.rect.x += self.veldir[0]*toTravel
    self.rect.y += self.veldir[1]*toTravel
    r=self.radius
    minFreeTravel = toTravel    
    tl=[]
    bGenStuck = False
    steps=int(toTravel)+1
    dbgPrint( 'sb', g_devflags['F5'], "@@in spriteTouch - tryMove=",toTravel,"  steps=",steps)
    dx=toTravel/float(steps)*self.veldir[0]
    dy=toTravel/float(steps)*self.veldir[1]
    for group,ignoreSubgroup, minOverlap,bStop, self_action, inflict_action in self.collisionTable:
        for s in pygame.sprite.spritecollide(self, group, False):
            if ((ignoreSubgroup is None) or
                (ignoreSubgroup is not None and s.subgroup!=ignoreSubgroup)
               ):
                dbgPrint( 'sb', g_devflags['F5'], "@@@ spriteTouched x,y,width,height",s.x,s.y,s.width,s.height)
                dbgPrint( 'sb', g_devflags['F5'], "@@@ sprite   Ball x,y,width,height",x0,y0,self.width,self.height)
                dbgPrint( 'sb', g_devflags['F5'], "@@@   moved  Ball x,y", self.rect.x,self.rect.y)
                ww=s.width-2.*minOverlap; hh=s.height-2.*minOverlap
                target=pygame.Rect(s.x+minOverlap,s.y+minOverlap,ww,hh)
                #####-> must be from the initial position
                px=x0+self.width/2.-r   ; py=y0+self.height/2.0-r
                bBump = False
                for i in range(0,steps):
                    dbgPrint( 'sb', g_devflags['F5'], "          probe left,right:",px,px+2*r)
                    if target.colliderect( px,py,2.*r,2.*r ):
                        bBump=True
                        break
                    px+=dx
                    py+=dy
                dbgPrint( 'sb', g_devflags['F5'], "bBump=",bBump,"  i=",i)
                if bBump:
                    if i==0 and bStop:
                        bStuck = True
                        bGenStuck = True
                        freeTravel = 0
                        overshot = toTravel
                    else:
                        bStuck = False
                        freeTravel = (i-1)/float(steps)*toTravel
                        overshot = toTravel - freeTravel 
                else:
                    bStuck = False
                    freeTravel = toTravel
                    overshot = 0
                dbgPrint( 'sb', g_devflags['F5'], "overshot",overshot)
                tl.append( ( freeTravel, minOverlap, bStop,bStuck,
                             group, s,
                             self_action, inflict_action) )
                if bStop and freeTravel<minFreeTravel:
                    minFreeTravel=freeTravel
    get0=itemgetter(0) #to acces member 0 of tuple without unpacking
    tl = [ v for v in tl if get0(v)<=minFreeTravel ]  
    self.rect.x = x0
    self.rect.y = y0
    return minFreeTravel, bGenStuck, tl

def collide_bounce(self,toTravel): ## to chek: maybe a dummy spriteTofollow is needed
00582     self.veldir = self.bounceDir
    if self.bounceFactor:
        toTravel = toTravel * self.bounceFactor
        self.fasteness *= self.bounceFactor
        if self.fasteness < 0.1:
            self.fasteness = 0
            toTravel = 0
            #maybe set mov_0 as movement, or call event stopped
    return toTravel

#stick is a variant of bounce when the stone loose al velocity
def collide_stick(self, bounceDir, toTravel, spriteToFollow=None):
    ## NOTE: probably wrong, never tested nor updated. Consider as placeholder.
    #maybe more work is needed when collisions with sprite and self is
    #following another sprite. Or we need an 'scrap' sister function that will be
    #the OnCollision when sprite is atached to a sprite.
    #if there is a timed event after stick , we need to add code to track this.
    self.veldir = bounceDir
    toTravel = 0
    self.fasteness = 0
    if spriteToFollow is not None:
        self.followMe = spriteToFollow
    if self._animations.has_key["stick"]: ## lava can have more than 1 stick
        #sequence: born, stick to world, loose stone
        self.setAnimation["stick"]
    elif self._animationName != "default":
        self.setAnimationName = "default"
    return toTravel

def mov_0(self):
    # NOTE: untested and unupdated. Consider a placeholder
    if self.followMe is not None:
        if not self.followMe.alive():
            self.followMe = None
            #### set mov_v
        else:
            prev_x=self.x
            self.x = self.followMe.x
            #tentative, maybe we dont need to detach
            if self.followMe.falling or not self.followMe.moving:
                self.followMe=None

    if self.unmovingTimelimit:
        self.unmovingTime -=1
        if self.unmovingTime <= 0:
            self.unmovingTerminated(self)
    #maybe collision code , with scrap and crush detection
            


def mov_h(self,toTravel):
    x0=self.x;y0=int(self.y)
    r=self.radius
    bOutOfScreen = False
    bBump = False
    nonColisionTravel = toTravel
    x1=x0+self.veldir[0]*toTravel
    if self.veldir[0]<0:
        if x1+self.width<0:
            bOutOfScreen = True
        elif self.level[int(x1)/32,y0/32]:
                #world colision
                x1 = (int(x1)/32+1)*32
                nonColisionTravel = x0-x1
                self.bounceDir = [1,0]
                bBump = True
        else:
            pass
    else:
        if x1>=self.level.width*32:
            bOutOfScreen = True
        elif self.level[int(x1+self.width)/32,y0/32]:
                #world colision
                excess=int(x1+self.width)%32 #+1 seems correct but looks worse
                x1 -= excess
                nonColisionTravel = x1-x0
                self.bounceDir = [-1,0]
                bBump = True
        else:
            pass
    return bBump, toTravel, nonColisionTravel, bOutOfScreen

def mov_v(self,toTravel):
    x0=int(self.x);y0=self.y
    r=self.radius
    bOutOfScreen = False
    bBump = False
    nonColisionTravel = toTravel
    y1=y0+self.veldir[1]*toTravel
    if self.veldir[1]<0:
        if y1+self.height<0:
            bOutOfScreen = True
        elif self.level[x0/32,int(y1)/32]:
                #world colision
                y1 = (int(y1)/32+1)*32
                nonColisionTravel = y0-y1
                self.bounceDir = [0,1]
                bBump = True
        else:
            pass
    else:
        if y1>=self.level.height*32:
            bOutOfScreen = True
        elif self.level[x0/32,int(y1+self.height)/32]:
                #world colision
                excess = int(y1+self.height)%32+1
                y1 -= excess
                nonColisionTravel = y1-y0
                self.bounceDir = [0,-1]
                bBump = True
        else:
            pass
    return bBump, toTravel, nonColisionTravel, bOutOfScreen


def mov_diagonal(self,toTravel):
    #asume fasteness <32
    x0=self.x;y0=self.y
    r=self.radius-1
    veldir = self.veldir
    level = self.level
    bOutOfScreen = False
    bBump = False
    nonColisionTravel = toTravel
    #tentative next pos
    x1=x0+veldir[0]*toTravel
    y1=y0+veldir[1]*toTravel
    #check out of screen
    if veldir[0]<0:
        if x1+self.width<0:
            bOutOfScreen = True
    else:
        if x1>=self.level.width*32:
            bOutOfScreen = True
    if veldir[1]<0:
        if y1+self.height<0:
            bOutOfScreen = True
    else:
        if y1>=self.level.height*32:
            bOutOfScreen = True
    if bOutOfScreen:
        return bBump, toTravel, toTravel, bOutOfScreen

    #test colision by checking  the posible colisions of three points
    #if a,b center of stone,
    #the case test are:
    #    (a,b)+r*cos(45)*veldir
    #    (a,b)+r*(veldir[0],0)
    #    (a,b)+r*(0,veldir[1])
    #and we need to test if colisions happens when moving
    #dt*fasteness*veldir
    a=x0+self.width/2.0
    b=y0+self.height/2.0

    aa=a+r*veldir[0]
    bb=b+r*veldir[1]

    steps = int(toTravel)+1;
    dx=self.fasteness/float(steps)*veldir[0]
    dy=self.fasteness/float(steps)*veldir[1]
    
    self.bounceDir = veldir
    for i in range(0,steps):
        aa += dx; a += dx 
        bb += dy; b += dy
        #note: aa and bb seems the correct but with veldir >0 bounces prematurelly
        #with (aa-1) and (bb-1) looks better, albeit not perfect.
        if level[int(aa)/32,int(b)/32]:
            bBump=True
            self.bounceDir[0]=-veldir[0]
        if level[int(a)/32,int(bb)/32]:
            self.bounceDir[1]=-veldir[1]
            bBump = True
        if bBump:
            break

    if not bBump:
        aa=(x0+self.width/2.0)+r*0.7071*veldir[0]
        bb=(y0+self.height/2.0)+r*0.7071*veldir[1]
        for i in range(0,steps):
            aa += dx
            bb += dy
            if level[int(aa)/32,int(bb)/32]:
                bBump=True
                self.bounceDir[0]=-veldir[0]
                self.bounceDir[1]=-veldir[1]
            if bBump:
                break
    if bBump:
        nonColisionTravel = i/float(steps)*toTravel
    else:
        nonColisionTravel = toTravel
        
    return bBump, toTravel, nonColisionTravel, bOutOfScreen
        
00777 def calcSpriteBounceDir( ts , s ):
    """ts sprite to bounce
    s obstacle sprite
    .move() must be mov_diag"""
    #for robustness the entire plane is partitioned in five regions:
    #the diagonals of sprite target grows to the infinite. points over the
    #diagonals are one region, the interior of each rotated quadrant are the
    #others. Then, sprite to bounce is asigned the region of its center.
    #Each region has an obvious meaning of tell bounce dir.
    #diagonals are:
    #   y= s.height/s.width(x-s.x)+ s.y
    #   y=-s.height/s.width(x-s.x)+ s.y+s.height
    # note: if minOverlap is refined to (minOverlap_x,minOverlap_y) then
    #       corrections will be needed
    #       algoritms that revert one or more components of veldir proven not
    #       robust.

    cx = ts.x+ts.width/2.
    cy = ts.y+ts.height/2.
    
    u = s.height/float(s.width)*(cx-s.x)
    d1 =  u + s.y - cy
    d2 = -u + s.y+s.height -cy
    dbgPrint( 'sb', g_devflags['F5'], "d1=",d1,"   d2=",d2)
    if abs(d1)<0.3 or abs(d2)<0.3:
        #into diagonals
        if s.x+s.width/2.<cx:
            ts.bounceDir[0]= 1
            if s.y+s.height/2.<cy:
                ts.bounceDir[1]= 1
            else:
                ts.bounceDir[1]=-1
        else:
            ts.bounceDir[0]=-1
            if s.y+s.height/2.<cy:
                ts.bounceDir[1]= 1
            else:
                ts.bounceDir[1]=-1
    else:
        #not in diagonals
        if d1>0:
            if d2>0:
                ts.bounceDir[1]=-1
                ts.bounceDir[0]=ts.veldir[0]
            else:
                ts.bounceDir[0]=1
                ts.bounceDir[1]=ts.veldir[1]
        else:
            if d2>0:
                ts.bounceDir[0]=-1
                ts.bounceDir[1]=ts.veldir[1]
            else:
                ts.bounceDir[1]= 1
                ts.bounceDir[0]=ts.veldir[0]

00832 class PhysicsStoneSprite(AnimatedSprite):
    """ non living entities
    visual aspect must be near round, to facilitate colision detection"""
    def __init__(self, level, x, y, w, h, animations,radius, veldir,
                 fasteness, collisionTable=[], dvy=0., bounceFactor=1, subgroup="global"):
        AnimatedSprite.__init__(self, x, y, w, h, animations)
        self.level = level
        self.radius = radius
        self.veldir = veldir
        self.fasteness = fasteness
        if fasteness<0:
            self.move = mov_0
        elif veldir[0] and veldir[1]:
            self.move = mov_diagonal
        elif veldir[0]:
            self.move = mov_h
        else:
            self.move = mov_v
            
        self.subgroup = subgroup
        self.bounceFactor = bounceFactor
        self.dvy = dvy
        dbgPrint( 'sb', g_devflags['F5'], "##################### in constructor phstones: dvy=",self.dvy)
        self.collisionTable = collisionTable

        self.moving = fasteness>0
        self.tubed = False
        self.falling = False
        self.bounceDir = None

    def hack_info_vel(self): #must be NOP. 
        pass

    def physics(self):
        maxBounces = 4
        x0 = self.x
        y0 = self.y
        r = self.radius
        dvy = self.dvy
        if dvy:
            dt = 1.0
            toTravel = 0.5*dvy + self.fasteness*self.veldir[1]
            if toTravel<0:
                toTravel = -toTravel
        else:
            toTravel = self.fasteness
        while toTravel and maxBounces:
            maxBounces -= 1
            dbgPrint( 'sb', g_devflags['F5'], "@@@@@@@@@@@@@@ maxBounces=",maxBounces)
            bBump, toTravel, nonColisionTravel, bOutOfScreen = self.move(self,toTravel)  
            dbgPrint( 'sb', g_devflags['F5'],"    bBump=",bBump,"   toTravel=",toTravel,"  nonColisionTravel=",nonColisionTravel)
            maxTravel, bGenStuck, tl = getSpritesTouched( self, nonColisionTravel )
            dbgPrint( 'sb', g_devflags['F5'],"   maxTravel=",maxTravel,"   bGenStuck=",bGenStuck)
            x1 = x0 + maxTravel*self.veldir[0]
            y1 = y0 + maxTravel*self.veldir[1]
            self.x = x1; self.y=y1
            self.rect.x=x1; self.rect.y=y1
            #update toTravel, and fasteness if grav
            if not dvy:
                toTravel -= maxTravel
            else:
                if toTravel<=maxTravel:
                    used_dt = dt
                else:
                    used_dt = dt*maxTravel/toTravel
                    if used_dt<0:
                        used_dt = -used_dt
                dt -= used_dt
                if self.veldir[1]>0:
                    self.fasteness += used_dt*dvy
                else:
                    self.fasteness -= used_dt*dvy
                    if self.fasteness<0:
                        self.fasteness = -self.fasteness
                        self.veldir[1]=1
                toTravel = (0.5*dvy+self.fasteness*self.veldir[1])*dt
                if toTravel<0 :
                    toTravel = -toTravel
                if toTravel<1.e-6:
                    toTravel = 0
            dbgPrint( 'sb', g_devflags['F5'],"     decremented toTravel=",toTravel)

            x0=x1; y0=y1
            if bOutOfScreen:
                bOutOfScreen = ( x1+self.width<0 or x1>self.level.width or
                                 y1+self.height<0 or y1>self.level.height )

            #handle world colisions
            if nonColisionTravel==maxTravel:
                if bBump:
                    toTravel = self.OnWorldCollision(self,toTravel)
                    tl=[] # at the risk of loosing some touch, empty the list
                          # and let the next pass detect the touchs ( reason:
                          # bounce after bounce of world colision does bad -->
                          #UPDATE: badiness untested-unanalized for this version)

            #process all sprite touch
            for freeTravel, minOverlap, bStop,bStuck, collideGroup, spriteTouched,\
                                     self_action, inflict_action in tl:
                dbgPrint( 'sb', g_devflags['F5'],"@@@", self_action )
                if self_action =="bounceSelf" or self_action=="bounceBoth":
                    spriteTouched.hack_info_vel()
                    dbgPrint( 'sb', g_devflags['F5'], "bounce; veldir=[ %d , %d ]"%(self.veldir[0],self.veldir[1]))

                    #get bounce direction for self
                    if not(self.veldir[0] and self.veldir[1]):
                        self.bounceDir = [-self.veldir[0],-self.veldir[1]]
                    else:
                        calcSpriteBounceDir( self , spriteTouched )
                    dbgPrint( 'sb', g_devflags['F5'], "   bounceDir=[ %d , %d ]"%(self.bounceDir[0],self.bounceDir[1]))

                    #if not bounceBoth must handle the 'chase' case
                    if self_action=="bounceSelf":
                        fasteness = self.fasteness
                        #code can be added to reduce fasteness when rev chase
                        if (self.bounceDir[0] and
                            self.bounceDir[0]==spriteTouched.veldir[0] and
                            self.fasteness<spriteTouched.fasteness):
                            fasteness = spriteTouched.fasteness
                        if (self.bounceDir[1] and
                            self.bounceDir[1]==spriteTouched.veldir[1] and
                            self.fasteness<spriteTouched.fasteness):
                            fasteness = spriteTouched.fasteness
                        #adjust to travel after the bounce
                        #NOTE: maybe bounceFactor must be handled here, before
                        #the toTravel adjust
                        if ( toTravel and 
                             ( fasteness!=self.fasteness
                               or (dvy and self.veldir[1]!=self.bounceDir[1]))
                             ):
                            if dvy:
                                dt = toTravel/(0.5*dvy+self.fasteness*self.veldir[1])
                                toTravel = (0.5*dvy+fasteness*self.bounceDir[1])*dt
                                if toTravel<0:
                                    toTravel = -toTravel
                            else:
                                if self.fasteness>1.e-6:
                                    toTravel *= fasteness/self.fasteness
                                else:
                                    toTravel = fasteness
                        self.fasteness = fasteness

                    else: #"bounceBoth" , untested
                        #'bounce' direction for spriteTouched, simetrical to bounceSelf
                        if isinstance( spriteTouched,PhysicsStoneSprite ):
                            if not(spriteTouched.veldir[0] and spriteTouched.veldir[1]):
                                spriteTouched.bounceDir = [-spriteTouched.veldir[0],-spriteTouched.veldir[1]]
                            else:
                                calcSpriteBounceDir( spriteTouched, self )
                                collide_bounce( spriteTouched , 0)
                        else:
                            #old style physycs sprite; they only move h or v
                            # TODO
                            pass
                        #spriteTouched.doAction("afterBeBounced")

                    toTravel = collide_bounce(self,toTravel)
                    dbgPrint( 'sb', g_devflags['F5'],"   after bounce toTravel=",toTravel)
### note: maybe the else must catch self_action=='atach'
                else:
                    self.doAction(self_action)
                spriteTouched.doAction(inflict_action)
            #good, all sprite touchs procesed                             
            if bOutOfScreen:
                self.kill()
                return
        #tryied to move k-times
        if toTravel:
            dbgPrint( 'sb', g_devflags['F5'], "@@@probably stuck-crushed. toTravel=",toTravel)

 
    def doAction(self,action):
        if action=='die':
            self.kill()

# probably we must add detection of "crushed"

Generated by  Doxygen 1.6.0   Back to index