def detect_all_collisions(player):
        # 1. Fetch all possiple collisions
        all_collisions = {
            'FLOOR': [],
            'CEILING': [],
            'LEFT_WALL': [],
            'RIGHT_WALL': [],
        }
        for barrier in Barrier.instances:
            all_collisions = merge_into_list_dict(
                all_collisions,
                get_collision(barrier=barrier, moving_object=player))

        # 2. Reduce all collisions to the relevant ones, example:
        #    all_collisions['FLOOR'] = [3.0, 4.2, 2.2, 4.0]
        #    -> relevant_collisions['FLOOR'] = 4.2
        return reduce_to_relevant_collisions(all_collisions)
示例#2
0
    def detect_all_collisions(moving_player):
        # 1. Fetch all possiple collisions
        all_collisions = {
            'FLOOR': [],
            'OBJECTS_ON_TOP': [],
            'OBJECTS_BELOW': [],
            'LEFT_WALL': [],
            'RIGHT_WALL': [],
        }

        for player in Player.instances:
            if player != moving_player:
                collision = get_collision(barrier=player,
                                          moving_object=moving_player,
                                          stacked_collision=True)
                all_collisions = merge_into_list_dict(all_collisions,
                                                      collision)

        # 2. Reduce all collisions to the relevant ones, example:
        #    all_collisions['FLOOR'] = [3.0, 4.2, 2.2, 4.0]
        #    -> relevant_collisions['FLOOR'] = 4.2
        return reduce_to_relevant_collisions(all_collisions)
示例#3
0
    def update_for_collisions(self, new_velocity, new_position, timedelta):

        # 1. Detect combat collisions with enemies. "MOVING_OBJECT"
        #    refers to the player. "BARRIER" refers to the enemy.
        combat_collisions = Enemy.detect_all_collisions(self)
        for enemy in combat_collisions['BARRIER_KILLED']:
            enemy.kill()
            self.enemies_killed += 1
        if len(combat_collisions['MOVING_OBJECT_KILLED']) > 0:
            self.kill()
            return

        # 2. Detecting movement collisions with Barriers and other
        #    players. Collisions should refer to the new velocity
        #    and new position that is why we preliminarily update
        #    the players state (self.)
        self.velocity, self.position = new_velocity, new_position
        movement_collisions = reduce_to_relevant_collisions(
            merge_into_list_dict(Barrier.detect_all_collisions(self),
                                 Player.detect_all_collisions(self)))

        # The strategy now is to go through all the collisions that
        # were detected and successively adjust new_velocity and
        # new_position if needed. In the end the players state (self.
        # will be updated with the adjusted position/velocity once
        # again

        new_collisions = {
            'CEILING': None,
            'FLOOR': None,
            'LEFT_WALL': None,
            'RIGHT_WALL': None,
            'OBJECTS_ON_TOP': movement_collisions['OBJECTS_ON_TOP'],
        }

        # "Snap" to Wall/Floor/Ceiling when hitting one. Example
        #   Moving left & new_x = -0.04
        #   Wall detected at x=0
        #   Snaps to x=0 and velocity *= -1 (turns around)
        def snap_to_barrier(side):
            dimension = 1 if (side in ('FLOOR', 'CEILING')) else 0
            coordinate_direction = +1 if (side in ('FLOOR',
                                                   'LEFT_WALL')) else -1
            new_velocity[dimension] = 0
            limit_center_offset = ((self.size[dimension] / 2) -
                                   ERROR_MARGIN) * coordinate_direction
            new_position[
                dimension] = movement_collisions[side] + limit_center_offset
            new_collisions[side] = movement_collisions[side]

        # 3. React to vertical collisions
        if movement_collisions['CEILING'] is not None:
            if new_velocity[1] > -ERROR_MARGIN:
                snap_to_barrier('CEILING')

            # Edge case for two players standing on top of each other with
            # the bottom player jumping up and only the top player hitting
            # a ceiling. This snippet is needed so that the upper player is
            # not being "forced into the wall" and the bottom player detects
            # the ceiling indirectly
            for _object in movement_collisions['OBJECTS_BELOW']:
                _object.velocity[1] = 0
                limit_center_offset = (_object.size[1]) + (
                    self.size[1] / 2) + 2 * ERROR_MARGIN
                _object.position[
                    1] = movement_collisions['CEILING'] - limit_center_offset
        elif movement_collisions[
                'FLOOR'] is not None and new_velocity[1] < +ERROR_MARGIN:
            snap_to_barrier('FLOOR')

        # 4. React to horizontal collisions. Left and Right wall block
        # is only applied if the player is moving towards that barrier
        if movement_collisions[
                'LEFT_WALL'] is not None and new_velocity[0] < ERROR_MARGIN:
            snap_to_barrier('LEFT_WALL')
        elif movement_collisions[
                'RIGHT_WALL'] is not None and new_velocity[0] > -ERROR_MARGIN:
            snap_to_barrier('RIGHT_WALL')

        # 5. When standing on top of another player and that player moves
        #    then the player on top should also be moved by that players
        #    movement = the player on top will be carried around (as long
        # as he doe not hit a wall
        if len(movement_collisions['OBJECTS_BELOW']) > 0:
            _object = movement_collisions['OBJECTS_BELOW'][0]
            if (_object.velocity[0] < 0 and new_collisions['LEFT_WALL'] is None
                    or _object.velocity[0] > 0
                    and new_collisions['RIGHT_WALL'] is None):
                new_position[0] += _object.velocity[0] * timedelta

        # 6. Now new_velocity and new_position has been adjusted to conform
        #    with collisions -> player state will be updated with the adjusted
        #    values
        self.collisions = new_collisions
        self.velocity = [round(v, COORDINATE_PRECISION) for v in new_velocity]
        self.position = [round(p, COORDINATE_PRECISION) for p in new_position]
    def update_for_collisions(self, new_velocity, new_position, timedelta):

        # 1. Detecting movement collisions with Barriers and other
        #    players. Collisions should refer to the new velocity
        #    and new position that is why we preliminarily update
        #    the players state (self.)
        self.velocity, self.position = new_velocity, new_position
        movement_collisions = reduce_to_relevant_collisions(
            Barrier.detect_all_collisions(self))

        # The strategy now is to go through all the collisions that
        # were detected and successively adjust new_velocity and
        # new_position if needed. In the end the players state (self.
        # will be updated with the adjusted position/velocity once
        # again

        new_collisions = {
            'CEILING': None,
            'FLOOR': None,
            'LEFT_WALL': None,
            'RIGHT_WALL': None
        }

        # "Snap" to Wall/Floor/Ceiling when hitting one. Example
        #   Moving left & new_x = -0.04
        #   Wall detected at x=0
        #   Snaps to x=0 and velocity *= -1 (turns around)
        def snap_to_barrier(side):
            dimension = 1 if (side in ('FLOOR', 'CEILING')) else 0
            coordinate_direction = +1 if (side in ('FLOOR',
                                                   'LEFT_WALL')) else -1
            new_velocity[dimension] = 0
            limit_center_offset = ((self.size[dimension] / 2) -
                                   ERROR_MARGIN) * coordinate_direction
            new_position[
                dimension] = movement_collisions[side] + limit_center_offset
            new_collisions[side] = movement_collisions[side]

        # 2. React to vertical collisions
        if movement_collisions['CEILING'] is not None:
            if new_velocity[1] > -ERROR_MARGIN:
                snap_to_barrier('CEILING')
        elif movement_collisions[
                'FLOOR'] is not None and new_velocity[1] < +ERROR_MARGIN:
            snap_to_barrier('FLOOR')

        # 3. React to horizontal collisions. Left and Right wall block
        # is only applied if the player is moving towards that barrier
        if movement_collisions[
                'LEFT_WALL'] is not None and new_velocity[0] < ERROR_MARGIN:
            snap_to_barrier('LEFT_WALL')
        elif movement_collisions[
                'RIGHT_WALL'] is not None and new_velocity[0] > -ERROR_MARGIN:
            snap_to_barrier('RIGHT_WALL')

        # 4. Now new_velocity and new_position has been adjusted to conform
        #    with collisions -> player state will be updated with the adjusted
        #    values
        self.collisions = new_collisions
        self.velocity = [round(v, COORDINATE_PRECISION) for v in new_velocity]
        self.position = [round(p, COORDINATE_PRECISION) for p in new_position]