예제 #1
0
class Bro(entity.Entity):

    MASS = 10
    FRICTION = 0
    SIZE = 32 

    JUMP_VECTOR = (0, 2000)
    SPEED = 100

    FREEZE_FADE = 0.3

    COLLISION_TYPE = 2
    FROZEN_COLLISION_TYPE = 3

    @property
    def color(self):
        return self._color 

    @color.setter
    def color(self, val):
        self._color = val
        self.red = val.red
        self.green = val.green
        self.blue = val.blue

    @color.deleter
    def color(self):
        del self._color
        self.red = 1
        self.green = 1
        self.blue = 1

    @property
    def last_tile(self):
        if self._last_tile is None:
            return None
        else:
            return self._last_tile()

    @last_tile.setter
    def last_tile(self, val):
        # untint old last tile
        if self._last_tile is not None:
            self._last_tile().unset_last_tile_for(self)

        if val is None:
            self._last_tile = None
        else:
            self._last_tile = weakref.ref(val)
            self._last_tile().set_last_tile_for(self)

    def __init__(self, player, space, x=0, y=0, old_bro=None, *args, **kwargs):
        super(Bro, self).__init__(space, 
                x = x,
                y = y,
                mass = Bro.MASS,
                friction = Bro.FRICTION,
                collision_type = Bro.COLLISION_TYPE,
                width = Bro.SIZE,
                height = Bro.SIZE,
                texture = resources.box)
        self.player = player
        self.color = player.color
        self.dead = False
        self.frozen = False
        self.player.bros.append(self)

        # Model state
        self.moving_left = False
        self.moving_right = False
        self.collide_left = False
        self.collide_right = False
        self.shapes_below = WeakSet()
        self._last_tile = None

        # get old bro values
        if old_bro is not None:
            self.moving_left = old_bro.moving_left
            self.moving_right = old_bro.moving_right
            self.last_tile = old_bro.last_tile

    def update(self, dt):
        super(Bro, self).update(dt)

        # Move based on input
        if self.moving_left:
            target_velocity = -Bro.SPEED
        elif self.moving_right:
            target_velocity = Bro.SPEED
        else:
            target_velocity = 0

        self.pymunk_body.velocity.x = target_velocity

        # update player distance
        self.player.distance = int(max(self.x, self.player.distance))

    def freeze(self):
        self.frozen = True
        self.static = True
        self.player.freezes += 1

        self.stop()

        # set collision type for physics callbacks
        #self.pymunk_shape.collision_type = Bro.FROZEN_COLLISION_TYPE

        # Fade sprite
        self.red += Bro.FREEZE_FADE
        self.green += Bro.FREEZE_FADE 
        self.blue += Bro.FREEZE_FADE

    def drop(self):
        if self.frozen:
            self.static = False

    def die(self):
        self.dead = True
        if not self.frozen:
            self.player.deaths += 1
        # unset last tile
        self.last_tile = None
        # remove body from physics space
        self.space.remove(self.pymunk_body, self.pymunk_shape)

    def alive(self):
        return not self.dead and not self.frozen

    def jump(self):
        if self.can_jump():
            self.pymunk_body.apply_impulse(Bro.JUMP_VECTOR, (0, 0))
            # clear the shapes below set 
            for shape in self.shapes_below:
                self.shapes_below.remove(shape)

    def can_jump(self):
        return len(self.shapes_below) > 0

    def move_right(self):
        self.moving_right = True
        self.moving_left = False

    def move_left(self):
        self.moving_left = True
        self.moving_right = False

    def stop_right(self):
        self.moving_right = False

    def stop_left(self):
        self.moving_left = False

    def stop(self):
        self.stop_right()
        self.stop_left()

    @staticmethod
    def setup_collision_handlers(outer_space):

        required_overlap = 15

        # Prior to solbing collision
        def pre_solve_handler(space, arbiter):
            contact = arbiter.contacts[0]

            a = arbiter.shapes[0]
            b = arbiter.shapes[1]
            # if a is above b
            if abs(a.body.position.x - b.body.position.x) < required_overlap:
                if a.body.position.y > b.body.position.y:
                    record_shape_below(a, b)
                # otherwise b is above a
                else:
                    record_shape_below(b, a)

            # Allow sliding down walls (sorta, we still catch on 'corners')
            if round(contact.normal.x) == 1:
                body = arbiter.shapes[0].body
                bro = body.entity
                #body.velocity.x = contact.normal.x * Bro.SPEED

            return True

        def record_shape_below(above, below):
            bro = above.entity
            if type(bro) is Bro and not bro.frozen:
                # record this as an object under us
                bro.shapes_below.add(below)

                # check if we should record the last tile for this bro
                t = below.entity
                if type(t) is tile.Tile and t.static:
                    bro.last_tile = t

        # When first seperating
        def separate_handler(space, arbiter):
            # One less object below
            bro_shape = arbiter.shapes[0]
            bro = bro_shape.entity
            other_shape = arbiter.shapes[1]
            other = other_shape.entity

            # Remove object if it was below 
            if other_shape in bro.shapes_below:
                bro.shapes_below.remove(other_shape)

            return True

        # Handlers between bros and tiles
        outer_space.add_collision_handler(
                Bro.COLLISION_TYPE, 
                tile.Tile.COLLISION_TYPE,
                pre_solve = pre_solve_handler,
                separate = separate_handler
            )

        # Handlers between bros
        outer_space.add_collision_handler(
                Bro.COLLISION_TYPE, 
                Bro.COLLISION_TYPE, 
                pre_solve = pre_solve_handler,
                separate = separate_handler
            )
예제 #2
0
class Tile(entity.Entity):

    MASS = 20
    FRICTION = 0.5
    SIZE = 32

    WHITE_RATIO = 0.5

    BRIGHTNESS_MIN = 0.7
    BRIGHTNESS_RANGE = 1.0 - BRIGHTNESS_MIN

    DROP_IMPULSES = [(100, 0), (-100, 0)]

    DROP_OFFSET = (0, SIZE // 2)

    COLLISION_TYPE = 1

    def __init__(self, x, y, space, *args, **kwargs):
        self.space = space
        super(Tile, self).__init__(space,
                                   x=x * Tile.SIZE,
                                   y=y * Tile.SIZE,
                                   angle=0,
                                   width=Tile.SIZE,
                                   height=Tile.SIZE,
                                   friction=Tile.FRICTION,
                                   collision_type=Tile.COLLISION_TYPE,
                                   mass=Tile.MASS,
                                   static=True,
                                   texture=resources.box)

        # random colour
        if random.random() < Tile.WHITE_RATIO:
            brightness = random.random(
            ) % Tile.BRIGHTNESS_RANGE + Tile.BRIGHTNESS_MIN
            self.rgb = brightness, brightness, brightness

        self.orig_color = self.rgb
        self.tints = WeakSet()

    def drop(self):
        self.static = False
        self.untint_all()
        self.pymunk_body.apply_impulse(random.choice(Tile.DROP_IMPULSES),
                                       Tile.DROP_OFFSET)

    def set_last_tile_for(self, bro):
        self.tint(bro.color)

    def unset_last_tile_for(self, bro):
        self.untint(bro.color)

    def tint(self, color):
        self.tints.add(color)
        self._color()

    def untint(self, color):
        if color in self.tints:
            self.tints.remove(color)
        self._color()

    def untint_all(self):
        for tint in self.tints:
            self.tints.remove(tint)
        self._color()

    def _color(self):
        # start with orig colour
        self.red = self.orig_color[0]
        self.green = self.orig_color[1]
        self.blue = self.orig_color[2]
        # overlay each tint
        for tint in self.tints:
            t = tint.fade(Tile.BRIGHTNESS_RANGE).invert()
            self.red -= t.red
            self.green -= t.green
            self.blue -= t.blue
예제 #3
0
class Tile(entity.Entity):

    MASS = 20
    FRICTION = 0.5
    SIZE = 32

    WHITE_RATIO = 0.5

    BRIGHTNESS_MIN = 0.7
    BRIGHTNESS_RANGE = 1.0 - BRIGHTNESS_MIN

    DROP_IMPULSES = [(100, 0), (-100, 0)]

    DROP_OFFSET = (0, SIZE // 2)

    COLLISION_TYPE = 1

    def __init__(self, x, y, space, *args, **kwargs):
        self.space = space
        super(Tile, self).__init__(
            space,
            x=x * Tile.SIZE,
            y=y * Tile.SIZE,
            angle=0,
            width=Tile.SIZE,
            height=Tile.SIZE,
            friction=Tile.FRICTION,
            collision_type=Tile.COLLISION_TYPE,
            mass=Tile.MASS,
            static=True,
            texture=resources.box,
        )

        # random colour
        if random.random() < Tile.WHITE_RATIO:
            brightness = random.random() % Tile.BRIGHTNESS_RANGE + Tile.BRIGHTNESS_MIN
            self.rgb = brightness, brightness, brightness

        self.orig_color = self.rgb
        self.tints = WeakSet()

    def drop(self):
        self.static = False
        self.untint_all()
        self.pymunk_body.apply_impulse(random.choice(Tile.DROP_IMPULSES), Tile.DROP_OFFSET)

    def set_last_tile_for(self, bro):
        self.tint(bro.color)

    def unset_last_tile_for(self, bro):
        self.untint(bro.color)

    def tint(self, color):
        self.tints.add(color)
        self._color()

    def untint(self, color):
        if color in self.tints:
            self.tints.remove(color)
        self._color()

    def untint_all(self):
        for tint in self.tints:
            self.tints.remove(tint)
        self._color()

    def _color(self):
        # start with orig colour
        self.red = self.orig_color[0]
        self.green = self.orig_color[1]
        self.blue = self.orig_color[2]
        # overlay each tint
        for tint in self.tints:
            t = tint.fade(Tile.BRIGHTNESS_RANGE).invert()
            self.red -= t.red
            self.green -= t.green
            self.blue -= t.blue