view skaapsteker/sprites/base.py @ 214:6e7faba82c21

Remove debugging pdb.
author Simon Cross <hodgestar@gmail.com>
date Thu, 07 Apr 2011 00:36:29 +0200
parents c5c4306593d8
children fcc5eca8eaca
line wrap: on
line source

"""Basic sprite classes."""

from pygame import Rect
import re

from skaapsteker.physics import Sprite
from skaapsteker.constants import Layers
from skaapsteker import data
from skaapsteker import dialogue


TILE_SIZE = (64, 64)

# Collision Layers (values are ids not numbers)
PC_LAYER = 0
MONSTER_LAYER = 1
NPC_LAYER = 2



class GameSprite(Sprite):
    image_dir = 'sprites/'
    image_file = None

    def __init__(self, pos, **opts):
        Sprite.__init__(self)
        self.image = data.load_image(self.image_dir + self.image_file)
        self.rect = self.image.get_rect(midbottom=(pos[0]*TILE_SIZE[0]+TILE_SIZE[0]/2, (pos[1]+1)*TILE_SIZE[1]))
        self.collide_rect = self.rect.move(0, 0)
        self.setup(**opts)


class AnimatedGameSprite(Sprite):
    # folder for animation files, e.g. sprites/foo
    image_dir = None

    # first item is the starting animation
    animation_regexes = [
        # TODO: swap back once we know how to swap
        ("running", r"^.*_\d+.png$"),
        ("standing", r"^.*_standing.png$"),
    ]

    wants_updates = True

    def __init__(self, pos, **opts):
        Sprite.__init__(self)
        self._animations = dict((k, []) for k, r in self.animation_regexes)
        self._frame = 0
        self._tick = 0 # TODO: hack to show some animation; kill shortly
        self._animation = self.animation_regexes[0][0]

        for image in data.get_files(self.image_dir):
            print image
            for name, pattern in self.animation_regexes:
                if re.match(pattern, image):
                    img = data.load_image("%s/%s" % (self.image_dir, image))
                    collide_rect = img.get_bounding_rect(1).inflate(-2,-2)
                    self._animations[name].append((img, collide_rect))

        self.collide_rect = Rect((0, 0), (2, 2))
        self.collide_rect.midbottom = (pos[0]*TILE_SIZE[0]+TILE_SIZE[0]/2, (pos[1]+1)*TILE_SIZE[1])
        self._update_image()
        self.setup(**opts)

    def _update_image(self):
        images = self._animations[self._animation]
        if self._frame >= len(images):
            self._frame = 0
        cand_image, cand_collide_rect = images[self._frame]
        cand_collide_rect = cand_collide_rect.move(0, 0) # copy collide rect before we move it

        cur_pos = self.collide_rect.midbottom

        cand_rect = cand_image.get_rect()
        cand_rect_offset = cand_rect.centerx - cand_collide_rect.centerx, cand_rect.bottom - cand_collide_rect.bottom
        cand_rect.midbottom = cur_pos[0] + cand_rect_offset[0], cur_pos[1] + cand_rect_offset[1]
        cand_collide_rect.midbottom = cur_pos

        if not self.check_collide_rect(cand_collide_rect, cand_rect, cand_image):
            return

        self.image = cand_image
        self.collide_rect = cand_collide_rect
        self.rect = cand_rect
        self.rect_offset = cand_rect_offset
        self.init_pos()

    def update(self):
        if self._tick > 10:
            self._tick = 0
            self._frame += 1
            self._update_image()
        self._tick += 1


class Monster(GameSprite):

    collision_layer = MONSTER_LAYER
    collides_with = set([PC_LAYER])

    debug_color = (240, 120, 120)

    block = True

    def __init__(self, pos, **opts):
        GameSprite.__init__(self, pos, **opts)
        self.floor_rect = Rect(self.collide_rect.topleft, (self.collide_rect.width, 2))
        self._layer = Layers.PLAYER
        self.health = 10
        self.setup(**opts)


    def collided_player(self, player):
        print "%s collided with player" % self
        player.damage(1)

    def damage(self, damage):
        print 'Damaged by ', damage
        self.health -= damage
        print 'Monster health', self.health
        if self.health < 0:
            self.kill()


class NPC(AnimatedGameSprite):

    collision_layer = NPC_LAYER
    collides_with = set([PC_LAYER])

    debug_color = (240, 240, 240)

    block = False

    def __init__(self, pos, **opts):
        AnimatedGameSprite.__init__(self, pos, **opts)
        self._layer = Layers.PLAYER

    def setup(self, name, world, dsm):
        self.dsm = dialogue.DSM(name, world, dsm)


    def collided_player(self, player):
        print "%s is ignoring player" % self


class Projectile(GameSprite):
    gravitates = False


class Item(GameSprite):
    mobile = False
    gravitates = False

    collision_layer = MONSTER_LAYER
    collides_with = set([PC_LAYER])

    portable = True

    def __init__(self, pos, **opts):
        GameSprite.__init__(self, pos, **opts)
        self._layer = Layers.PLAYER


    def setup(self, name, world):
        self.name = name
        self.world = world


    def get_debug_color(self):
        if self.portable:
            return (240, 0, 240)
        return (0, 0, 240)


    def collided_player(self, player):
        print "Player touched %s" % self
        player.take_item(self)



class Geography(Sprite):
    mobile = False
    gravitates = False
    collides_with = set([PC_LAYER, MONSTER_LAYER, NPC_LAYER])
    is_ground = True
    bounce_factor = (0.0, 0.0)

    def __init__(self, pos, image):
        Sprite.__init__(self)
        self.tile_pos = pos
        self.image = image
        self.collide_rect = self.image.get_bounding_rect(1)
        self.floor_rect = Rect(self.collide_rect.topleft, (self.collide_rect.width, 2))
        self.rect = self.image.get_rect()
        self.rect_offset = self.collide_rect.left - self.rect.left, self.rect.top - self.rect.top
        self.collide_rect.topleft = pos[0] * TILE_SIZE[0] + self.rect_offset[0], pos[1] * TILE_SIZE[1] + self.rect_offset[1]
        self.floor_rect.topleft = pos[0] * TILE_SIZE[0] + self.rect_offset[0], pos[1] * TILE_SIZE[1] + self.rect_offset[1]
        self.rect.topleft = pos[0] * TILE_SIZE[0], pos[1] * TILE_SIZE[1]

    def get_debug_color(self):
        if self.floor or self.block:
            return (240, 240, 0)
        return (0, 240, 0)


def find_sprite(descr, mod_name=None):
    """Create a sprite object from a dictionary describing it."""
    descr = descr.copy()
    cls_name = descr.pop("type")
    if mod_name is None:
        mod_name, cls_name = cls_name.rsplit(".", 1)
    mod_name = ".".join(["skaapsteker.sprites", mod_name])
    mod =  __import__(mod_name, fromlist=[cls_name])
    cls = getattr(mod, cls_name)
    return cls(**descr)