Ejemplo n.º 1
0
 def applied_on_entity(self, entity):
     self.entity = entity
     entity.event_manager.bind(UpdateEvent, self.update)
     entity.event_manager.bind(HoverEvent, self.hover_event)
     entity.event_manager.bind(ClickEvent, self.click_event)
     if self.text is not None:
         trans = entity.get_component(TransformComponent)
         size = entity.get_component(RendererComponent).size
         self.label = Entity()
         entity.scene.add_entity(self.label)
         self.label_text = TextRenderer(self.text, 20, Colors.white)
         self.label.add_component(
             PyGameRendererComponent(self.label_text, (100, 100)))
         ls = self.label_text.render(entity, None).get_size()
         self.label.add_component(
             TransformComponent(
                 Vector2(trans.x + size[0] / 2 - ls[0] / 2,
                         trans.y + size[1] / 2 - ls[1] / 2)))
Ejemplo n.º 2
0
 def add_grain(self, rect, size, big=False):
     grain = Entity()
     self.add_entity(grain)
     grain.add_component(
         TransformComponent(
             Vector2(rect.x + rect.w / 2 - size / 2,
                     rect.y + rect.h / 2 - size / 2)))
     grain.add_component(
         RendererComponent(ImageRenderer("./assets/images/small_grain.png"),
                           (size, size)))
     grain.add_component(NameComponent('grain' + ('big' if big else '')))
Ejemplo n.º 3
0
    def create_objects(self):
        self.field_obj = Field(self.game, 32)
        self.ghost_obj = GhostMove(self.game, self.field_obj)

        field = Entity()
        self.add_entity(field)
        shader = Shader.init_from_files("assets/shaders/walls/walls.vert",
                                        "assets/shaders/walls/walls.frag")
        field.add_component(TransformComponent(Vector2(0, 0)))
        field.add_component(
            PyGameRendererComponent(ObjectRenderer(self.field_obj),
                                    self.game.screen_size, True, shader))
Ejemplo n.º 4
0
    def __init__(self, game):
        super().__init__(game)
        self.objects = []
        self.create_objects()
        self.rederer = SceneRenderer()

        rend_entity = Entity()
        self.add_entity(rend_entity)
        rend_entity.add_component(TransformComponent(Vector2(0, 0)))
        rend_entity.add_component(PyGameRendererComponent(self.rederer, game.screen_size))

        self.add_entities()
Ejemplo n.º 5
0
    def start():
        pygame.init()
        size = width, height = (640, 480)
        game = Game()
        game.setup_default_components(size)
        scene = game.scene

        background = Entity()
        scene.add_entity(background)
        background.add_component(TransformComponent(Vector2(0, 0)))
        background.add_component(
            RendererComponent(RectRenderer(Colors.from_hex("#4C5B5C")), size))

        menu_label = Entity()
        scene.add_entity(menu_label)
        menu_label.add_component(
            TransformComponent(Vector2(width / 2 - 120, 40)))
        menu_label.add_component(
            PyGameRendererComponent(
                TextRenderer("Simple Menu", 40, Colors.white), (100, 100)))

        click_label = Entity()
        scene.add_entity(click_label)
        click_label.add_component(
            TransformComponent(Vector2(width / 2 - 60, 90)))
        click_label_text = TextRenderer("Click count: 0", 20, Colors.white)
        click_label.add_component(
            PyGameRendererComponent(click_label_text, (100, 100)))

        play_button = Entity()
        scene.add_entity(play_button)
        play_button.add_component(
            TransformComponent(Vector2(width / 2 - 100, 150)))
        shader = Shader.init_from_files("assets/button_shader.vert",
                                        "assets/button_shader.frag")
        play_button.add_component(
            RendererComponent(RectRenderer(Colors.from_hex("#4F6D7A")),
                              (200, 50), shader))
        play_button.add_component(BoxCollider((200, 50)))
        play_button.add_component(MouseColliderComponent())
        play_button.add_component(
            ButtonComponent(shader,
                            text="Play",
                            hover_color=Colors.from_hex("#3891A6"),
                            click_color=Colors.from_hex("#FDE74C")))

        exit_button = Entity()
        scene.add_entity(exit_button)
        exit_button.add_component(
            TransformComponent(Vector2(width / 2 - 100, 250)))
        shader1 = Shader.init_from_files("assets/button_shader.vert",
                                         "assets/button_shader.frag")
        exit_button.add_component(
            RendererComponent(RectRenderer(Colors.from_hex("#9E3A35")),
                              (200, 50), shader1))
        exit_button.add_component(BoxCollider((200, 50)))
        exit_button.add_component(MouseColliderComponent())
        exit_button.add_component(
            ButtonComponent(shader1,
                            text="Exit",
                            hover_color=Colors.from_hex("#C24741"),
                            click_color=Colors.from_hex("#FDE74C")))

        def press(event):
            if event.entity == play_button:
                click_label_text.text = "Click count: {}".format(
                    int(click_label_text.text.split(": ")[1]) + 1)
            elif event.entity == exit_button:
                game.exit()

        exit_button.event_manager.bind(ButtonPressEvent, press)

        game.add_component(ExitOnEscape())

        game.run()
Ejemplo n.º 6
0
    def game_over(self):
        print("game over")
        self.entity.event_manager.trigger_event(
            PlaySoundEvent(Sounds.DEATH, 0, 20))

        scene = self.entity.scene

        black_back = Entity()
        scene.add_entity(black_back)
        black_back.add_component(TransformComponent(Vector2(0, 0)))
        shader = Shader.init_from_files("assets/shaders/back/back.vert",
                                        "assets/shaders/back/back.frag")
        shader.inject_rect = False
        shader.uniform_alpha = 1.0
        black_back.add_component(
            RendererComponent(RectRenderer(Colors.black),
                              self.entity.screen_size, shader))
        black_back.add_component(
            AnimationComponent(
                step=3,
                end=100,
                function=lambda x: shader.set_uniform("alpha", x / 100.0)))

        game_text = Entity()
        scene.add_entity(game_text)
        game_transform = TransformComponent(
            Vector2(0, self.entity.height / 2 - 65))
        game_text.add_component(game_transform)
        game_text.add_component(
            PyGameRendererComponent(
                TextRenderer("Game",
                             font_size=24,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))
        game_text.add_component(
            AnimationComponent(step=10,
                               end=self.entity.width / 2 - 220,
                               function=lambda x: game_transform.position.
                               update(x, game_transform.y)))

        over_text = Entity()
        scene.add_entity(over_text)
        over_transform = TransformComponent(
            Vector2(0, self.entity.height / 2 - 65))
        over_text.add_component(over_transform)
        over_text.add_component(
            PyGameRendererComponent(
                TextRenderer("Over",
                             font_size=24,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))
        over_text.add_component(
            AnimationComponent(step=-22,
                               start=self.entity.width,
                               end=self.entity.width / 2 - 110,
                               function=lambda x: over_transform.position.
                               update(x, game_transform.y)))

        self.entity.add_component(
            AnimationComponent(end=80, completion=self.go_to_menu))
Ejemplo n.º 7
0
class ButtonComponent(Component):
    def __init__(self,
                 shader,
                 text=None,
                 hover_color=Colors.blue,
                 click_color=Colors.green):
        self.entity = None
        self.hovering = False
        self.click = False
        self.state = ButtonState.Normal
        self.hover_color = hover_color
        self.click_color = click_color
        self.text = text
        self.click_position = (-1.0, -1.0)
        shader.uniform_click_pos = self.click_position
        shader.uniform_hover_color = hover_color.to_float()
        shader.uniform_click_color = click_color.to_float()
        shader.uniform_hover_progress = 0.0
        shader.uniform_click_progress = 0.0
        self.shader = shader
        self.label = None
        self.label_text = None

    def create_hover_animation(self, reverse=False):
        return AnimationComponent(step=-10 if reverse else 10,
                                  start=120 if reverse else 0,
                                  end=0 if reverse else 220,
                                  function=lambda x: self.shader.set_uniform(
                                      "hover_progress", x / 100.0))

    def create_click_animation(self, reverse=False):
        return AnimationComponent(step=-2 if reverse else 10,
                                  start=120 if reverse else 0,
                                  end=0 if reverse else 120,
                                  function=lambda x: self.shader.set_uniform(
                                      "click_progress", x / 100.0))

    def start_animation(self, anim):
        if self.entity.contains_component(AnimationComponent):
            self.entity.remove_component(AnimationComponent)

        self.entity.add_component(anim)

    def update(self, event):
        if self.hovering and self.state == ButtonState.Normal:
            self.start_animation(self.create_hover_animation(False))
            self.state = ButtonState.Hovered
        elif not self.hovering and self.state == ButtonState.Hovered:
            self.start_animation(self.create_hover_animation(True))
            self.state = ButtonState.Normal
        elif not self.hovering and self.state == ButtonState.Clicked:
            self.shader.uniform_click_pos = (-1.0, -1.0)
            self.shader.uniform_hover_progress = 0.0
            self.state = ButtonState.Normal
        elif self.click and not self.entity.contains_component(
                AnimationComponent):
            height = self.entity.scene.game.screen_size[1]
            self.shader.uniform_click_pos = (self.click_position[0],
                                             height - self.click_position[1])
            self.start_animation(self.create_click_animation(False))
            self.state = ButtonState.Clicked
            self.entity.event_manager.trigger_event(
                ButtonPressEvent(self.entity))

        self.hovering = False
        self.click = False

    def hover_event(self, event):
        if event.entity == self.entity:
            self.hovering = True

    def click_event(self, event):
        if event.entity == self.entity and event.buttons[0]:
            self.click = True
            self.click_position = tuple([float(i) for i in event.position])

    def applied_on_entity(self, entity):
        self.entity = entity
        entity.event_manager.bind(UpdateEvent, self.update)
        entity.event_manager.bind(HoverEvent, self.hover_event)
        entity.event_manager.bind(ClickEvent, self.click_event)
        if self.text is not None:
            trans = entity.get_component(TransformComponent)
            size = entity.get_component(RendererComponent).size
            self.label = Entity()
            entity.scene.add_entity(self.label)
            self.label_text = TextRenderer(self.text, 20, Colors.white)
            self.label.add_component(
                PyGameRendererComponent(self.label_text, (100, 100)))
            ls = self.label_text.render(entity, None).get_size()
            self.label.add_component(
                TransformComponent(
                    Vector2(trans.x + size[0] / 2 - ls[0] / 2,
                            trans.y + size[1] / 2 - ls[1] / 2)))
Ejemplo n.º 8
0
    def start():
        pygame.init()
        pygame.display.set_caption('PyDungeon')
        size = (640, 480)
        game = Game()
        game.setup_default_components(size)
        scene = game.scene

        tilemap = Entity()
        scene.add_entity(tilemap)
        tilemap.add_component(NameComponent("tilemap"))

        tilemap.add_component(TransformComponent(Vector2(0, 0)))

        ts = TileSet()
        ts.load("./assets/tileset.png", "./assets/tileinfo.info")
        tm = TileMap(ts, size)
        mp = [[["floor_" + str(random.randrange(1, 8))] for _ in range(24)]
              for _ in range(24)]
        PyDungeons.build_wall_rect(mp, pygame.Rect(2, 2, 10, 10))
        tm.load_letters(mp)
        tilemap.add_component(tm)
        tilemap.add_component(
            TileMapCollider(
                tm, ["wall_mid", "wall_side_mid_right", "wall_side_mid_left"]))
        tilemap.add_component(RendererComponent(TileMapRenderer(), size))

        player = Entity()
        scene.add_entity(player)
        player.add_component(NameComponent("player"))

        key_bindings = [[pygame.K_a], [pygame.K_d], [pygame.K_w], [pygame.K_s]]

        player.add_component(MoveComponent(1, 2))
        player.add_component(KeyControlComponent(key_bindings))
        player.add_component(TransformComponent(Vector2(100, 100)))
        player.add_component(BoxCollider((16 * 2, 22 * 2), Vector2(0, 12)))
        player.add_component(
            RendererComponent(TileRenderer(ts.tiles["knight_f_idle_anim"], ts),
                              (16 * 2, 28 * 2)))

        game.add_component(ExitOnEscape())

        game.run()
Ejemplo n.º 9
0
    def add_entities(self):
        grain_size = 8
        for g in self.field_obj.get_cells_by_type(Floor, Meta.grain_small):
            self.game_over.max_grains_count += 1
            self.add_grain(g.rect, grain_size)

        big_grain_size = 16
        for g in self.field_obj.get_cells_by_type(Floor, Meta.grain_big):
            self.game_over.max_grains_count += 1
            self.add_grain(g.rect, big_grain_size, True)

        player = Entity()

        ghost_pos = self.field_obj.get_cells_by_type(Floor, Meta.ghost_spawn)
        self.pinky = Entity()
        self.add_entity(self.pinky)
        self.pinky.add_component(
            TransformComponent(Vector2(*ghost_pos[0].rect.xy)))
        self.pinky.add_component(BoxCollider((32, 32)))
        self.pinky.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/pink.png"),
                              (32, 32)))
        self.pinky.add_component(
            GhostMoveComponent(self.field_obj, 2, self.pinky_find_target,
                               player, Colors.pink))
        self.pinky.add_component(ScaryModeComponent())

        red = Entity()
        self.add_entity(red)
        red.add_component(TransformComponent(Vector2(*ghost_pos[1].rect.xy)))
        red.add_component(BoxCollider((32, 32)))
        red.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/red.png"),
                              (32, 32)))
        red.add_component(
            GhostMoveComponent(self.field_obj, 2, self.red_find_target, player,
                               Colors.red))
        red.add_component(ScaryModeComponent())

        inky = Entity()
        self.add_entity(inky)
        inky.add_component(TransformComponent(Vector2(*ghost_pos[2].rect.xy)))
        inky.add_component(BoxCollider((32, 32)))
        inky.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/blue.png"),
                              (32, 32)))
        inky.add_component(
            GhostMoveComponent(self.field_obj, 2, self.inky_find_target,
                               player, Colors.purple))
        inky.add_component(ScaryModeComponent())

        clyde = Entity()
        self.add_entity(clyde)
        clyde.add_component(TransformComponent(Vector2(*ghost_pos[3].rect.xy)))
        clyde.add_component(BoxCollider((32, 32)))
        clyde.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/orange.png"),
                              (32, 32)))
        clyde.add_component(
            GhostMoveComponent(self.field_obj, 2, self.clyde_find_target,
                               player, Colors.orange))
        clyde.add_component(ScaryModeComponent())

        debug_line = Entity()
        self.add_entity(debug_line)
        debug_line.add_component(TransformComponent(Vector2(0, 0)))
        debug_line.add_component(RendererComponent(LineRenderer(), (0, 0)))
        debug_line.add_component(LineHandlerComponent())

        score_label = Entity()
        self.add_entity(score_label)
        score_label.add_component(
            TransformComponent(Vector2(self.game.width - 200, 0)))
        score_label.add_component(
            PyGameRendererComponent(
                TextRenderer("score",
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))

        score = Entity()
        self.add_entity(score)
        score.add_component(
            TransformComponent(Vector2(self.game.width - 200, 20)))
        score.add_component(
            PyGameRendererComponent(
                TextRenderer("000",
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))
        score.add_component(ScoreIncreaserComponent())

        high_score_label = Entity()
        self.add_entity(high_score_label)
        high_score_label.add_component(
            TransformComponent(Vector2(self.game.width - 200, 50)))
        high_score_label.add_component(
            PyGameRendererComponent(
                TextRenderer("high score",
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))

        high_score_num = self.scoreboard.get_instance(0)[1]
        high_score = Entity()
        self.add_entity(high_score)
        high_score.add_component(
            TransformComponent(Vector2(self.game.width - 200, 70)))
        high_score.add_component(
            PyGameRendererComponent(
                TextRenderer(str(high_score_num),
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))

        ts = TileSet()
        ts.load("./assets/tilesets/pacman_tiles.png",
                "./assets/tilesets/pacman.info")

        for i in range(3):
            pacman_live = Entity()
            self.add_entity(pacman_live)
            pacman_live.add_component(
                TransformComponent(
                    Vector2(self.game.width - 200 + 34 * i,
                            self.game.height - 100)))
            pacman_live.add_component(
                RendererComponent(
                    TileRenderer(ts.tiles["pacman"], ts, animate=False),
                    (32, 32)))

        self.add_entity(player)

        key_bindings = [[pygame.K_a], [pygame.K_d], [pygame.K_w], [pygame.K_s]]

        pacman_pos = self.field_obj.get_cells_by_type(
            Floor, Meta.pacman_spawn)[0].rect.xy

        player.add_component(MoveComponent(2))
        player.add_component(PacmanCollisions(self.field_obj))
        player.add_component(KeyControlComponent(key_bindings, MoveComponent))
        player.add_component(TransformComponent(Vector2(*pacman_pos)))
        player.add_component(BoxCollider((32, 32)))
        player.add_component(
            RendererComponent(
                TileRenderer(ts.tiles["pacman"], ts, animation_speed=0.3),
                (32, 32)))
        player.add_component(GrainCollisions())
        player.add_component(GhostCollision([red, self.pinky, inky, clyde]))
Ejemplo n.º 10
0
class MainScene(Scene):
    def __init__(self, game):
        self.game_over = GameOverComponent()
        game.add_component(self.game_over)
        game.add_component(MusicPlayerComponent())

        self.scoreboard = ScoreBoard()
        self.ghost_obj = None
        self.field_obj = None
        self.pinky = None
        super().__init__(game)

    def create_objects(self):
        self.field_obj = Field(self.game, 32)
        self.ghost_obj = GhostMove(self.game, self.field_obj)

        field = Entity()
        self.add_entity(field)
        shader = Shader.init_from_files("assets/shaders/walls/walls.vert",
                                        "assets/shaders/walls/walls.frag")
        field.add_component(TransformComponent(Vector2(0, 0)))
        field.add_component(
            PyGameRendererComponent(ObjectRenderer(self.field_obj),
                                    self.game.screen_size, True, shader))

    def add_grain(self, rect, size, big=False):
        grain = Entity()
        self.add_entity(grain)
        grain.add_component(
            TransformComponent(
                Vector2(rect.x + rect.w / 2 - size / 2,
                        rect.y + rect.h / 2 - size / 2)))
        grain.add_component(
            RendererComponent(ImageRenderer("./assets/images/small_grain.png"),
                              (size, size)))
        grain.add_component(NameComponent('grain' + ('big' if big else '')))

    def removed(self):
        super().removed()
        self.game.remove_component(GameOverComponent)
        self.game.remove_component(MusicPlayerComponent)

    def add_entities(self):
        grain_size = 8
        for g in self.field_obj.get_cells_by_type(Floor, Meta.grain_small):
            self.game_over.max_grains_count += 1
            self.add_grain(g.rect, grain_size)

        big_grain_size = 16
        for g in self.field_obj.get_cells_by_type(Floor, Meta.grain_big):
            self.game_over.max_grains_count += 1
            self.add_grain(g.rect, big_grain_size, True)

        player = Entity()

        ghost_pos = self.field_obj.get_cells_by_type(Floor, Meta.ghost_spawn)
        self.pinky = Entity()
        self.add_entity(self.pinky)
        self.pinky.add_component(
            TransformComponent(Vector2(*ghost_pos[0].rect.xy)))
        self.pinky.add_component(BoxCollider((32, 32)))
        self.pinky.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/pink.png"),
                              (32, 32)))
        self.pinky.add_component(
            GhostMoveComponent(self.field_obj, 2, self.pinky_find_target,
                               player, Colors.pink))
        self.pinky.add_component(ScaryModeComponent())

        red = Entity()
        self.add_entity(red)
        red.add_component(TransformComponent(Vector2(*ghost_pos[1].rect.xy)))
        red.add_component(BoxCollider((32, 32)))
        red.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/red.png"),
                              (32, 32)))
        red.add_component(
            GhostMoveComponent(self.field_obj, 2, self.red_find_target, player,
                               Colors.red))
        red.add_component(ScaryModeComponent())

        inky = Entity()
        self.add_entity(inky)
        inky.add_component(TransformComponent(Vector2(*ghost_pos[2].rect.xy)))
        inky.add_component(BoxCollider((32, 32)))
        inky.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/blue.png"),
                              (32, 32)))
        inky.add_component(
            GhostMoveComponent(self.field_obj, 2, self.inky_find_target,
                               player, Colors.purple))
        inky.add_component(ScaryModeComponent())

        clyde = Entity()
        self.add_entity(clyde)
        clyde.add_component(TransformComponent(Vector2(*ghost_pos[3].rect.xy)))
        clyde.add_component(BoxCollider((32, 32)))
        clyde.add_component(
            RendererComponent(ImageRenderer("assets/images/ghosts/orange.png"),
                              (32, 32)))
        clyde.add_component(
            GhostMoveComponent(self.field_obj, 2, self.clyde_find_target,
                               player, Colors.orange))
        clyde.add_component(ScaryModeComponent())

        debug_line = Entity()
        self.add_entity(debug_line)
        debug_line.add_component(TransformComponent(Vector2(0, 0)))
        debug_line.add_component(RendererComponent(LineRenderer(), (0, 0)))
        debug_line.add_component(LineHandlerComponent())

        score_label = Entity()
        self.add_entity(score_label)
        score_label.add_component(
            TransformComponent(Vector2(self.game.width - 200, 0)))
        score_label.add_component(
            PyGameRendererComponent(
                TextRenderer("score",
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))

        score = Entity()
        self.add_entity(score)
        score.add_component(
            TransformComponent(Vector2(self.game.width - 200, 20)))
        score.add_component(
            PyGameRendererComponent(
                TextRenderer("000",
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))
        score.add_component(ScoreIncreaserComponent())

        high_score_label = Entity()
        self.add_entity(high_score_label)
        high_score_label.add_component(
            TransformComponent(Vector2(self.game.width - 200, 50)))
        high_score_label.add_component(
            PyGameRendererComponent(
                TextRenderer("high score",
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))

        high_score_num = self.scoreboard.get_instance(0)[1]
        high_score = Entity()
        self.add_entity(high_score)
        high_score.add_component(
            TransformComponent(Vector2(self.game.width - 200, 70)))
        high_score.add_component(
            PyGameRendererComponent(
                TextRenderer(str(high_score_num),
                             font_size=18,
                             color=Colors.white,
                             font="assets/fonts/Emulogic.ttf"), (0, 0)))

        ts = TileSet()
        ts.load("./assets/tilesets/pacman_tiles.png",
                "./assets/tilesets/pacman.info")

        for i in range(3):
            pacman_live = Entity()
            self.add_entity(pacman_live)
            pacman_live.add_component(
                TransformComponent(
                    Vector2(self.game.width - 200 + 34 * i,
                            self.game.height - 100)))
            pacman_live.add_component(
                RendererComponent(
                    TileRenderer(ts.tiles["pacman"], ts, animate=False),
                    (32, 32)))

        self.add_entity(player)

        key_bindings = [[pygame.K_a], [pygame.K_d], [pygame.K_w], [pygame.K_s]]

        pacman_pos = self.field_obj.get_cells_by_type(
            Floor, Meta.pacman_spawn)[0].rect.xy

        player.add_component(MoveComponent(2))
        player.add_component(PacmanCollisions(self.field_obj))
        player.add_component(KeyControlComponent(key_bindings, MoveComponent))
        player.add_component(TransformComponent(Vector2(*pacman_pos)))
        player.add_component(BoxCollider((32, 32)))
        player.add_component(
            RendererComponent(
                TileRenderer(ts.tiles["pacman"], ts, animation_speed=0.3),
                (32, 32)))
        player.add_component(GrainCollisions())
        player.add_component(GhostCollision([red, self.pinky, inky, clyde]))

    @staticmethod
    def red_find_target(pacman, field, pos):
        return pacman.get_component(TransformComponent).pos

    @staticmethod
    def clyde_find_target(pacman, field, pos):
        pac_pos = pacman.get_component(TransformComponent).pos
        if pac_pos.distance_to(pos) > field.size * 8:
            return pac_pos
        return Vector2(0, len(field.matrix) * field.size)

    @staticmethod
    def vec2tuple(vec):
        return int(vec.x), int(vec.y)

    def find_cell_ahead(self, pac_pos, dir, field, distance):
        pdir = Vector2(dir.x, dir.y)
        start_pos = Vector2(pac_pos.x // field.size, pac_pos.y // field.size)
        cell_pos = Vector2(start_pos.x, start_pos.y)
        c_dirs = [Vector2(1, 0), Vector2(-1, 0), Vector2(0, 1), Vector2(0, -1)]
        for i in range(distance):
            cell = field.get_cell_iter(*self.vec2tuple(cell_pos))
            next_cell = field.get_cell_iter(*self.vec2tuple(cell_pos + dir))
            if (Meta.ghost_turn in cell.meta
                    and not next_cell.state) or not cell.state:
                for c_dir in c_dirs:
                    new_pos = cell_pos + c_dir
                    if start_pos != cell_pos + c_dir and (c_dir.x != -pdir.x or c_dir.y != -pdir.y) \
                            and field.get_cell_iter(*self.vec2tuple(new_pos)).state:
                        dir = c_dir
            cell_pos += dir
        return cell_pos

    def pinky_find_target(self, pacman, field, pos):
        pac_pos = pacman.get_component(TransformComponent).pos
        dir = pacman.get_component(MoveComponent).direction
        cell_pos = self.find_cell_ahead(pac_pos, dir, field, 4)

        res_pos = cell_pos * field.size
        if pac_pos.distance_to(pos) < res_pos.distance_to(
                pos) and pac_pos.distance_to(pos) < 128:
            res_pos = pac_pos

        pacman.event_manager.trigger_event(
            DrawDebugLineEvent(self.create_rect_path(res_pos +
                                                     Vector2(16, 16)),
                               color=Colors.green))
        return res_pos

    def inky_find_target(self, pacman, field, pos):
        pac_pos = pacman.get_component(TransformComponent).pos
        dir = pacman.get_component(MoveComponent).direction
        cell_pos = self.find_cell_ahead(pac_pos, dir, field, 2) * field.size
        pinky_pos = self.pinky.get_component(TransformComponent).pos
        rs = cell_pos * 2 - pinky_pos
        dst = cell_pos.distance_to(pinky_pos)
        for i in range(int(dst // field.size // 2)):
            cell = field.get_cell(
                rs.lerp(cell_pos, 0.5 + (i * field.size) / dst))
            if cell.state:
                rs = Vector2(*cell.rect.xy)
                break
            cell = field.get_cell(
                rs.lerp(cell_pos, 0.5 - (i * field.size) / dst))
            if cell.state:
                rs = Vector2(*cell.rect.xy)
                break

        res_pos = rs
        if not field.get_cell(res_pos).state:
            res_pos = pac_pos

        pacman.event_manager.trigger_event(
            DrawDebugLineEvent(self.create_rect_path(res_pos +
                                                     Vector2(16, 16)),
                               color=Colors.red))
        pacman.event_manager.trigger_event(
            DrawDebugLineEvent(self.create_rect_path(cell_pos +
                                                     Vector2(16, 16)),
                               color=Colors.pink))
        pacman.event_manager.trigger_event(
            DrawDebugLineEvent([res_pos, cell_pos, pinky_pos],
                               color=Colors.blue))
        return res_pos

    @staticmethod
    def create_rect_path(pos, size=10):
        offsets = [
            Vector2(size, size),
            Vector2(size, -size),
            Vector2(-size, -size),
            Vector2(-size, size),
            Vector2(size, size)
        ]
        return [pos + off for off in offsets]