Ejemplo n.º 1
0
class TeleportSpell(Spell):
    spell_type = Spell.TELEPORT
    mana_cost = 300
    UPDATE_TIME = 40
    speed = TILE_SIZE * 1
    acceleration = 0
    damage_frame = 2
    action_time = 0

    size = (TILE_SIZE // 4 * 7,) * 2
    frames = cut_sheet(load_image('EMPTY.png', 'assets\\tiles'), 1, 1, size)
    frames += cut_sheet(load_image('teleport_puf.png', 'assets\\spells'), 8, 1, size)

    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    CAST_SOUND = pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "teleport_sound.ogg"))
    CAST_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    SPELL_SOUNDS = (
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "teleport_sound.ogg")),
    )
    for sound in SPELL_SOUNDS:
        sound.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, subject_x: float, subject_y: float, object_x: float, object_y: float, object_group, *groups):
        super().__init__(subject_x, subject_y, object_x, object_y, object_group, *groups)

        self.start_sprite = pygame.sprite.Sprite()
        self.start_sprite.start_position = None
        self.start_sprite.point = None
        self.start_sprite.image = TeleportSpell.frames[0][0]
        self.start_sprite.rect = self.start_sprite.image.get_rect()
        self.start_sprite.rect.center = object_group[0].rect.center
Ejemplo n.º 2
0
class IceSpell(Spell):
    damage = 20
    spell_type = Spell.ICE
    mana_cost = 30
    UPDATE_TIME = 40
    speed = TILE_SIZE * 0.3
    acceleration = 4
    action_time = 500

    size = (TILE_SIZE // 4 * 3,) * 2
    frames = cut_sheet(load_image('ice_laser.png', 'assets\\spells'), 30, 1, size)
    frames += cut_sheet(load_image('ice_explosion.png', 'assets\\spells'), 28, 1, size)

    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    CAST_SOUND = pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "cast_sound_1.ogg"))
    CAST_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    SPELL_SOUNDS = (
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_2.ogg")),
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_12.ogg")),
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_18.ogg")),
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_19.ogg")),
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_20.ogg")),
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_21.ogg")),
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_22.ogg")),
        pygame.mixer.Sound(concat_two_file_paths("assets/spells/audio", "spell_sound_26.ogg")),
    )
    for sound in SPELL_SOUNDS:
        sound.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, subject_x: float, subject_y: float, object_x: float, object_y: float, object_group, *groups):
        super().__init__(subject_x, subject_y, object_x, object_y, object_group, *groups)
Ejemplo n.º 3
0
class PoisonSpell(Spell):
    damage = 10
    spell_type = Spell.POISON
    mana_cost = 40
    UPDATE_TIME = 40
    speed = TILE_SIZE * 0.2
    acceleration = 0.5
    action_time = 500

    size = (TILE_SIZE // 4 * 3, ) * 2
    frames = cut_sheet(load_image('poison_laser.png', 'assets\\spells'), 7, 1,
                       size)
    frames += cut_sheet(load_image('poison_explosion.png', 'assets\\spells'),
                        11, 1, size)
    frames += cut_sheet(load_image('poison_explosion_1.png', 'assets\\spells'),
                        25, 1, size)

    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    CAST_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/spells/audio", "cast_sound_3.ogg"))
    CAST_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    SPELL_SOUNDS = (
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_1.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_12.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_13.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_17.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_23.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_24.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_26.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_27.ogg")),
    )
    for sound in SPELL_SOUNDS:
        sound.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, subject_x: float, subject_y: float, object_x: float,
                 object_y: float, object_group, *groups):
        super().__init__(subject_x, subject_y, object_x, object_y,
                         object_group, *groups)
Ejemplo n.º 4
0
class VoidSpell(Spell):
    damage = 70
    spell_type = Spell.VOID
    mana_cost = 120
    speed = TILE_SIZE * 0.24
    acceleration = 3
    UPDATE_TIME = 40
    damage_frame = 5
    action_time = 0

    size = (TILE_SIZE * 3, ) * 2
    frames = cut_sheet(load_image('void_laser.png', 'assets\\spells'), 10, 1)
    frames += cut_sheet(load_image('void_explosion.png', 'assets\\spells'), 12,
                        2, size)
    frames += cut_sheet(load_image('void_explosions.png', 'assets\\spells'),
                        10, 5, size)

    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    CAST_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/spells/audio", "cast_sound_5.ogg"))
    CAST_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    SPELL_SOUNDS = (
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_2.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_5.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_14.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_15.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_16.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_17.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_18.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_25.ogg")),
    )
    for sound in SPELL_SOUNDS:
        sound.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, subject_x: float, subject_y: float, object_x: float,
                 object_y: float, object_group, *groups):
        super().__init__(subject_x, subject_y, object_x, object_y,
                         object_group, *groups)
Ejemplo n.º 5
0
class LongWizard(ShootingMonster):
    """
    Большой маг

    Подвижный
    Среднее количество жизней
    Большой урон
    Устойчивость к молниям
    Слабость к огню
    """
    damage = 20
    size = (int(TILE_SIZE // 8 * 7), ) * 2
    frames = cut_sheet(load_image('long_wizard_run.png', 'assets\\enemies'), 4,
                       2)
    frames += cut_sheet(load_image('long_wizard_idle.png', 'assets\\enemies'),
                        4, 2)

    death_frames = cut_sheet(
        load_image('long_wizard_dying.png', 'assets\\enemies'), 16, 1)[0]

    default_speed = TILE_SIZE * 0.02
    look_directions = {
        (-1, -1): 1,
        (-1, 0): 1,
        (-1, 1): 1,
        (0, -1): 1,
        (0, 0): 0,
        (0, 1): 0,
        (1, -1): 0,
        (1, 0): 0,
        (1, 1): 0
    }
    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(2)

    # Звуки
    FOOTSTEP_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/enemies/audio", "wizard_rustle.mp3"))
    FOOTSTEP_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, x, y, *args):
        super().__init__(x, y, *args)

        self.visibility_range = TILE_SIZE * 13

        self.health = 80
        self.full_health = self.health

        self.reload_time = self.reload_time * 4 / 3
Ejemplo n.º 6
0
class Demon(WalkingMonster):
    """
    Демон

    Мало жизней
    Быстрый
    Больно бьёт
    Устойчивойть к огню
    Слабость к льду
    """
    damage = 50
    size = (int(TILE_SIZE // 8 * 5), ) * 2
    frames = cut_sheet(load_image('demon_run.png', 'assets\\enemies'), 4, 2,
                       size)
    frames += cut_sheet(load_image('demon_idle.png', 'assets\\enemies'), 4, 2,
                        size)

    death_frames = cut_sheet(load_image('demon_dying.png', 'assets\\enemies'),
                             16, 1)[0]

    UPDATE_TIME = 60
    default_speed = TILE_SIZE * 0.023

    look_directions = {
        (-1, -1): 1,
        (-1, 0): 1,
        (-1, 1): 1,
        (0, -1): 1,
        (0, 0): 0,
        (0, 1): 0,
        (1, -1): 0,
        (1, 0): 0,
        (1, 1): 0
    }
    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    FOOTSTEP_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/enemies/audio", "little_steps.mp3"))
    FOOTSTEP_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, x, y, *args):
        super().__init__(x, y, *args)
        self.alive = True
        self.visibility_range = TILE_SIZE * 7

        self.health = 40
        self.full_health = self.health
Ejemplo n.º 7
0
class DirtySlime(WalkingMonster):
    """
    Грязный слизень
    Я как Зеленый, но чуть крепче

    Медленный
    Много жизней
    Не очень большой урон
    Устойчивость к льду и отравлению
    Слабость к молниям
    """
    damage = 70
    size = (int(TILE_SIZE // 8 * 7), ) * 2
    frames = cut_sheet(load_image('dirty_slime_any.png', 'assets\\enemies'), 4,
                       2)
    frames += cut_sheet(load_image('dirty_slime_any.png', 'assets\\enemies'),
                        4, 2)

    death_frames = cut_sheet(
        load_image('dirty_slime_dying.png', 'assets\\enemies'), 16, 1)[0]

    default_speed = TILE_SIZE * 0.02
    look_directions = {
        (-1, -1): 1,
        (-1, 0): 1,
        (-1, 1): 1,
        (0, -1): 1,
        (0, 0): 0,
        (0, 1): 0,
        (1, -1): 0,
        (1, 0): 0,
        (1, 1): 0
    }
    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(4)

    # Звуки
    FOOTSTEP_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/enemies/audio", "slime_sound_1.ogg"))
    FOOTSTEP_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, x, y, *args):
        super().__init__(x, y, *args)
        self.alive = True
        self.visibility_range = TILE_SIZE * 5

        self.health = 100
        self.full_health = self.health
Ejemplo n.º 8
0
class Wizard(ShootingMonster):
    """
    Маг

    Подвижный
    Маловато жизней
    Средний урон
    Устойчивость к молниям
    Слабость к огню (МОЙ ПЛАЩ ГОРИТ)
    """
    damage = 10
    size = (TILE_SIZE // 8 * 7, ) * 2
    frames = cut_sheet(load_image('wizard_run.png', 'assets\\enemies'), 4, 2,
                       size)
    frames += cut_sheet(load_image('wizard_idle.png', 'assets\\enemies'), 4, 2,
                        size)

    death_frames = cut_sheet(load_image('wizard_dying.png', 'assets\\enemies'),
                             16, 1)[0]

    default_speed = TILE_SIZE * 0.022
    look_directions = {
        (-1, -1): 1,
        (-1, 0): 1,
        (-1, 1): 1,
        (0, -1): 1,
        (0, 0): 0,
        (0, 1): 0,
        (1, -1): 0,
        (1, 0): 0,
        (1, 1): 0
    }
    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    FOOTSTEP_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/enemies/audio", "wizard_rustle.mp3"))
    FOOTSTEP_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, x, y, *args):
        super().__init__(x, y, *args)
        self.alive = True
        self.visibility_range = TILE_SIZE * 9

        self.health = 60
        self.full_health = self.health
Ejemplo n.º 9
0
class Zombie(WalkingMonster):
    """
    Зомби

    Не медленный, но и не быстрый
    Среднее количество жизней
    Средний урон
    Устойчивость к молниям (они двигают мои нейроны)
    Слабостей не обнаружено (земля пухом ученым)
    """
    damage = 30
    size = (int(TILE_SIZE // 4 * 3), ) * 2
    frames = cut_sheet(load_image('zombie_run.png', 'assets\\enemies'), 4, 2)
    frames += cut_sheet(load_image('zombie_idle.png', 'assets\\enemies'), 4, 2)

    death_frames = cut_sheet(load_image('zombie_dying.png', 'assets\\enemies'),
                             16, 1)[0]

    default_speed = TILE_SIZE * 0.02
    look_directions = {
        (-1, -1): 1,
        (-1, 0): 1,
        (-1, 1): 1,
        (0, -1): 1,
        (0, 0): 0,
        (0, 1): 0,
        (1, -1): 0,
        (1, 0): 0,
        (1, 1): 0
    }
    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    FOOTSTEP_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/enemies/audio", "stone_steps_1.mp3"))
    FOOTSTEP_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, x, y, *args):
        super().__init__(x, y, *args)
        self.alive = True
        self.visibility_range = TILE_SIZE * 6

        self.health = 80
        self.full_health = self.health
Ejemplo n.º 10
0
class Torch(pygame.sprite.Sprite):
    frames = cut_sheet(load_image('TORCH.png', 'assets\\tiles'), 8, 1,
                       (round(TILE_SIZE / 4 * 3), ) * 2)

    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(0)
    min_distance_to_player = 100

    # Звуки
    BURNING_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/audio", "torch_sound.mp3"))
    BURNING_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME - SOUNDS_VOLUME_REDUCER)

    def __init__(self, x: float, y: float, *groups):
        super().__init__(*groups)
        self.image = Torch.frames[0][randint(0, len(Torch.frames[0]) - 1)]
        self.rect = self.image.get_rect().move(x * TILE_SIZE, y * TILE_SIZE)

        self.cur_frame = 0
        self.update_time = pygame.time.get_ticks()

    def update(self, player=None) -> None:
        if not player:
            Torch.min_distance_to_player = 100000
            return
        if pygame.time.get_ticks() - self.update_time > 100 + randint(-20, 20):
            self.update_time = pygame.time.get_ticks()
            while 1:
                n = randint(0, 7)
                if n != self.cur_frame:
                    self.cur_frame = n
                    break
            self.image = Torch.frames[0][self.cur_frame]

        dx, dy = player.rect.centerx - self.rect.centerx, player.rect.centery - self.rect.centery
        Torch.min_distance_to_player = min(max((dx**2 + dy**2)**0.5, 0.000001),
                                           Torch.min_distance_to_player)
        self.BURNING_SOUND.set_volume(
            min(
                DEFAULT_SOUNDS_VOLUME /
                (Torch.min_distance_to_player / TILE_SIZE) * 1, 1.2))
        if not self.sounds_channel.get_busy():
            self.sounds_channel.play(self.BURNING_SOUND)
Ejemplo n.º 11
0
class Door(pygame.sprite.Sprite):
    frames = [load_tile('DOOR.png'), load_tile('EMPTY.png')]

    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(0)
    min_distance_to_player = 100

    # Звуки
    OPEN_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/audio", "door_open.mp3"))
    OPEN_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)
    CLOSE_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/audio", "door_close.mp3"))
    CLOSE_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, x: float, y: float, *groups):
        super().__init__(*groups)
        self.image = Door.frames[0]
        self.rect = self.image.get_rect().move(x * TILE_SIZE, y * TILE_SIZE)
        self.collider = Collider(x, y)

        self.opened = False

    def update(self,
               player=None,
               enemies_group=None,
               player_group=None) -> None:
        if not player:
            Door.min_distance_to_player = 100000
            return
        collide = pygame.sprite.spritecollide

        if not self.opened and (collide(self, enemies_group, False)
                                or collide(self, player_group, False)):
            dx, dy = player.rect.centerx - self.rect.centerx, player.rect.centery - self.rect.centery
            Door.min_distance_to_player = min(
                max((dx**2 + dy**2)**0.5, 0.000001),
                Door.min_distance_to_player)

            volume = min(
                DEFAULT_SOUNDS_VOLUME /
                (Door.min_distance_to_player / TILE_SIZE) * 10, 1.2)
            self.OPEN_SOUND.set_volume(volume)
            if self.sounds_channel.get_busy():
                self.sounds_channel.stop()
            self.sounds_channel.play(self.OPEN_SOUND)
            self.opened = True
            self.image = Door.frames[1]

        elif self.opened and not (collide(self, enemies_group, False)
                                  or collide(self, player_group, False)):
            dx, dy = player.rect.centerx - self.rect.centerx, player.rect.centery - self.rect.centery
            Door.min_distance_to_player = min(
                max((dx**2 + dy**2)**0.5, 0.000001),
                Door.min_distance_to_player)

            volume = min(
                DEFAULT_SOUNDS_VOLUME /
                (Door.min_distance_to_player / TILE_SIZE) * 10, 1.2)
            self.CLOSE_SOUND.set_volume(volume)
            if self.sounds_channel.get_busy():
                self.sounds_channel.stop()
            self.sounds_channel.play(self.CLOSE_SOUND)
            self.opened = False
            self.image = Door.frames[0]
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
class Button(pygame.sprite.Sprite):
    """
    Класс отвечающий за кнопку в UI элементах
    """

    # Типы событий
    PRESS_TYPE = pygame.USEREVENT + 1
    HOVER_TYPE = pygame.USEREVENT + 2
    # Звук при наведении
    HOVER_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/audio", "button_hover.wav"))
    HOVER_SOUND.set_volume(DEFAULT_HOVER_SOUND_VOLUME)

    def __init__(self,
                 position: tuple,
                 text: str,
                 text_size: int,
                 base_button_filename="button.png",
                 hover_button_filename="button_hover.png",
                 *args):
        super().__init__(*args)

        # События, которые будут вызываться pygame внутри update
        # (с помощью sender_text будет определено какая кнопка нажата)
        self.PRESS_EVENT = pygame.event.Event(Button.PRESS_TYPE,
                                              {"sender_text": text})
        self.HOVER_EVENT = pygame.event.Event(Button.HOVER_TYPE,
                                              {"sender_text": text})

        # Свойство, чтобы при наведении звук воспроизводился только один раз
        self.was_sound_played = False

        # Базовое изображение
        self.base_image = load_image(base_button_filename,
                                     path_to_folder="assets/UI")
        # Изображение при наведении
        self.hover_image = load_image(hover_button_filename,
                                      path_to_folder="assets/UI")
        # Текущее изображение
        self.image = self.base_image
        # Текст
        self.text = text
        self.font = pygame.font.Font("assets\\UI\\pixel_font.ttf", text_size)
        self.text_surface = self.font.render(text, True, pygame.Color("white"))
        # Выводим текст поверх кнопки
        self.image.blit(
            self.text_surface,
            self.text_surface.get_rect(center=self.image.get_rect().center))
        self.rect = self.image.get_rect()
        # Двигаем кнопку, но с учётом размера
        self.rect = self.rect.move(position[0] - self.rect.width / 2,
                                   position[1] - self.rect.height / 2)

    def update(self, scope_position: tuple, was_click: bool, *args) -> None:
        """
        Метод обновляет состояние кнопки. Если что-то произошло, то вызывается
        соответствующий метод, и меняется sprite (если нужно)
        :param scope_position: Кортеж координат курсора или
        прицела, если подключён джойстик
        :param was_click: Было ли произведено нажатие
        """
        # Проверяем наличие колизии курсора с кнопкой
        if self.rect.collidepoint(*scope_position):
            # Добавляем нужное событие в конец списка событий
            if was_click:
                pygame.event.post(self.PRESS_EVENT)
            else:
                # Если звук наведения не был воспроизведён, то он воспроизводится
                if not self.was_sound_played:
                    Button.HOVER_SOUND.play()
                    self.was_sound_played = True

                pygame.event.post(self.HOVER_EVENT)
            # Меняем изображение
            self.image = self.hover_image
        else:
            self.image = self.base_image
            # Т.к. на кнопку наведения нет, то сбрасываем свойство
            self.was_sound_played = False

        # Заного выводим текст поверх кнопки
        self.image.blit(
            self.text_surface,
            self.text_surface.get_rect(center=self.image.get_rect().center))
Ejemplo n.º 14
0
class FlashSpell(Spell):
    damage = 50
    spell_type = Spell.FLASH
    mana_cost = 200
    UPDATE_TIME = 60
    speed = TILE_SIZE * 0.5
    acceleration = 1
    damage_frame = 5
    action_time = 0

    size = (TILE_SIZE // 2 * 3, ) * 2
    frames = cut_sheet(load_image('EMPTY.png', 'assets\\tiles'), 1, 1, size)
    frames += cut_sheet(load_image('light.png', 'assets\\spells'), 15, 1, size)

    # Канал для звуков
    sounds_channel = pygame.mixer.Channel(3)

    # Звуки
    CAST_SOUND = pygame.mixer.Sound(
        concat_two_file_paths("assets/spells/audio", "cast_sound_4.ogg"))
    CAST_SOUND.set_volume(DEFAULT_SOUNDS_VOLUME)

    SPELL_SOUNDS = (
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_3.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_4.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_5.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_6.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_7.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_8.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio", "spell_sound_9.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_10.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_11.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_14.ogg")),
        pygame.mixer.Sound(
            concat_two_file_paths("assets/spells/audio",
                                  "spell_sound_26.ogg")),
    )
    for sound in SPELL_SOUNDS:
        sound.set_volume(DEFAULT_SOUNDS_VOLUME)

    def __init__(self, subject_x: float, subject_y: float, object_x: float,
                 object_y: float, object_group, *groups):
        super().__init__(subject_x, subject_y, object_x, object_y,
                         object_group, *groups)
Ejemplo n.º 15
0
def execute(screen: pygame.surface.Surface) -> int:
    """
    Функция запускает главное меню игры на переданном экране. В
    зависимости от действий возвращает свой код
    0 - была нажата кнопка выйти
    1 - была нажата кнопка играть
    :param screen: Экран на котором надо отрисовывать менюв
    :return: Код
    """
    is_open = True
    clock = pygame.time.Clock()
    joystick = get_joystick() if check_any_joystick() else None

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

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

    button_play = Button((screen.get_width() // 2, next_y), "Играть", 32)
    next_y = button_play.rect.y + button_play.rect.height + UI_MARGIN

    button_controls = Button((screen.get_width() // 2, next_y), "Управление",
                             32)
    next_y = button_controls.rect.y + button_controls.rect.height + UI_MARGIN

    button_about = Button((screen.get_width() // 2, next_y), "Об игре", 32)
    next_y = button_about.rect.y + button_about.rect.height + UI_MARGIN

    button_authors = Button((screen.get_width() // 2, next_y), "Авторы", 32)
    next_y = button_authors.rect.y + button_authors.rect.height + UI_MARGIN

    button_exit = Button((screen.get_width() // 2, 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_authors)
    UI_sprites.add(button_exit)

    # Текущие диалог (может появлятся при нажатии кнопок)
    current_message_box = None

    # Фоновое изоюражение
    background_image = load_image("main_menu_BG.png", "assets/UI")
    # Меняем размер картинки в зависимости от размера экрана
    background_image = pygame.transform.scale(
        background_image, (screen.get_width(), screen.get_height()))

    # Делаем курсор мыши невидимым и загружаем вместо него своё изображение
    pygame.mouse.set_visible(False)
    cursor_image = load_image("cursor.png", "assets/UI/icons")
    # координаты курсора
    cursor_x, cursor_y = screen.get_width() * 0.5, screen.get_height() * 0.1
    cursor_speed = 30  # скорость курсора (нужно если используется джойстик)

    # Фоновая музыка
    pygame.mixer.music.load(
        concat_two_file_paths("assets/audio", "main_menu.ogg"))
    # Воспроизведение музыки вечно
    pygame.mixer.music.play(-1)
    # Установка громкости
    pygame.mixer.music.set_volume(DEFAULT_MUSIC_VOLUME)

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

    # Цикл окна
    while is_open:
        # Обработка событий
        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_controls.text:
                    text = str("Базовое управление:\n" +
                               "На клавиатуре: WASD - двигаться; Q - рывок\n" +
                               "На джойстике: PADS - двигаться; R1 - рывок\n")
                    current_message_box = MessageBox(
                        text, 30,
                        (screen.get_width() * 0.5, screen.get_height() * 0.5))
                    continue

                # Об игре
                if sender_text == button_about.text:
                    text = str("Игра жанра Rogulite, в \n"
                               "которой надо пройти \n" +
                               "сквозь подземелье, заполненное врагами.\n"
                               "Желаем удачи\n")
                    current_message_box = MessageBox(
                        text, 30,
                        (screen.get_width() * 0.5, screen.get_height() * 0.5))
                    continue

                # Авторы
                if sender_text == button_authors.text:
                    text = str("Никита Сошнев (Nik4ant)\n"
                               "Максим Рудаков (Massering)")
                    current_message_box = MessageBox(
                        text, 30,
                        (screen.get_width() * 0.5, screen.get_height() * 0.5))
                    continue

                # Музыка затухает (1 секунду), т.к. главный экран закроется
                pygame.mixer.music.fadeout(1000)

                # Проверяем какая кнопка была нажата
                if sender_text == button_play.text:
                    return 1
                elif sender_text == button_exit.text:
                    return 0

        # Определение местоположения для курсора
        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
        UI_sprites.draw(screen)
        # Если есть диалог, то его тоже обновляем и рисуем
        if current_message_box:
            current_message_box.update(was_click)
            if current_message_box.need_to_draw:
                current_message_box.draw(screen)

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

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