Mercurial > mamba
view mamba/snake.py @ 188:d76c069164c0
Much better interaction detection.
author | Jeremy Thurgood <firxen@gmail.com> |
---|---|
date | Wed, 14 Sep 2011 17:41:26 +0200 |
parents | 3449b51ae944 |
children | d488731886dc |
line wrap: on
line source
"""The player snake object.""" from pygame.sprite import Group, spritecollide from pygame.locals import BLEND_MULT from mamba.constants import TILE_SIZE from mamba.sprites import BaseSprite from mamba.engine import SnakeDiedEvent from mamba import mutators class Snake(object): UP, DOWN, LEFT, RIGHT = [(0, -1), (0, 1), (-1, 0), (1, 0)] def __init__(self, tile_pos, orientation): self.segments = self.create_segments(tile_pos, orientation) self.segment_group = Group() self.segment_group.add(*reversed(self.segments)) self.set_orientation(orientation) self.speed = 120.0 # pixel / s self.frac_ds = 0.0 self.mutation = None head = property(fget=lambda self: self.segments[0]) tail = property(fget=lambda self: self.segments[-1]) def create_segments(self, tile_pos, orientation): tx, ty = tile_pos dx, dy = orientation segments = [] for cls in [Head] + [Body] * 10 + [Tail]: segments.append(cls((tx, ty))) return segments def draw(self, surface): self.segment_group.draw(surface) def update(self, dt, world): ds = dt * self.speed + self.frac_ds ds, self.frac_ds = divmod(ds, 1) ds = int(ds) while True: tile_state = self.head.get_tile_state() shifted, ds = self.head.shift_head(ds) if not shifted: break self.head.set_orientation(self.orientation) for segment in self.segments[1:]: old_tile_state = segment.get_tile_state() segment.shift_tile(tile_state) tile_state = old_tile_state for segment in self.segments: segment.shift_pixels(ds) world.interact(segment) def set_orientation(self, orientation): self.orientation = orientation def crash(self): SnakeDiedEvent.post() def mutate(self, mutation): self.mutation = mutation def can_swim(self): return self.mutation == 'amphibious' class Segment(BaseSprite): GREEN = mutators.Overlay("tiles/common/snake/green.png", BLEND_MULT) BLUE = mutators.BLUE RED = mutators.RED YELLOW = mutators.YELLOW _detail_mutators = () is_head = False def __init__(self, image_name, tile_pos): super(Segment, self).__init__() self.set_base_image(image_name) self._colour_overlay = self.GREEN self.orientation = Snake.UP self.make_images() self.update_image() self.set_tile_pos(tile_pos) self.on_tiles = [] def filter_collisions(self, group): collide = [] tiles = spritecollide(self, group, False) for tile in tiles: if tile not in self.on_tiles: collide.append(tile) self.on_tiles = tiles return collide def set_base_image(self, image_name): self._base_image = "/".join(["snake", image_name]) def make_images(self): self._images = {} for orientation, muts in [ (Snake.RIGHT, (mutators.RIGHT,)), (Snake.LEFT, (mutators.LEFT,)), (Snake.UP, (mutators.UP,)), (Snake.DOWN, (mutators.DOWN,)), ]: all_muts = (self._colour_overlay,) + self._detail_mutators + muts self._images[orientation] = self.load_image(self._base_image, all_muts) def update_image(self): self.image = self._images[self.orientation] def set_orientation(self, orientation): self.orientation = orientation self.update_image() def set_colour(self, colour_overlay): self._colour_overlay = colour_overlay self.make_images() self.update_image() def get_tile_state(self): return self.tile_pos, self.orientation def shift_tile(self, tile_state): """Shift this segment to the tile the other one was on. Also reset the position to be the center of the tile. """ tile_pos, orientation = tile_state self.set_tile_pos(tile_pos) self.orientation = orientation def shift_pixels(self, distance): """Shift this segment a number of pixels.""" dx, dy = self.orientation dx, dy = distance * dx, distance * dy self.rect = self.rect.move(dx, dy) class Head(Segment): CLOSED = "snake-head" OPEN = "snake-head-mouth-open-r" EYE = mutators.Overlay("tiles/common/snake/snake-head-eye-r.png") TONGUE = mutators.Overlay("tiles/common/snake/snake-head-tongue-r.png") is_head = True def __init__(self, tile_pos): self._detail_mutators = (self.EYE,) super(Head, self).__init__(self.CLOSED, tile_pos) def mouth_open(self): self.set_base_image(self.OPEN) self.make_images() self.update_image() def mouth_closed(self): self.set_base_image(self.CLOSED) self.make_images() self.update_image() def tongue_out(self): self._detail_mutators = (self.EYE, self.TONGUE) self.make_images() self.update_image() def tongue_in(self): self._detail_mutators = (self.EYE,) self.make_images() self.update_image() def shift_head(self, ds): """Shift the head a number of pixels in the direction of it orientation. """ dx, dy = self.orientation TX, TY = TILE_SIZE rx, ry = self.rect.left, self.rect.top tx, ty = self.tile_pos # WARNING: Tri-state logic ahead # (Tri-state logic is the mamba's natural habitat) if dx != 0: newdx = rx + ds * dx newtx = newdx / TX if newtx > tx: self.set_tile_pos((tx + 1, ty)) ds = newdx - self.rect.left return True, ds elif newtx < tx - 1: self.set_tile_pos((tx - 1, ty)) ds = self.rect.left - newdx return True, ds else: newdy = ry + ds * dy newty = newdy / TY if newty > ty: self.set_tile_pos((tx, ty + 1)) ds = newdy - self.rect.top return True, ds elif newty < ty - 1: self.set_tile_pos((tx, ty - 1)) ds = self.rect.top - newdy return True, ds return False, ds class Body(Segment): def __init__(self, tile_pos): super(Body, self).__init__("snake-body", tile_pos) class Tail(Segment): def __init__(self, tile_pos): super(Tail, self).__init__("snake-tail", tile_pos)