Mercurial > skaapsteker
view skaapsteker/sprites/player.py @ 272:630ebb87b38a
Remove debugging print
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Fri, 08 Apr 2011 17:32:50 +0200 |
parents | 56a529a69e97 |
children | 95e2ef31e714 |
line wrap: on
line source
"""Class for dealing with the player""" import pygame.transform import time from ..sprites.base import TILE_SIZE, PC_LAYER, MONSTER_LAYER from ..physics import Sprite from ..constants import Layers from ..data import get_files, load_image from ..engine import PlayerDied class Player(Sprite): collision_layer = PC_LAYER collides_with = set([MONSTER_LAYER]) wants_updates = True block = True _max_sprint_time = 2 def __init__(self, the_world, soundsystem): Sprite.__init__(self) 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 self._last_time = time.time() # State flags and such self.attacking = 0 self.running = False self.sprinting = 0 self.jumping = False self.flying = False self._load_images() # We muck with these in load for convience, so ensure they're right self.the_world = the_world self.set_facing('left') self.set_image() self.set_pos((0, 0)) self._collisions_seen = 0 self._last_collide = [] self._layer = Layers.PLAYER def set_image(self): key = self._make_key(len(self.the_world.fox.tails)) images = self._image_dict[key] if self._animation_frame >= len(images): self._animation_frame = 0.0 if self.rect: cur_pos = self.collide_rect.midbottom else: cur_pos = (0, 0) # TODO: can save a lot of calculation here by caching collision rects cand_image = images[int(self._animation_frame)] cand_collide_rect = cand_image.get_bounding_rect(1).inflate(-2,-2) 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 # We always allow the attacking animation frames if not self.check_collide_rect(cand_collide_rect, cand_rect, cand_image) and not self.attacking: 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): v_x, v_y = self.velocity # Never animate slower than !7 fps, never faster than ~15 fps if self.attacking > 0: if self._last_time: if time.time() - self._last_time > 0.15: self._animation_frame += 1 self.attacking -= 1 self._last_time = time.time() else: self._last_time = time.time() else: old_frame = self._animation_frame self._animation_frame += abs(v_x) / 300 time_diff = time.time() - self._last_time if int(self._animation_frame) - int(old_frame) > 0: # Check time diff if time_diff < 0.10: # Delay animation frame jump self._animation_frame -= abs(v_x) / 300 else: self._last_time = time.time() elif time_diff > 0.20: # Force animation frame jump self._animation_frame = old_frame + 1 self._last_time = time.time() if self.sprinting > 0: if (time.time() - self._sprint_start_time) > self._max_sprint_time: self.sprinting = 0 if abs(v_x) < 80: # Clamp when we're not moving at least 5 pixel / s self.velocity = (0, v_y) if self.sprinting == 1: self.sprinting = 0 self.running = not self.on_solid # if you're not on something you can't stand else: self.velocity = (0, v_y) # Standard platformer physics if self.sprinting > 0: self.sprinting = 1 self.running = True self.set_image() if self._collisions_seen > 2 * len(self._last_collide): # Can we find a position "nearby" that reduces the collision # surface best_move = (0, 0) clip_area = 0 for obj in self._last_collide[:]: if not obj.collide_rect.colliderect(self.collide_rect): # Prune stale objects from the list self._last_collide.remove(obj) continue clip = obj.collide_rect.clip(self.collide_rect) clip_area += clip.width * clip.height if (obj.floor or obj.block) and \ clip.width > TILE_SIZE[0] / 2 and \ self.collide_rect.bottom < obj.collide_rect.top + TILE_SIZE[1] / 3: delta = self.rect.bottom - self.collide_rect.bottom self.collide_rect.bottom = obj.collide_rect.top - 1 self.rect.bottom = self.collide_rect.bottom + delta self.init_pos() return # Jump out of this case min_area = clip_area for attempt in [(0, 2), (2, 0), (-2, 0), (2, 2), (-2, 2)]: clip_area = 0 for obj in self._last_collide: cand_rect = self.collide_rect.move(attempt) clip = obj.collide_rect.clip(cand_rect) clip_area += clip.width * clip.height if clip_area < min_area: min_area = clip_area best_move = attempt elif clip_area == min_area and attempt[1] > best_move[1]: # Of equal choices, prefer that which moves us downwards best_move = attempt self.collide_rect.move_ip(best_move) self.rect.move_ip(best_move) self.init_pos() self._last_collide = [] self._collisions_seen = 0 def set_facing(self, new_facing): self.facing = new_facing def collided(self, other): if self.attacking and hasattr(other, 'damage'): # FIXME: Check if we're facing the right way other.damage(5) if other not in self._last_collide and (other.floor or other.block): self._last_collide.append(other) self._collide_pos = self.collide_rect.midbottom self._collisions_seen = 0 elif other in self._last_collide: self._collisions_seen += 1 if hasattr(other, 'collided_player'): other.collided_player(self) print 'Health', self.the_world.fox.cur_health def damage(self, damage): self.the_world.fox.cur_health -= damage self._soundsystem.play_sound('yelp') if self.the_world.fox.cur_health <= 0: PlayerDied.post() def restore(self): """Restore player to max health (for restarting levels, etc.)""" self.the_world.fox.cur_health = self.the_world.fox.max_health def set_pos(self, pos): self.rect.midbottom = pos[0] * TILE_SIZE[0] + self.rect_offset[0], (pos[1] + 1) * TILE_SIZE[1] + self.rect_offset[1] self.collide_rect.midbottom = pos[0] * TILE_SIZE[0], (pos[1] + 1) * TILE_SIZE[1] def action_left(self): if self.facing != 'left': self.facing = 'left' self.set_image() if self.sprinting > 0: self.sprinting = 1 self.deltav((-900.0, 0.0)) else: self.deltav((-450.0, 0.0)) def action_double_left(self): # FIXME: Tie this to the tails if self.sprinting > 0: return self.sprinting = 2 self._sprint_start_time = time.time() def action_double_down(self): print 'double down tap' def action_double_right(self): if self.sprinting > 0: return self.sprinting = 2 self._sprint_start_time = time.time() def action_right(self): if self.facing != 'right': self.facing = 'right' self.set_image() if self.sprinting > 0: self.sprinting = 1 # Flag so stopping works self.deltav((900.0, 0.0)) else: self.deltav((450.0, 0.0)) def action_up(self): if self.on_solid: self.deltav((0.0, -self.terminal_velocity[1])) self.on_solid = False def action_down(self): self.deltav((0.0, 100.0)) def action_fire1(self): # FIXME: Use the correct tail properties for this if len(self.the_world.fox.tails) < 2: # Only have a bite attack print 'attacking' self.attacking = 2 print "F1" def action_fire2(self): print "F2" def _get_action(self): if self.attacking: return 'attacking' if (self.sprinting > 0) and self.running: return 'sprinting' if self.running: return 'running' if self.jumping: return 'jumpin' return 'standing' def _make_key(self, tails, action=None): if action is None: action = self._get_action() if tails >= 4: tails = 4 elif tails >= 2: tails = 2 return '%s %s %d' % (action, self.facing, tails) def _load_images(self): 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) def take_item(self, item): my_item = self.the_world.fox.item if my_item is not None: print "I already have", my_item return getattr(self.the_world.items, item.name).level = "gone" self.the_world.fox.item = item.name item.kill() print "took", item