Пример #1
0
class Ghost:
    def __init__(self, sprites, start_tile, exit_spawn_path, square_size, map,
                 player_rect, move_time, move_speed, choose_target_tile,
                 start_at_power_points):
        self.sprites = sprites
        self.start_tile = start_tile
        self.exit_spawn_path = exit_spawn_path
        self.square_size = square_size
        self.map = map
        self.move_time = move_time
        self.reset_move_speed = self.move_speed = move_speed

        self.state = "normal"  # the other state is "chased"
        self.chassed_sprite_kind = "chased"

        self.move_anim = Anim(self.sprites["right"], speed=0.12)

        self.start_at_power_points = start_at_power_points  # will start if less than X power points are eaten

        self.move_timer = 0

        self.chased_change_color_timer = 0

        self.pos = [
            self.start_tile[0] * self.square_size,
            self.start_tile[1] * self.square_size
        ]
        self.rect = pygame.Rect(self.pos[0], self.pos[1], self.square_size,
                                self.square_size)
        level_nb = 1
        self.timer = Timer(level_nb)

        # "Scatter" # Scatter -> fixed tile to reach (outside screen) | Chase -> attack pac man | Frightened -> random
        self.mode = self.timer.phases[self.timer.current_phase_index][0]

        self.move_direction = "left"

        self.moving_to = (
            8, 7
        )  # the first move after the ghost left the spawn (going to the left tile)

        self.choose_target_tile = choose_target_tile

        self.direction_conversion = {
            "right": (1, 0),
            "left": (-1, 0),
            "down": (0, 1),
            "up": (0, -1)
        }

    # def shortest_path_to(self, target_tile):
    #     return target_tile

    def move(self, player_current_tile, surface, power_points_infos):
        if self.start_at_power_points <= power_points_infos["total"] - len(
                power_points_infos["current"]) and time.time(
                ) > self.move_timer:

            self.player_current_tile = player_current_tile

            self.move_timer = time.time() + self.move_time

            if len(self.exit_spawn_path) != 0:
                move_direction = self.exit_spawn_path[0][0]
                moving_to = self.exit_spawn_path[0][1]

            else:  # if the ghost is outside the spawn cage
                move_direction = self.move_direction
                moving_to = self.moving_to

            if move_direction == "left":
                self.pos[0] -= self.move_speed
                self.rect.x = self.pos[0]
                if self.pos[0] / self.square_size < moving_to[
                        0]:  # if exceed the target tile
                    self.pos[0] = moving_to[0] * self.square_size
                    self.rect.x = self.pos[0]

                    if self.rect.right <= 0:  # if outside the screen
                        self.rect.x = surface.get_width()
                        self.pos[0] = self.rect.x
                        self.moving_to = (
                            surface.get_width() // self.square_size - 1,
                            moving_to[1])
                    else:
                        if len(self.exit_spawn_path) != 0:
                            self.exit_spawn_path.pop(0)
                        else:
                            self.moving_to = self.choose_next_tile()

            elif move_direction == "right":
                self.pos[0] += self.move_speed
                self.rect.x = self.pos[0]

                if self.pos[0] / self.square_size > moving_to[
                        0]:  # if exceed the target tile
                    self.pos[0] = moving_to[0] * self.square_size
                    self.rect.x = self.pos[0]

                    if self.rect.left >= surface.get_width():
                        self.rect.right = 0
                        self.pos[0] = self.rect.x
                        self.moving_to = (0, moving_to[1])

                    else:
                        if len(self.exit_spawn_path) != 0:
                            self.exit_spawn_path.pop(0)
                        else:
                            self.moving_to = self.choose_next_tile()

            elif move_direction == "up":
                self.pos[1] -= self.move_speed
                self.rect.y = self.pos[1]

                if self.pos[1] / self.square_size < moving_to[
                        1]:  # if exceed the target tile
                    self.pos[1] = moving_to[1] * self.square_size
                    self.rect.y = self.pos[1]
                    if len(self.exit_spawn_path) != 0:
                        self.exit_spawn_path.pop(0)
                    else:
                        self.moving_to = self.choose_next_tile()

            elif move_direction == "down":
                self.pos[1] += self.move_speed
                self.rect.y = self.pos[1]

                if self.pos[1] / self.square_size > moving_to[
                        1]:  # if exceed the target tile
                    self.pos[1] = moving_to[1] * self.square_size
                    self.rect.y = self.pos[1]
                    if len(self.exit_spawn_path) != 0:
                        self.exit_spawn_path.pop(0)
                    else:
                        self.moving_to = self.choose_next_tile()

    def possible_next_tile_algo(self):
        adjacency_tiles = {}
        if self.move_direction != "up":
            adjacency_tiles["down"] = self.map[self.moving_to[1] +
                                               1][self.moving_to[0]]
        if self.move_direction != "down":
            adjacency_tiles["up"] = self.map[self.moving_to[1] -
                                             1][self.moving_to[0]]
        if self.move_direction != "left":
            adjacency_tiles["right"] = self.map[self.moving_to[1]][
                self.moving_to[0] + 1]
        if self.move_direction != "right":
            adjacency_tiles["left"] = self.map[self.moving_to[1]][
                self.moving_to[0] - 1]

        while True:
            for direction, tile in adjacency_tiles.items():

                if tile == "#" or tile == "b":
                    del adjacency_tiles[direction]
                    break
            else:
                break

        return list(adjacency_tiles.keys())

    def choose_next_tile(self):
        # update the timer
        self.timer.update()
        if self.timer.timer > self.timer.phases[
                self.timer.current_phase_index][1]:
            self.timer.start_time = time.time()
            self.timer.current_phase_index += 1
            self.mode = self.timer.phases[self.timer.current_phase_index][0]

        target_tile, possibles_next_direction = self.choose_target_tile()

        if len(possibles_next_direction) == 1:
            next_direction = possibles_next_direction[0]
        # shortest path (in a straight line) to the target tile
        else:
            shortest_line = float("+inf")
            current_chosen_direction = None
            for direction in possibles_next_direction:
                conv = self.direction_conversion[direction]
                tile = (self.moving_to[0] + conv[0],
                        self.moving_to[1] + conv[1])
                # lenght from this tile to the target tile
                line_lenght = math.sqrt(
                    abs(tile[0] - target_tile[0])**2 +
                    abs(tile[1] - target_tile[1])**2)
                if line_lenght < shortest_line:
                    shortest_line = line_lenght
                    current_chosen_direction = direction

            next_direction = current_chosen_direction

        if next_direction == "right":
            next_tile = [self.moving_to[0] + 1, self.moving_to[1]]
        elif next_direction == "left":
            next_tile = [self.moving_to[0] - 1, self.moving_to[1]]
        elif next_direction == "down":
            next_tile = [self.moving_to[0], self.moving_to[1] + 1]
        elif next_direction == "up":
            next_tile = [self.moving_to[0], self.moving_to[1] - 1]

        self.move_direction = next_direction

        return next_tile

    def draw(self, surface):
        # if self.state == "chased":

        self.move_anim.do()
        if self.state == "chased":
            if self.chased_start_time + 10 > time.time():
                if self.chased_start_time + 7 < time.time(
                ) and self.chased_change_color_timer < time.time():
                    self.chased_change_color_timer = time.time() + 0.3
                    if self.chassed_sprite_kind == "chased":
                        self.chassed_sprite_kind = "chased_white"
                    else:
                        self.chassed_sprite_kind = "chased"
            else:
                self.chassed_sprite_kind = "chased"
                self.state = "normal"

            sprite = self.sprites[self.chassed_sprite_kind][
                self.move_anim.s_index]
        else:  # draw the normal sprite
            self.move_speed = self.reset_move_speed
            sprite = self.sprites[self.move_direction][self.move_anim.s_index]
        # pygame.draw.rect(surface, sprite, self.rect)
        surface.blit(
            sprite, (self.rect.x +
                     (self.square_size - sprite.get_width()) / 2, self.rect.y +
                     (self.square_size - sprite.get_height()) / 2 + 1.5))

    def collide(self, surface, player):

        if self.rect.colliderect(player.rect):
            if self.state == "chased":
                # self.pos = [self.start_tile[0] * self.square_size, self.start_tile[1] * self.square_size]

                self.pos[0] = 9 * self.square_size
                self.pos[1] = 9 * self.square_size
                self.rect = pygame.Rect(self.pos[0], self.pos[1],
                                        self.square_size, self.square_size)
                self.exit_spawn_path = [("up", (9, 8)), ("up", (9, 7))]
                player.score += 200
                self.moving_to = (8, 7)
                self.move_direction = "left"
                self.state = "normal"
                print("pac man eat ghost")
            else:
                player.killed = True
                print("ghost eat pac man")
Пример #2
0
class Player:
    def __init__(self, square_size, obstacles, sprites):
        self.square_size = square_size
        self.obstacles = obstacles
        self.sprites = sprites
        self.move_anim = Anim(sprites["moving"]["right"], speed=0.12)
        self.death_anim = Anim(sprites["death"], speed=0.1)
        self.font = pygame.font.SysFont("coopbl", 55)

        self.timer = {"move": 0}

        self.move_time = 0.02

        self.portals = {1: None, 2: None, "space_pressed": False}

        # initial amount of lives
        self.lives = 3

        # the player will move 2 pixel every move_time sec
        self.reset_move_speed = self.move_speed = 3

        self.color = (211, 144, 11)

        self.direction = {"current": "left",
                          "next": None,
                          "previous": None,
                          "right": (1, 0),
                          "left": (-1, 0),
                          "down": (0, 1),
                          "up": (0, -1)}

        self.killed = False
        self.make_death_anim = False
        self.make_ghost_respawn = False
        self.start_pos = [self.square_size * 9, self.square_size * 11]
        self.rect = pygame.Rect(self.start_pos[0],
                                self.start_pos[1],
                                self.square_size,
                                self.square_size)

        self.define_current_tile()

        self.score = 0

    def define_current_tile(self):
        current_tile_x = int(self.rect.centerx / self.square_size)
        current_tile_y = int(self.rect.centery / self.square_size)
        self.current_tile = [current_tile_x, current_tile_y]

    def user_input(self):
        keys_pressed = pygame.key.get_pressed()
        if ((keys_pressed[pygame.K_LEFT] or keys_pressed[pygame.K_a]) and not (
                keys_pressed[pygame.K_RIGHT] or keys_pressed[pygame.K_d])):
            self.direction["next"] = "left"

        if ((keys_pressed[pygame.K_RIGHT] or keys_pressed[pygame.K_d]) and not (
                keys_pressed[pygame.K_LEFT] or keys_pressed[pygame.K_a])):
            self.direction["next"] = "right"

        if ((keys_pressed[pygame.K_DOWN] or keys_pressed[pygame.K_s]) and not (
                keys_pressed[pygame.K_UP] or keys_pressed[pygame.K_w])):
            self.direction["next"] = "down"

        if ((keys_pressed[pygame.K_UP] or keys_pressed[pygame.K_w]) and not (
                keys_pressed[pygame.K_DOWN] or keys_pressed[pygame.K_s])):
            self.direction["next"] = "up"

    def change_direction(self, surface):
        if self.direction["next"] is not None:
            next_rect = self.rect.copy()

            next_rect.x += self.move_speed * self.direction[self.direction["next"]][0]

            next_rect.y += self.move_speed * self.direction[self.direction["next"]][1]

            if next_rect.right > 0 and next_rect.left < surface.get_width():

                if next_rect.collidelist(self.obstacles) == -1:
                    self.direction["current"] = self.direction["next"]
                    self.direction["previous"] = self.direction["current"]
                    self.direction["next"] = None

    def move(self, surface):
        self.user_input()

        if time.time() > self.timer["move"]:
            self.timer["move"] = time.time() + self.move_time
            self.define_current_tile()

            self.change_direction(surface)

            if self.direction["current"] is not None:

                self.rect.x += self.move_speed * self.direction[self.direction["current"]][0]
                self.rect.y += self.move_speed * self.direction[self.direction["current"]][1]

                # if the player is outside the screen at the right
                if self.rect.x > surface.get_width():
                    self.rect.x = 0 - self.square_size

                # if the player is outside the screen at the left
                if self.rect.x < 0 - self.square_size:
                    self.rect.x = surface.get_width()

                if self.current_tile == self.portals[2]:
                    self.current_tile = self.portals[1]
                    self.rect.x = self.portals[1][0] * self.square_size
                    self.rect.y = self.portals[1][1] * self.square_size

                # if the player HAS collide with an obstacle
                collide_index = self.rect.collidelist(self.obstacles)
                if collide_index != -1:

                    if self.direction["current"] == "up":
                        self.rect.y = self.obstacles[collide_index].bottom

                    elif self.direction["current"] == "down":
                        self.rect.y = self.obstacles[collide_index].top - self.square_size

                    elif self.direction["current"] == "right":
                        self.rect.x = self.obstacles[collide_index].left - self.square_size

                    elif self.direction["current"] == "left":
                        self.rect.x = self.obstacles[collide_index].right

                    self.direction["previous"] = self.direction["current"]
                    self.direction["current"] = None

    def draw_score(self, surface):
        label = self.font.render(f"Score : {self.score}", 1, (222, 222, 222))
        x_pos = surface.get_width() - label.get_width() - self.square_size
        y_pos = self.square_size // 2 - label.get_height() // 2
        surface.blit(label, (x_pos, y_pos))

    def draw_lives(self, surface):
        label = self.font.render(f"Lives : {self.lives}", 1, (222, 222, 222))
        x_pos = surface.get_width() // 2 - label.get_width() // 2
        y_pos = surface.get_height() - label.get_height() - 4
        surface.blit(label, (x_pos, y_pos))

    def draw(self, surface):
        self.draw_score(surface)
        self.draw_lives(surface)
        self.draw_portals(surface)

        if not self.make_death_anim:
            self.move_anim.do()
            if self.direction["current"] is None:
                self.move_anim.s_index = 0
                direction = "right"
            else:
                direction = self.direction["current"]
            sprite = self.sprites["moving"][direction][self.move_anim.s_index]
            pos_x = self.rect.x + (self.square_size - sprite.get_width()) / 2
            pos_y = (self.rect.y +
                     (self.square_size - sprite.get_height()) / 2 + 1)
            surface.blit(sprite, (pos_x, pos_y))

        # death anim
        if self.make_death_anim:
            self.move_speed = 0
            sprite = self.death_anim.current_sprite
            pos_x = self.rect.x + (self.square_size - sprite.get_width()) / 2
            pos_y = (self.rect.y +
                     (self.square_size - sprite.get_height()) / 2 + 1)
            surface.blit(sprite, (pos_x, pos_y))

            if self.death_anim.do() == "end":
                # reset
                self.make_death_anim = False
                self.make_ghost_respawn = True
                self.reset_pos()

    def reset_pos(self):
        self.rect.x = self.start_pos[0]
        self.rect.y = self.start_pos[1]
        self.move_speed = self.reset_move_speed
        self.direction["current"] = "left"
        self.portals = {1: None, 2: None, "space_pressed": False}

    # Tests if the player is killed or not
    def test_kill(self):
        if self.killed is True:
            self.killed = False
            self.lives -= 1
            self.death_anim.s_index = 0
            self.make_death_anim = True
            self.portals = {1: None, 2: None, "space_pressed": False}
            return True

    def create_portals(self):
        keys_pressed = pygame.key.get_pressed()
        if keys_pressed[pygame.K_SPACE]:
            if not self.portals["space_pressed"]:
                self.portals["space_pressed"] = True
                tile = self.current_tile.copy()
                if self.portals[1] == None:
                    self.portals[1] = tile
                elif self.portals[2] == None:
                    self.portals[2] = tile
        else:
            self.portals["space_pressed"] = False

    def draw_portals(self, surface):
        if self.portals[1] != None:
            surface.blit(self.sprites["portals"]["blue"],
                         (self.portals[1][0] * self.square_size, self.portals[1][1] * self.square_size ))
        if self.portals[2] != None:
            surface.blit(self.sprites["portals"]["orange"],
                         (self.portals[2][0] * self.square_size, self.portals[2][1] * self.square_size ))