Beispiel #1
0
def fade_to_color_and_back(screen: pygame.surface.Surface,
                           fade_color: pygame.Color) -> None:
    background_surface = screen.copy()
    fade_surface = pygame.surface.Surface(screen.get_size())
    fade_surface.fill(fade_color)
    fade_out(screen, background_surface, fade_surface)
    fade_out(screen, fade_surface, background_surface)
Beispiel #2
0
def apply_colour_to_surface(colour: pygame.Color,
                            shape_surface: pygame.surface.Surface,
                            rect: Union[pygame.Rect, None] = None):
    """
    Apply a colour to a shape surface by multiplication blend. This works best when the shape
    surface is predominantly white.

    :param colour: The colour to apply.
    :param shape_surface: The shape surface to apply the colour to.
    :param rect: A rectangle to apply the colour inside of.

    """
    if rect is not None:
        colour_surface = pygame.surface.Surface(rect.size,
                                                flags=pygame.SRCALPHA,
                                                depth=32)
        colour_surface.fill(colour)
        shape_surface.blit(colour_surface,
                           rect,
                           special_flags=pygame.BLEND_RGBA_MULT)
    else:
        colour_surface = pygame.surface.Surface(shape_surface.get_size(),
                                                flags=pygame.SRCALPHA,
                                                depth=32)
        colour_surface.fill(colour)
        shape_surface.blit(colour_surface, (0, 0),
                           special_flags=pygame.BLEND_RGBA_MULT)
Beispiel #3
0
    def __init__(self, scr: pygame.surface.Surface, val):
        self.value = val
        self.size = scr.get_size()
        self.screen = pygame.surface.Surface(self.size)
        self.scr = scr
        self.fps = 60
        self.background = copy(scr)
        self.background_color = (0, 0, 0)
        self.color = (255, 255, 255)
        self.width = 10

        self.start()
Beispiel #4
0
    def __init__(self, label, text, background: pygame.surface.Surface):
        self.font = pygame.font.Font(FONT_PATH, 60)
        self.screen = pygame.surface.Surface(background.get_size())
        self.background = background
        self.margin = self.screen.get_size()[0] * 0.04

        self.main_label = pygame.font.Font(FONT_PATH, 200).render(label, True, (243, 246, 250))

        self.date_update(text)
        self.button = MenuButton(width // 2 - (width * .2) // 2,
                                 height // 2 + self.text[0].get_height() * len(self.text), (width * .2, height * .15),
                                 width // 80, "OK", width // 22, self.screen)

        self.button.set_on_click(lambda: exit(), 1)
Beispiel #5
0
def flickering(screen: pygame.surface.Surface) -> None:
    background_surface = screen.copy()
    flicker_surface = pygame.surface.Surface(screen.get_size())
    flicker_surface.fill('white')
    flicker_surface.set_alpha(128)

    clock = pygame.time.Clock()
    for flicker_times in range(10):
        screen.blit(flicker_surface, (0, 0))
        clock.tick(30)
        pygame.display.flip()

        screen.blit(background_surface, (0, 0))
        clock.tick(30)
        pygame.display.flip()
def dark(surf: pygame.surface.Surface, brightness):
    image = Image.frombytes('RGBA', surf.get_size(), pygame.image.tostring(surf, 'RGBA', False))
    for x in range(image.size[0]):
        for y in range(image.size[1]):
            r, g, b, a = image.getpixel((x, y))

            red = int(r // brightness)
            red = min(255, max(0, red))

            green = int(g // brightness)
            green = min(255, max(0, green))

            blue = int(b // brightness)
            blue = min(255, max(0, blue))

            image.putpixel((x, y), (red, green, blue, a))
    del r, g, b, a, red, green, blue, brightness
    return pygame.image.fromstring(image.tobytes("raw", 'RGBA'), image.size, 'RGBA')
Beispiel #7
0
def scale_frame(image: pygame.surface.Surface,
                size: (int, int),
                k: int = 40) -> pygame.surface.Surface:
    """
    Функция масшабирует фон (рамку) к размеру <= размеру image, добавляя
    ему красивую текстуру
    :param image: Изображение фона
    :param size: Размер, к которому будет приведено изображение (но при этом
    этот размер <= размеру image
    :param k: Параметр для задания текстуры
    :return: Новое изображение
    """
    # Получение пикселец текущего изображения
    image = Image.frombytes('RGBA', image.get_size(),
                            pygame.image.tostring(image, 'RGBA'))
    pix = image.load()
    # Новое иизображение
    new_image = Image.new('RGBA', size)
    new_pix = new_image.load()
    # Итерация по пикселям текущего изображения и придание им текстуры
    # + масштабирование к размеру <= размеру image
    for j in range(size[1]):
        for i in range(size[0]):
            # Вычисления ниже нужны для придачи текстуры изображению. Так, в
            # сравнении с обычным уменьшеным изображением, оно будет выглядит красивее

            # Вычисление ряда пикселя
            if i <= k:
                a = i
            elif k <= i <= size[0] - k:
                a = k + randint(0, 10)
            else:
                a = i - size[0] + image.size[0]
            # Вычесление колонки пикселя
            if j <= k:
                b = j
            elif k <= j <= size[1] - k:
                b = k + randint(0, 10)
            else:
                b = j - size[1] + image.size[1]
            # Запись пикселя по вычисленной позиции
            new_pix[i, j] = pix[a, b]
    return pygame.image.fromstring(new_image.tobytes(), size, 'RGBA')
Beispiel #8
0
    def apply_gradient_to_surface(self,
                                  input_surface: pygame.surface.Surface,
                                  rect: Union[pygame.Rect, None] = None):
        """
        Applies this gradient to a specified input surface using blending multiplication.
        As a result this method works best when the input surface is a mostly white, stencil shape
        type surface.

        :param input_surface:
        :param rect: The rectangle on the surface to apply the gradient to. If None, applies to the
                     whole surface.
        """
        # scale the gradient up to the right size
        input_surface_size = input_surface.get_size()
        inverse_rotated_input = pygame.transform.rotate(
            input_surface, -self.angle_direction)
        gradient_size = inverse_rotated_input.get_rect().size
        gradient_surf = pygame.surface.Surface(gradient_size,
                                               flags=pygame.SRCALPHA,
                                               depth=32)

        pygame.transform.scale(self.gradient_surface, gradient_size,
                               gradient_surf)
        gradient_surf = pygame.transform.rotate(gradient_surf,
                                                self.angle_direction)

        if rect is not None:
            input_surface.set_clip(rect)
            input_surface.blit(gradient_surf,
                               rect,
                               special_flags=pygame.BLEND_RGBA_MULT)
            input_surface.set_clip(None)
        else:
            gradient_placement_rect = gradient_surf.get_rect()
            gradient_placement_rect.center = (int(input_surface_size[0] / 2),
                                              int(input_surface_size[1] / 2))

            input_surface.blit(gradient_surf,
                               gradient_placement_rect,
                               special_flags=pygame.BLEND_RGBA_MULT)
 def from_surface(surface: pygame.surface.Surface,
                  format: str = 'RGBA') -> SurfacePickable:
     return SurfacePickable(pygame.image.tostring(surface, format),
                            surface.get_size(), format)
def execute(screen: pygame.surface.Surface):
    """
    Функция запускает меню игры на паузе на переданном экране. В
    зависимости от действий закрывает всю игру, либо продолжает дальше
    :param screen: Экран на котором надо отрисовывать менюв
    :return: Возвращает -1, если игру надо закрыть, None если нет
    """
    is_open = True
    clock = pygame.time.Clock()
    joystick = get_joystick() if check_any_joystick() else None

    # Смещение между UI элементами
    UI_MARGIN = 20
    # Фоновое изображение для всего экрана
    background_image = load_image("pause_menu_BG.png", "assets/UI")
    background_image = pygame.transform.scale(background_image,
                                              screen.get_size())
    # Фоновое игображение
    ui_background_image = load_image("pause_menu_UI_BG.png", "assets/UI")
    # Центральная координата всего меню на экране
    menu_top_left = (screen.get_width() * 0.5 -
                     ui_background_image.get_width() * 0.5,
                     screen.get_height() * 0.5 -
                     ui_background_image.get_height() * 0.5)

    # Создание UI элементов
    next_y = menu_top_left[1] + ui_background_image.get_width(
    ) * 0.5 - UI_MARGIN * 2.5
    button_continue = Button((screen.get_width() // 2, next_y),
                             "Продолжить",
                             32,
                             base_button_filename="button_1.png",
                             hover_button_filename="button_1_hover.png")

    next_y += button_continue.rect.width * 0.5 + UI_MARGIN
    button_exit = Button((screen.get_width() // 2, next_y),
                         "Выйти в меню",
                         32,
                         base_button_filename="button_1.png",
                         hover_button_filename="button_1_hover.png")

    # Добавление в группу
    UI_sprites = pygame.sprite.Group()
    UI_sprites.add(button_continue)
    UI_sprites.add(button_exit)

    # Изображение для курсора
    cursor_image = load_image("cursor.png", "assets/UI/icons")
    # координаты курсора
    cursor_x, cursor_y = screen.get_rect().center
    cursor_speed = 25  # скорость курсора (нужно если используется джойстик)

    # Цикл меню
    while is_open:
        # Переменная, становящайся True если было нажатие курсора
        # (предусмотрен как джойстик, так и обычная мышка)
        was_click = False

        # Обработка событий
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_open = False
                break

            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    was_click = True

            if event.type == Button.PRESS_TYPE:
                # Текст нажатой кнопки
                # (гарантированно есть, т.к. устанавливается при инициализации)
                sender_text = event.dict["sender_text"]

                # Продолжить
                if sender_text == button_continue.text:
                    is_open = False
                    UI_sprites.empty()  # удаление всех спрайтов в группе
                    break

                # Выход
                if sender_text == button_exit.text:
                    return -1

        # Определение местоположения для курсора
        if joystick:
            axis_x, axis_y = joystick.get_axis(0), joystick.get_axis(1)
            cursor_x += cursor_speed * axis_x if abs(
                axis_x) >= JOYSTICK_SENSITIVITY else 0
            cursor_y += cursor_speed * axis_y if abs(
                axis_y) >= JOYSTICK_SENSITIVITY else 0
            # Проверка на нажатие
            was_click = joystick.get_button(CONTROLS["JOYSTICK_UI_CLICK"])
        else:
            cursor_x, cursor_y = pygame.mouse.get_pos()

        cursor_position = (cursor_x, cursor_y)
        # Обновляем все UI элементы
        UI_sprites.update(cursor_position, was_click)

        # Очистка экрана
        screen.fill((0, 0, 0))

        # Фоновое изображение окна
        screen.blit(background_image, (0, 0))
        # Фоновое изобраджение UI
        screen.blit(ui_background_image, menu_top_left)
        # Рисуем весь UI
        UI_sprites.draw(screen)

        # Рисуем курсор поверх всего
        screen.blit(cursor_image, cursor_position)
        pygame.display.flip()

        # Обновляем состояние джойстика
        joystick = get_joystick() if check_any_joystick() else None
        clock.tick(FPS)
Beispiel #11
0
def execute(screen: pygame.surface.Surface) -> int:
    """
    Функция запускает меню игры на паузе на переданном экране. В
    зависимости от действий закрывает всю игру, либо продолжает дальше
    :param screen: Экран на котором надо отрисовывать меню
    :return: Возвращает код. (1 - начать заного, -1 - закрыть игру, None - ничего)
    """
    is_open = True
    clock = pygame.time.Clock()
    joystick = get_joystick() if check_any_joystick() else None
    # Смещение между UI элементами
    margin = 20
    # Фоновое изображение для всего экрана
    background_image = AnimatedBackground(
        "pause_menu_BG_{0}.png", "assets/sprites/UI/backgrounds/pause_BG", 1,
        45, 25, screen.get_size())
    menu_width, menu_height = 280, 360
    # Фоновое игображение
    background_menu_image = scale_frame(
        load_image("assets/sprites/UI/backgrounds/pause_menu_UI_BG.png"),
        (menu_width, menu_height))
    # Центральная координата всего меню на экране
    menu_top_left = (screen.get_width() * 0.5 - menu_width * 0.5,
                     screen.get_height() * 0.25)
    # Группа со спрайтами интерфейса
    UI_sprites = pygame.sprite.Group()
    # Создание кнопок
    next_y = menu_top_left[1] + margin * 3.5  # позиция y следущего элемента
    titles = ("Продолжить", "Начать заново", "Выйти в меню"
              )  # заголовки кнопок
    for number in range(len(titles)):
        # Текущая кнопка
        button = Button((screen.get_width() // 2, next_y),
                        titles[number],
                        32,
                        base_button_filename="button_1.png",
                        hover_button_filename="button_1_hover.png")
        # Высчитывание следущей позиции по y со смещением
        next_y += button.rect.height + margin
        # Добавление в группу
        UI_sprites.add(button)
    # Изображение для курсора
    cursor_image = load_image("assets/sprites/UI/icons/cursor.png")
    # координаты курсора
    cursor_x, cursor_y = screen.get_rect().center
    cursor_speed = 40  # скорость курсора (нужно если используется джойстик)
    # Цикл меню
    while is_open:
        # Переменная, становящайся True если было нажатие курсора
        # (предусмотрен как джойстик, так и обычная мышка)
        was_click = False
        # Обработка событий
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_open = False
                break

            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    was_click = True

            if event.type == pygame.KEYDOWN:
                if event.key == CONTROLS["KEYBOARD_PAUSE"]:
                    is_open = False
                    UI_sprites.empty()  # удаление всех спрайтов в группе
                    break

            if event.type == Button.PRESS_TYPE:
                # Текст нажатой кнопки
                # (гарантированно есть, т.к. устанавливается при инициализации)
                sender_text = event.dict["sender_text"]
                # Продолжить
                if sender_text == titles[0]:
                    is_open = False
                    UI_sprites.empty()  # удаление всех спрайтов в группе
                    break
                # Начать заного
                if sender_text == titles[1]:
                    return 1
                # Выход
                if sender_text == titles[-1]:
                    return -1
        # Определение местоположения для курсора
        if joystick:
            axis_x, axis_y = joystick.get_axis(0), joystick.get_axis(1)
            cursor_x += cursor_speed * axis_x if abs(
                axis_x) >= JOYSTICK_SENSITIVITY else 0
            cursor_y += cursor_speed * axis_y if abs(
                axis_y) >= JOYSTICK_SENSITIVITY else 0
            # Проверка на нажатие
            was_click = joystick.get_button(CONTROLS["JOYSTICK_UI_CLICK"])
        else:
            cursor_x, cursor_y = pygame.mouse.get_pos()
        cursor_position = cursor_x, cursor_y

        # Обновляем все UI элементы
        UI_sprites.update(cursor_position, was_click)
        # Очистка экрана
        screen.fill((0, 0, 0))
        # Фоновое изображение окна
        background_image.update()
        screen.blit(background_image.image, (0, 0))
        # Фоновое изобраджение UI
        screen.blit(background_menu_image, menu_top_left)
        # Рисуем весь UI
        UI_sprites.draw(screen)
        # Рисуем курсор поверх всего
        screen.blit(cursor_image, cursor_position)
        pygame.display.flip()
        # Обновляем состояние джойстика
        joystick = get_joystick() if check_any_joystick() else None
        clock.tick(FPS)
Beispiel #12
0
def execute(screen: pygame.surface.Surface) -> int:
    """
    Функция запускает главное меню игры на переданном экране. В
    зависимости от действий возвращает свой код, описанный в main.py
    :param screen: Экран, на котором надо отрисовывать меню
    :return: Код
    """
    is_open = True
    clock = pygame.time.Clock()
    joystick = get_joystick() if check_any_joystick() else None

    # Смещение между ui элементами
    button_margin = 55

    screen_center = screen.get_width() // 2
    # Создание ui элементов
    game_logo = LogoImage(
        (screen_center, screen.get_height() // 6 - button_margin))
    next_y = game_logo.rect.y + game_logo.rect.height + button_margin * 2

    button_play = Button((screen_center, next_y), "Играть", 32)
    next_y = button_play.rect.y + button_play.rect.height + button_margin
    # Если файла сохранения нет (т.е. игрок играет в первый раз), то эта кнопка
    # выделяется caps lock'ом (выделяются кнопки "управление" и "об игре")
    button_controls = Button(
        (screen_center, next_y),
        "Управление" if exists('data/save.txt') else "УПРАВЛЕНИЕ", 32)
    next_y = button_controls.rect.y + button_controls.rect.height + button_margin

    button_about = Button((screen_center, next_y),
                          "Об игре" if exists('data/save.txt') else "ОБ ИГРЕ",
                          32)
    next_y = button_about.rect.y + button_about.rect.height + button_margin

    button_exit = Button((screen_center, next_y), "Выйти", 32)
    # Добавление в группу
    ui_sprites = pygame.sprite.Group()
    ui_sprites.add(game_logo)
    ui_sprites.add(button_play)
    ui_sprites.add(button_controls)
    ui_sprites.add(button_about)
    ui_sprites.add(button_exit)
    # Текущие диалог (может появлятся при нажатии кнопок)
    current_message_box = None
    # Текст появляющийся в сообщении при нажатии на кнопку "управление"
    control_text = """На клавиатуре: 
    WASD/Стрелки направлений - Двигаться
    Shift - Рывок
    1-5 - Заклинания атаки
    Space - Заклинание телепорта

    На джойстике PS4 (проводном): 
    PADS - Двигаться
    R1 - Рывок
    Заклинания см. на иконках
    """
    control_message_box = MessageBox(
        control_text, 32, (screen_center, screen.get_height() * 0.5))
    # Текст появляющийся в сообщении при нажатии на кнопку "об игре"
    about_text = """
    Pixelarious
Игра была создана как проект на тему PyGame для Яндекс Лицея.
Игра жанра Rogulite, поэтому смерть в игре перманентна.
Чтобы победить, надо пройти 10 уровней подземелья.
Чтобы убивать врагов, нужно использовать заклинания (см. управление).
Играть можно как на клавиутуре, так и на проводном джойстике от PS4.
Управление показывается внутри игры на главном окне при нажатии на кнопку "Управление". 
Его РЕКОМЕНДУЕТСЯ прочитать перед началом игры.
Ещё ОБЯЗАТЕЛЬНО посмотрите ОСОБЕННОСТИ заклинаний, НАВЕДЯ НА ИКОНКУ заклинания внизу.

Удачи в прохождении!
"""
    about_message_box = MessageBox(about_text, 32,
                                   (screen_center, screen.get_height() * 0.5))
    # Фоновое изоюражение
    background_image = load_image(
        "assets/sprites/UI/backgrounds/main_menu_BG.png")
    # Меняем размер картинки в зависимости от размера экрана
    background_image = pygame.transform.scale(background_image,
                                              screen.get_size())
    # Делаем курсор мыши невидимым и загружаем вместо него своё изображение
    pygame.mouse.set_visible(False)
    cursor_image = load_image("assets/sprites/UI/icons/cursor.png")
    # координаты курсора
    cursor_x, cursor_y = screen_center, screen.get_height() * 0.1
    # Фоновая музыка
    pygame.mixer.music.load("assets/audio/music/main_menu.ogg")
    # Воспроизведение музыки вечно
    pygame.mixer.music.play(-1)
    # Установка громкости
    pygame.mixer.music.set_volume(DEFAULT_MUSIC_VOLUME)
    # Цикл окна
    while is_open:
        # Переменная, становящайся True если было нажатие курсора
        # (предусмотрен как джойстик, так и обычная мышка)
        was_click = False
        # Обработка событий
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_open = False
            # Мышь
            if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
                was_click = True
            # Клавиши
            if event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_KP_ENTER, pygame.K_SPACE,
                                 pygame.K_RETURN):
                    # Музыка затухает (1 секунду), т.к. главный экран закроется
                    pygame.mixer.music.fadeout(1000)
                    return 1
                if event.key == CONTROLS["KEYBOARD_PAUSE"]:
                    # Музыка затухает (1 секунду), т.к. главный экран закроется
                    pygame.mixer.music.fadeout(1000)
                    return 0
            # Кастомное событие нажатия на кнопку
            if event.type == Button.PRESS_TYPE:
                # Текст нажатой кнопки (нужно для определения какая кнопка нажата
                # (гарантированно есть, т.к. устанавливается при инициализации)
                sender_text = event.dict["sender_text"]
                # Управление
                if sender_text == button_controls.text:
                    current_message_box = control_message_box
                    current_message_box.need_to_draw = True
                # Об игре
                elif sender_text == button_about.text:
                    current_message_box = about_message_box
                    current_message_box.need_to_draw = True
                # Играть
                elif sender_text == button_play.text:
                    # Музыка затухает (1 секунду), т.к. главный экран закроется
                    pygame.mixer.music.fadeout(1000)
                    return 1
                # Выход
                elif sender_text == button_exit.text:
                    # Музыка затухает (1 секунду), т.к. главный экран закроется
                    pygame.mixer.music.fadeout(1000)
                    return 0

        # Определение местоположения для курсора
        if joystick:
            axis_x, axis_y = joystick.get_axis(0), joystick.get_axis(1)
            if abs(axis_x) >= JOYSTICK_SENSITIVITY:
                cursor_x += JOYSTICK_CURSOR_SPEED * axis_x
            if abs(axis_y) >= JOYSTICK_SENSITIVITY:
                cursor_y += JOYSTICK_CURSOR_SPEED * axis_y
            # Проверка на нажатие
            was_click = joystick.get_button(CONTROLS["JOYSTICK_UI_CLICK"])
        else:
            cursor_x, cursor_y = pygame.mouse.get_pos()
        cursor_position = cursor_x, cursor_y

        # Обновляем все ui элементы
        ui_sprites.update(cursor_position, was_click)
        # Фоновое изобраджение
        screen.blit(background_image, (0, 0))
        # Рисуем весь ui
        ui_sprites.draw(screen)
        # Если есть диалог, то его тоже обновляем и рисуем
        if current_message_box:
            if current_message_box.need_to_draw:
                current_message_box.draw(screen)
            current_message_box.update(was_click)
        # Рисуем курсор поверх всего
        screen.blit(cursor_image, cursor_position)
        pygame.display.flip()
        # Обновляем состояние джойстика
        joystick = get_joystick() if check_any_joystick() else None
        clock.tick(FPS)
    return 0
Beispiel #13
0
def execute(screen: pygame.surface.Surface,
            money: int,
            count_of_alive_assistants: int,
            is_win=False):
    """
    Функция запускает конечной экран (либо смерти, либо победы)
    :param screen: Экран на котором надо отрисовывать менюв
    :param is_win: Флаг, выиграл ли игрок
    :param money: Количество собранных игроком и асистентом денег
    :param count_of_alive_assistants: Количетсво всех живых осистентов к концу игры
    игры
    """
    is_open = True
    # Фоновое изображение для всего экрана
    if is_win:
        # Фоновая музыка при победе
        pygame.mixer.music.load("assets/audio/music/win_screen_BG.ogg")
        pygame.mixer.music.play(-1)
        animated_background = AnimatedBackground(
            "win_{0}.png", "assets/sprites/UI/backgrounds/triumph_screen", 1,
            8, 80, screen.get_size())
        # Картигка с заголовком победы
        title_you_win = load_image('assets/sprites/UI/you_win.png')
        you_win_rect = title_you_win.get_rect()
        you_win_rect.center = screen.get_rect().centerx, int(
            screen.get_rect().centery * 0.7)
    else:
        # Фоновая музыка при проигрыше
        pygame.mixer.music.load("assets/audio/music/fail_screen_BG.mp3")
        pygame.mixer.music.play(-1)
        # Высчитывание размера для фона и сам фон
        size = screen.get_width() // 3, screen.get_height() // 3
        animated_background = AnimatedBackground(
            "death_{0}.png",
            "assets/sprites/UI/backgrounds/fail_screen",
            1,
            23,
            140,
            size,
            scale_2n=True)
    # Лого игры
    logo = LogoImage((screen.get_width() * 0.5, screen.get_height() * 0.1))
    # Изображение курсора
    cursor_image = load_image("assets/sprites/UI/icons/cursor.png")
    # Получение джойстика (если есть) и определение начальной позиции курсора
    if check_any_joystick():
        joystick = get_joystick()
        cursor_x, cursor_y = screen.get_rect().center
    else:
        joystick = None
        # Т.к. джойстика нет позиция будет сразу переопределна далее,
        # поэтому тут начальная позиция не задаётся
        cursor_x, cursor_y = 0, 0
    # Т.к. игрок завершил игру, то файл с сохранением будет перезаписан
    if os.path.isfile("data/save.txt"):
        with open('data/save.txt', 'r+', encoding="utf-8") as file:
            file.truncate(0)
    # Кортеж с текстом который надо вывести (каждый элемент на новой строке)
    texts = (f"Деньги собранные игроком вместе с асистентом: {money}",
             f"Количество живых асистентов: {count_of_alive_assistants}")
    # Шрифт для поверхностей ниже
    title_font = load_game_font(64)
    # Поверхности с одним и тем же текстом, но разный цвет делает крассивый эффект
    text_surfaces_yellow = [
        title_font.render(part.strip(), True, (255, 184, 50)) for part in texts
    ]
    text_surfaces_red = [
        title_font.render(part.strip(), True, (179, 64, 16)) for part in texts
    ]
    # Смещение между наложенными поверхностями для красивого эффекта
    surfaces_offset = 3
    margin = title_font.get_height() * 0.9  # отступ между двумя поверхностями
    # События, которые активируют закрытие экрана с концном
    QUITING_EVENTS = (
        pygame.QUIT,
        pygame.MOUSEBUTTONUP,
        pygame.KEYDOWN,
    )
    # Цикл меню
    while is_open:
        # Обработка событий
        for event in pygame.event.get():
            if event.type in QUITING_EVENTS:
                is_open = False
                break
        # Обновление позиции курсора
        if joystick is not None:
            # Проверка на выход
            if joystick.get_button(CONTROLS["JOYSTICK_UI_CLICK"]):
                break
            # Значение осей на левом стике
            axis_x, axis_y = joystick.get_axis(0), joystick.get_axis(1)
            # Перемещение курсора при движении оси
            if abs(axis_x) >= JOYSTICK_SENSITIVITY:
                cursor_x += JOYSTICK_CURSOR_SPEED * axis_x
            if abs(axis_y) >= JOYSTICK_SENSITIVITY:
                cursor_y += JOYSTICK_CURSOR_SPEED * axis_y
        else:
            cursor_x, cursor_y = pygame.mouse.get_pos()
        # На экране проигрыша есть фон, которого нет на экране победы
        if not is_win:
            screen.fill((31, 30, 36))
        # Вывод текущего кадра фонового изображения
        animated_background.update()
        screen.blit(
            animated_background.image,
            animated_background.image.get_rect(
                center=screen.get_rect().center))
        # Вывод картинки победного заголовка, если игрок выиграл
        if is_win:
            # Анализатор может ругаться, но если is_win истина, то
            # переменные 100% объявлены выше
            screen.blit(title_you_win, you_win_rect)
        # следущая позиция по y (будет нужно при вычислении смещения)
        next_y = 20
        # Вывод красного текста
        for text_surface in text_surfaces_red:
            y_pos = screen.get_height() * 0.6 + next_y
            screen.blit(
                text_surface,
                text_surface.get_rect(midtop=(screen.get_rect().centerx +
                                              surfaces_offset,
                                              y_pos + surfaces_offset)))
            next_y += margin
        next_y = 20
        # Вывод жёлтого текста
        for text_surface in text_surfaces_yellow:
            y_pos = screen.get_height() * 0.6 + next_y
            screen.blit(
                text_surface,
                text_surface.get_rect(midtop=(screen.get_rect().centerx,
                                              y_pos)))
            next_y += margin
        # Вывод логотипа игры
        screen.blit(logo.image, logo.rect.topleft)
        # Вывод изображения курсора
        screen.blit(cursor_image, (cursor_x, cursor_y))

        # Обновление состояния джойстика
        joystick = get_joystick() if check_any_joystick() else None
        pygame.display.flip()
Beispiel #14
0
def execute(screen: pygame.surface.Surface, is_win=False):
    """
    Функция запускает конечной экран (либо смерти, либо победы)
    :param screen: Экран на котором надо отрисовывать менюв
    :param is_win: Флаг, выиграл ли игрок
    """

    is_open = True
    clock = pygame.time.Clock()
    joystick = get_joystick() if check_any_joystick() else None

    # Фоновое изображение для всего экрана
    if not is_win:
        animated_background = AnimatedBackground("death_{0}.png", 1, 23, 60,
                                                 screen.get_size())
    else:
        # Фоновая музыка для победителя
        pygame.mixer.music.load(
            concat_two_file_paths("assets/audio", "win_screen_BG.ogg"))
        pygame.mixer.music.play(-1)
        animated_background = AnimatedBackground("win_{0}.png", 1, 8, 60,
                                                 screen.get_size())

    # Лого игры
    logo = LogoImage((screen.get_width() * 0.5, screen.get_height() * 0.1))

    # Кнопка возвращения в меню
    button_exit = Button((screen.get_width() // 2, screen.get_height() * 0.9),
                         "Вернутся в меню",
                         32,
                         base_button_filename="button_1.png",
                         hover_button_filename="button_1_hover.png")

    # Добавление в группу
    UI_sprites = pygame.sprite.Group()
    UI_sprites.add(logo)
    UI_sprites.add(button_exit)

    # Изображение для курсора
    cursor_image = load_image("cursor.png", "assets/UI/icons")
    # координаты курсора
    cursor_x, cursor_y = screen.get_rect().center
    cursor_speed = 15  # скорость курсора (нужно если используется джойстик)

    # Т.к. игрок завершил игру, то файл с сохранением будет перезаписан
    if os.path.isfile("data/save.txt"):
        with open('data/save.txt', 'r+', encoding="utf-8") as file:
            file.truncate(0)

    # Цикл меню
    while is_open:
        # Переменная, становящайся True если было нажатие курсора
        # (предусмотрен как джойстик, так и обычная мышка)
        was_click = False

        # Обработка событий
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_open = False
                break

            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    was_click = True

            if event.type == Button.PRESS_TYPE:
                # Текст нажатой кнопки
                # (гарантированно есть, т.к. устанавливается при инициализации)
                sender_text = event.dict["sender_text"]

                # Выход
                if sender_text == button_exit.text:
                    return

        # Определение местоположения для курсора
        if joystick:
            axis_x, axis_y = joystick.get_axis(0), joystick.get_axis(1)
            cursor_x += cursor_speed * axis_x if abs(
                axis_x) >= JOYSTICK_SENSITIVITY else 0
            cursor_y += cursor_speed * axis_y if abs(
                axis_y) >= JOYSTICK_SENSITIVITY else 0
            # Проверка на нажатие
            was_click = joystick.get_button(CONTROLS["JOYSTICK_UI_CLICK"])
        else:
            cursor_x, cursor_y = pygame.mouse.get_pos()

        cursor_position = (cursor_x, cursor_y)
        # Обновляем все UI элементы
        UI_sprites.update(cursor_position, was_click)

        # Очистка экрана
        screen.fill((0, 0, 0))

        animated_background.update()
        # Вывод текущего кадра фонового изображения
        screen.blit(animated_background.image, (0, 0))

        # Рисуем весь UI
        UI_sprites.draw(screen)

        # Рисуем курсор поверх всего
        screen.blit(cursor_image, cursor_position)
        pygame.display.flip()

        # Обновляем состояние джойстика
        joystick = get_joystick() if check_any_joystick() else None
        clock.tick(FPS)