Exemplo n.º 1
0
class Ball(Entity):
    def __init__(self):
        self.x = BALL_X
        self.y = BALL_Y
        self.width = BALL_SIZE
        self.height = BALL_SIZE
        self.color = RED
        self.velocity = Velocity()

    def move(self):
        self.x += self.velocity.x
        self.y += self.velocity.y

    def update(self, launch, player, blocks, walls):
        if launch and not self.velocity.is_moving():
            self.velocity.x = BALL_SPEED * math.pow(-1, random.randint(1, 3))
            self.velocity.y = -BALL_SPEED

        if not self.velocity.is_moving():
            self.x = player.x + player.width / 2 - self.width / 2
            self.y = player.y - player.height
        else:
            self.move()

        return self._handle_collisions(player, blocks, walls)

    def _handle_collisions(self, player, blocks, walls):
        results = {}

        self._handle_wall_collisions(walls)
        self._handle_player_collisions(player)
        results.update(self._handle_block_collisions(blocks))
        results.update(self._handle_loss_collisions())

        return results

    def _handle_player_collisions(self, player):
        if is_collision(self.get_bounding_box(), player.get_bounding_box()):
            self.y = player.y - self.height

            player_middle = player.x + player.width / 2
            ball_middle = self.x + self.width / 2

            relative_intersect_x = player_middle - ball_middle
            normalized_relative_intersect_x = relative_intersect_x / (player.width / 2)
            bounce_angle = normalized_relative_intersect_x * (
                math.pi / 2 - MAX_BOUNCE_ANGLE
            )

            self.velocity.x = BALL_SPEED * -math.sin(bounce_angle)
            self.velocity.y = BALL_SPEED * -math.cos(bounce_angle)

    def _handle_wall_collisions(self, walls):
        left_wall = walls[0]
        right_wall = walls[1]
        top_wall = walls[2]

        if self.x < left_wall.width:
            self.x = left_wall.width
            self.velocity.reverse_x()
        if self.x + self.width > right_wall.x:
            self.x = right_wall.x - self.width
            self.velocity.reverse_x()
        if self.y < top_wall.y + top_wall.height:
            self.y = top_wall.y + top_wall.height
            self.velocity.reverse_y()

    def _handle_block_collisions(self, blocks):
        left_x = self.x
        left_y = self.y + self.height / 2
        right_x = self.x + self.width
        right_y = self.y + self.height / 2
        top_x = self.x + self.width / 2
        top_y = self.y
        bottom_x = self.x + self.width / 2
        bottom_y = self.y + self.height

        for block in blocks:
            if is_side_collision(left_x, left_y, block.get_bounding_box()):
                self.y += self.height
                self.velocity.reverse_x()
                blocks.remove(block)
                return {"points": block.value}
            elif is_side_collision(right_x, right_y, block.get_bounding_box()):
                self.y -= self.height
                self.velocity.reverse_x()
                blocks.remove(block)
                return {"points": block.value}
            elif is_side_collision(top_x, top_y, block.get_bounding_box()):
                self.y += self.height
                self.velocity.reverse_y()
                blocks.remove(block)
                return {"points": block.value}
            elif is_side_collision(bottom_x, bottom_y, block.get_bounding_box()):
                self.y -= self.height
                self.velocity.reverse_y()
                blocks.remove(block)
                return {"points": block.value}
        return {"points": 0}

    def _handle_loss_collisions(self):
        bottom_y = self.y + self.height

        if bottom_y > WINDOW_HEIGHT:
            return {"loss": True}
        else:
            return {"loss": False}