рЕаЛиЗаЦиЯ

Сейчас все вместе посмеёмся над тем, как я игры делаю. Аккуратно, там дальше nsfw-контент, от которого может стать плохо даже латентному перфекционисту.

Я опять пытаюсь превратить юнити в флеш-плеер. Из игрового движка в программу для анимации. Я уже делал пробный заход на это минное поле в период 15-го КОДа со своим «Каким-то Неправильным Симулятором Ходьбы».

В нём было много катсцен. Да что уж, он весь целиком состоял из катсцен, которые портил зачем-то затесавшейся в паре мест геймплей, а кроме того, они даже были озвучены. Поскольку ядром игры на текущий гаминатор так же должны стать катсцены, я решил прямо в процессе поделиться, как это вообще работает или не работает и что происходит, может кому-то будет интересен этот опыт.

Напомню, как выглядело окно аниматора после завершения работы над КНСХ:

CJoM8qXNC3mKaCb5tl6t0

Несмотря на визуальное сходство этой паутины с космическим кораблём, мне показалось более-менее удобным работать с ней. На первой картинке с левой стороны можно наблюдать длинный список триггеров, каждый из которых отвечает за запуск определённой анимации, запускаемой из «Any State», то есть из любого состояния. Отдельным триггером был тригер «skip», вызываемый по нажатию клавиши U и так же из любого состояния прыгающий в состояние, отвечающее за прекращение катсцен.

Все анимации в том проекте проигрывались на определённом спрайте, как свет проектора на белой простыне. По сему с началом какой-либо анимации камера должна была прыгать на этот спрайт (я не хотел создавать уйму включаемо-выключаемых камер) и в этом мне помогла такая вещь, как Behaviour Scripts, которые можно навесить прямо на состояние в аниматоре, и выполнять какой-то код при старте или по окончании анимационного фрагмента. Такой скрипт как-раз отвечал за переброс камеры к «экрану», а так же запоминал её предыдущую позицию.

В текущем проекте у меня, например, такие скрипты: (мы к ним ещё вернёмся)

bOFJqrk

Сразу вскрывается подводный камень: даже если сделать публичным переменную GameObject’a на Behaviour-скрипте, игровой объект невозможно просто взять и перетащить со сцены в окошко инспектора. Каждый раз приходится вызывать GameObject.Find (), имея возможность задать только имя объекта как string-переменную.

И второй подводный камень — странные баги юнити, при которых редактор вдруг перестаёт видеть на сцене объекты, хотя они там точно есть, и до этого момента всё работало как японские часы. Помогает перезагрузка редактора. Может быть в новых версиях уже исправили, хз, я с докембрия не обновлялся.

В том проекте, на который было отведено всего дня два (КНСХ), я даже не пытался искать способа автоматизировать вычисление длительности анимации. Все катсцены сопровождались озвучкой, посему анимация должна была более менее совпадать с аудиодорожкой, и на каждую аудиодорожку создавалась отдельная анимация, даже если она была очень похожа на предыдущую. Надо сказать, что аудио я записывал в первую очередь, потому что слышал, что работа над мультфильмами на настоящих студиях начинается как раз с записи голосов. Мультипликаторам потом проще рисовать движения губ, и вообще удалить ненужный или неудачный кусок аудио намного легче, чем нарисовать кучу кадров, которые всё равно не попадут на экраны.

Поначалу я пытался разбивать анимации на куски, просто потому что боялся, что на разных компьютерах может пойти рассинхронизация, и хорошо бы иметь как можно больше гвоздей, соединяющих визуал со звуком. Но быстро понял, что так я далеко не уеду и стал писать озвучку каждой анимации в цельный файл. При входе в анимацию выполнялся Behaviour-скрипт, отыскивающий на сцене источник звука, заменяющий в нём аудиофайл на нужную дорожку и запускающий проигрывание звука. Оставалось только раз за разом запускать игру в «тестовом» режиме, вручную активировать тригер и смотреть, где герой не попадает ртом в фонограмму, и сдвигать кадры. По этой причине к концу второго дня меня тошнило от собственного голоса. Уж не знаю, как работают профессиональные аниматоры, но было бы гораздо удобнее реализовать общую шкалу для звука и для анимации, чтобы можно было просто промотать, запустить с любого момента и услышав, на сколько секунд надо сдвинуть кадр, сразу это и поправить. К слову, никакой разницы на стримах между распиленными анимациями, и анимациями, проигрываемыми под цельный аудиофайл, я не увидел. Так что возможная рассинхронизация была пустым страхом.

А сейчас мы подходим к главному плюсу всей этой хтонической придури. Этот подход (как минимум по задумке) должен позволить мне делать интерактивные катсцены. То есть, когда игрок в КНСХ приходил к какому-либо выбору, это буквально всё ещё оставалась катсцена, в которой от мог совершить действие, которое передавалось аниматору в качестве int-значения. Мол, вариант-1, вариант-2, вариант-3, и на моём экране всё это лаконично выглядело как разветвляющееся дерево.

JfJ9uio

В текущем проекте, слава поднебесью, озвучки не предвидится. Вместо этого я решил сшить в одну химеру систему катсцен с системой диалогов (здесь можно вернуться к предыдущему скриншоту). Скрипт «AnimTextOn» по имени героя ищет соответствующий ему объект с текстом, а затем вызывает из висящего на нём скрипта «TextPrinter» функцию, которой передаётся текстовая строка. TextPrinter красиво выводит текст, а затем активирует в аниматоре триггер «flag». flag поднят — значит анимация переходит в следующее состояние и опять ждёт поднятия флага, пока не договорит очередной персонаж. Ко всему этому, конечно, присовокупляются всякие мелочи, как например отключение управления во время катсцен и всё такое, а ещё у меня в этот раз анимируется вся сцена, что несколько усложняет разбиение игры на отдельные состояния. Вот по этому у меня половину аниматора составляют длинные гирлянды пустых стейтов.