changeset 622:da331c80ec08

Clean up sprite inheritance hierarchy a bit.
author Jeremy Thurgood <firxen@gmail.com>
date Sat, 07 May 2011 13:42:27 +0200
parents 851c8726696c
children 65881746dc20
files skaapsteker/levelscene.py skaapsteker/physics.py skaapsteker/sprites/base.py skaapsteker/sprites/items.py skaapsteker/sprites/player.py
diffstat 5 files changed, 80 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/skaapsteker/levelscene.py	Fri May 06 17:54:24 2011 +0200
+++ b/skaapsteker/levelscene.py	Sat May 07 13:42:27 2011 +0200
@@ -77,7 +77,7 @@
         self._player = player.Player(self.game_state.world, self._soundsystem)
         self._player.set_facing(doorway.facing)
         self._player.set_image()
-        self._player.set_pos(doorway._starting_tile_pos)
+        self._player.set_pos(doorway.get_tile_pos())
 
         # Double tap stuff
         self._last_keydown_time = None
--- a/skaapsteker/physics.py	Fri May 06 17:54:24 2011 +0200
+++ b/skaapsteker/physics.py	Sat May 07 13:42:27 2011 +0200
@@ -52,7 +52,7 @@
         self._mask_cache = {} # image id -> collision bit mask
 
     def init_pos(self):
-        self._float_pos = self.rect.topleft
+        self._float_pos = self.rect.center
 
     def get_debug_color(self):
         return self.debug_color
@@ -67,10 +67,10 @@
 
 
     def deltap(self, dt):
-        old_pos = self.rect.topleft
+        old_pos = self.rect.center
         self._float_pos = cadd(self._float_pos, cmul(self.velocity, dt))
-        self.rect.topleft = cint(self._float_pos)
-        delta_pos = csub(self.rect.topleft, old_pos)
+        self.rect.center = cint(self._float_pos)
+        delta_pos = csub(self.rect.center, old_pos)
         self.collide_rect.move_ip(delta_pos)
         self.floor_rect.move_ip(delta_pos)
 
--- a/skaapsteker/sprites/base.py	Fri May 06 17:54:24 2011 +0200
+++ b/skaapsteker/sprites/base.py	Sat May 07 13:42:27 2011 +0200
@@ -34,42 +34,43 @@
 class GameSprite(Sprite):
     image_dir = 'sprites/'
     image_file = None
+    sprite_layer = None
 
     def __init__(self, pos, **opts):
         Sprite.__init__(self)
-        self._starting_tile_pos = pos
+        if self.sprite_layer is not None:
+            # pygame's Sprite class clobbers self._layer in __init__(), so we need to thwart it.
+            self._layer = self.sprite_layer
+        self.setup_image_data(pos)
         self.setup(**opts)
-        self.setup_image_data(pos)
 
     def setup(self):
         pass
 
+    def get_tile_pos(self):
+        return cdiv(self.rect.center, TILE_SIZE)
+
     def setup_image_data(self, pos):
         self.image = data.load_image(self.image_dir + self.image_file)
         self.rect = self.image.get_rect(midbottom=tile_midbottom(pos))
         self.collide_rect = self.rect.move(0, 0)
 
 
-class AnimatedGameSprite(Sprite):
-    # folder for animation files, e.g. sprites/foo
-    image_dir = None
-
+class AnimatedGameSprite(GameSprite):
     # first item is the starting animation
-    animation_regexes = [
+    animation_regexes = (
         # TODO: swap back once we know how to swap
         ("running", r"^.*_\d+.png$"),
         ("standing", r"^.*_standing.png$"),
         ("attacking", r"^.*_attacking.png$"),
-    ]
+    )
 
     wants_updates = True
-
     frame_pause = 0.1  # default time between animation frames
+    facings = None
 
-    facings = {}
 
-    def __init__(self, pos, **opts):
-        Sprite.__init__(self)
+    def setup_image_data(self, pos):
         self._animations = dict((k, []) for k, r in self.animation_regexes)
         self._frame = 0
         self._last_time = 0
@@ -103,10 +104,7 @@
         else:
             self.collide_rect.midbottom = tile_midbottom(pos)
         self._update_image()
-        self.setup(**opts)
 
-    def setup(self):
-        pass
 
     def _update_image(self, force=False):
         if self.facing:
@@ -149,6 +147,7 @@
 
 class Monster(AnimatedGameSprite):
 
+    sprite_layer = Layers.PLAYER
     collision_layer = MONSTER_LAYER
     collides_with = set([PC_LAYER, PROJECTILE_LAYER])
 
@@ -156,13 +155,12 @@
 
     block = True
 
-    attack_frame = None  # Mark a spefici frame in the animatio n as when the attack lands
+    attack_frame = None  # Mark a speficic frame in the animation as when the attack lands
     attack_damage = 1
 
     def __init__(self, pos, **opts):
         AnimatedGameSprite.__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._done_attack = False
         self.setup(**opts)
@@ -273,6 +271,7 @@
 
 class NPC(AnimatedGameSprite):
 
+    sprite_layer = Layers.PLAYER
     collision_layer = NPC_LAYER
     collides_with = set([])
 
@@ -283,10 +282,6 @@
     block = False
     actionable = True
 
-    def __init__(self, pos, **opts):
-        AnimatedGameSprite.__init__(self, pos, **opts)
-        self._layer = Layers.PLAYER
-
     def setup(self, name, world, dsm, state, facing=None):
         self.name = name
         self.world = world
@@ -375,14 +370,11 @@
     actionable = True
     liftable = True
 
+    sprite_layer = Layers.PLAYER
     collision_layer = NPC_LAYER
 
     debug_color = (240, 0, 240)
 
-    def __init__(self, pos, **opts):
-        GameSprite.__init__(self, pos, **opts)
-        self._layer = Layers.PLAYER
-
 
     def setup(self, name, world):
         self.name = name
@@ -484,16 +476,17 @@
     actionable = False
     liftable = False
     image_dir = 'sprites/skulls/'
+    sprite_layer = Layers.BEHIND
     debug_color = (255, 255, 0)
 
+
     def __init__(self, pos, player=False, **opts):
         self._pos = pos
         if player:
             self.image_file = 'kitsune.png'
         else:
             self.image_file = 'monster.png'
-        GameSprite.__init__(self, pos, **opts)
-        self._layer = Layers.BEHIND
+        super(Skeleton, self).__init__(pos, **opts)
 
     def setup_image_data(self, pos):
         GameSprite.setup_image_data(self, pos)
--- a/skaapsteker/sprites/items.py	Fri May 06 17:54:24 2011 +0200
+++ b/skaapsteker/sprites/items.py	Sat May 07 13:42:27 2011 +0200
@@ -29,7 +29,7 @@
         if not self._me.broken:
             self._me.broken = True
             self.broken = True
-            self.setup_image_data(self._starting_tile_pos)
+            self.setup_image_data(self.get_tile_pos())
             if self.breaking_sound[0] is not None:
                 sound.play_sound(self.breaking_sound[0])
 
--- a/skaapsteker/sprites/player.py	Fri May 06 17:54:24 2011 +0200
+++ b/skaapsteker/sprites/player.py	Sat May 07 13:42:27 2011 +0200
@@ -5,33 +5,31 @@
 import pygame.transform
 from pygame.constants import BLEND_RGBA_MULT
 
-from ..physics import Sprite
 from ..constants import Layers, FoxHud, DOUBLE_TAP_TIME
 from ..data import get_files, load_image
 from ..engine import PlayerDied, AddSpriteEvent, OpenNotification
 from ..utils import cadd
 
-from .base import (find_sprite, Monster, NPC, Item, Doorway, TILE_SIZE,
-                   PC_LAYER, MONSTER_LAYER, PROJECTILE_LAYER, tile_midbottom)
+from .base import (find_sprite, AnimatedGameSprite, Monster, NPC, Item, Doorway,
+                   TILE_SIZE, PC_LAYER, MONSTER_LAYER, PROJECTILE_LAYER,
+                   tile_midbottom)
 from .projectiles import Fireball, Lightning
 from .items import BreakableItem
 
 
 
-class Player(Sprite):
+class Player(AnimatedGameSprite):
 
+    sprite_layer = Layers.PLAYER
     collision_layer = PC_LAYER
     collides_with = set([MONSTER_LAYER, PROJECTILE_LAYER])
     wants_updates = True
-
     block = True
 
-
     def __init__(self, the_world, soundsystem):
-        Sprite.__init__(self)
+        super(Player, self).__init__((0, 0))
         self.image = None
         self.rect = None
-        self._image_dict = {}
         self._soundsystem = soundsystem
         self._soundsystem.load_sound('yelp', 'sounds/yelp.ogg')
         self._animation_frame = 0.0
@@ -53,8 +51,6 @@
         self.prep_flight = 0.0
         self.invisible = 0
         self.using_shield = 0
-        self.shape = 'fox'  # Needed so load image does the right thing
-        self._load_images()
         self.inventory_image = None
         # We muck with these in load for convience, so ensure they're right
         self.the_world = the_world
@@ -65,7 +61,53 @@
         self.set_pos((0, 0))
         self._collisions_seen = 0
         self._last_collide = []
-        self._layer = Layers.PLAYER
+
+
+    def setup_image_data(self, pos):
+        self.shape = 'fox'  # Needed so load image does the right thing
+        self._image_dict = {}
+        self._shield_image = load_image('sprites/kitsune_shield.png')
+        for action in ['standing', 'running', 'jumping', 'attacking']:
+            for tails in [0, 1, 2, 4]:
+                directory = 'sprites/kitsune_%s/kitsune_%s_%dtail' % (action, action, tails)
+                for facing in ['left', 'right']:
+                    self.facing = facing
+                    key = self._make_key(tails, action)
+                    self._image_dict[key] = []
+                    for image_file in get_files(directory):
+                        if image_file.startswith('.'):
+                            # Skip extra junk for now
+                            continue
+                        image = load_image('%s/%s' % (directory, image_file))
+                        if action == 'running':
+                            sprint_key = self._make_key(tails, 'sprinting')
+                            if sprint_key not in self._image_dict:
+                                self._image_dict[sprint_key] = []
+                            shockwave = load_image('sprites/kitsune_shockwave.png')
+                            if facing == 'right':
+                                shockwave = pygame.transform.flip(shockwave, True, False)
+                        if facing == 'right':
+                            image = pygame.transform.flip(image, True, False)
+                        self._image_dict[key].append(image)
+                        if action == 'running':
+                            sprint_image = image.copy()
+                            sprint_image.blit(shockwave, (0, 0))
+                            self._image_dict[sprint_key].append(sprint_image)
+        for shape, name in [('human', 'disguise_'), ('human_with_fan', 'disguise-fan_')]:
+            directory = 'sprites/kitsune_disguise'
+            for facing in ['left', 'right']:
+                key = '%s_running_%s' % (shape, facing)
+                standing_key = '%s_standing_%s' % (shape, facing)
+                self._image_dict[key] = []
+                for image_file in get_files(directory):
+                    if name not in image_file:
+                        continue
+                    image = load_image('%s/%s' % (directory, image_file))
+                    if facing == 'right':
+                        image = pygame.transform.flip(image, True, False)
+                    self._image_dict[key].append(image)
+                self._image_dict[standing_key] = [self._image_dict[key][0]]
+
 
     def set_image(self):
         key = self._make_key(len(self._me.tails))
@@ -259,8 +301,7 @@
 
     def set_pos(self, pos):
         self.rect.midbottom = cadd(tile_midbottom(pos), self.rect_offset)
-        # self.collide_rect.midbottom = pos[0] * TILE_SIZE[0], (pos[1] + 1) * TILE_SIZE[1] # Is this wrong?
-        self.collide_rect.midbottom = self.rect.midbottom
+        self.collide_rect.midbottom = tile_midbottom(pos)
 
     def action_left(self):
         self.set_facing('left')
@@ -464,60 +505,10 @@
             tails = 2
         return '%s %s %d' % (action, self.facing, tails)
 
-    def _load_images(self):
-        self._shield_image = load_image('sprites/kitsune_shield.png')
-        for action in ['standing', 'running', 'jumping', 'attacking']:
-            for tails in [0, 1, 2, 4]:
-                directory = 'sprites/kitsune_%s/kitsune_%s_%dtail' % (action, action, tails)
-                for facing in ['left', 'right']:
-                    self.facing = facing
-                    key = self._make_key(tails, action)
-                    self._image_dict[key] = []
-                    for image_file in get_files(directory):
-                        if image_file.startswith('.'):
-                            # Skip extra junk for now
-                            continue
-                        image = load_image('%s/%s' % (directory, image_file))
-                        if action == 'running':
-                            sprint_key = self._make_key(tails, 'sprinting')
-                            if sprint_key not in self._image_dict:
-                                self._image_dict[sprint_key] = []
-                            shockwave = load_image('sprites/kitsune_shockwave.png')
-                            if facing == 'right':
-                                shockwave = pygame.transform.flip(shockwave, True, False)
-                        if facing == 'right':
-                            image = pygame.transform.flip(image, True, False)
-                        self._image_dict[key].append(image)
-                        if action == 'running':
-                            sprint_image = image.copy()
-                            sprint_image.blit(shockwave, (0, 0))
-                            self._image_dict[sprint_key].append(sprint_image)
-        for shape, name in [('human', 'disguise_'), ('human_with_fan', 'disguise-fan_')]:
-            directory = 'sprites/kitsune_disguise'
-            for facing in ['left', 'right']:
-                key = '%s_running_%s' % (shape, facing)
-                standing_key = '%s_standing_%s' % (shape, facing)
-                self._image_dict[key] = []
-                for image_file in get_files(directory):
-                    if name not in image_file:
-                        continue
-                    image = load_image('%s/%s' % (directory, image_file))
-                    if facing == 'right':
-                        image = pygame.transform.flip(image, True, False)
-                    self._image_dict[key].append(image)
-                self._image_dict[standing_key] = [self._image_dict[key][0]]
-
-
     def discard_item(self):
         self._me.item = None
 
 
-    def get_tile_pos(self):
-        return [a/b for a, b in zip(self.rect.center, TILE_SIZE)]
-
-    def get_tile_for_pos(self, pos):
-        return [a/b for a, b in zip(pos, TILE_SIZE)]
-
     def get_sprite(self, set_level):
         my_item = self._me.item
         if my_item is None: