Полгода назад за чашечкой кофе программист, режиссер и геймдизайнер вели дружескую беседу на тему того, что кинематограф становится скучным. «Да, спецэффекты становятся круче, количество D становится больше, но этим сейчас малого кого можно удивить. Людей цепляет сюжет. А теперь представьте, что когда-нибудь мы будем смотреть смотреть фильмы, которыми можно управлять?»
— Я бы убил Джона Коннора.
— А я бы не выбросил бузинную палочку и стал плохим волшебником.
— А я бы на месте Поттера воспользовался маховиком времени, чтобы спасти его родителей, а не клювокрыла.
И, как говорится, понеслось…
На прошлой неделе мы спросили Хабражителей интересно ли узнать о технических аспектах создания игры. Сейчас мы готовы представить плоды нашей работы и рассказать с какими трудностями столкнулись, как с ними боролись и какие результаты получили.
Ссылки на демо и продакшн версии находятся внизу статьи.
Задача: спроектировать интерактивное видео (проще говоря натянуть экспириенс Heavy Rain и Mass Effect на видео)
Сразу ответим на ваш вопрос: «Почему именно на видео? Почему не задать игровую среду и полную свободу действий?»
Мы пришли к тому что такие игры уже есть, и ничто не дает большего эффекта присутствия, чем качественное видео, да и в текстурах не застрянешь. Решили запускаться в вебе и не сталкиваться с проблемой выпуска продукта на DVD и прочими прелестями геймдева. Тем более качество интернет соединения на текущий день в большинстве случаев позволяет смотреть full hd видео без предварительной прогрузки.
Для создания MVP решили не городить несколько сюжетных линий и пошли по пути одной сюжетной линии, разбитой на определенные чекпоинты с тупиковыми ответвлениями.
Работа с управлением
Поскольку все это должно быть общедоступным и работать в браузере, наш выбор пал на JavaScript («только JavaScript, только хардкор!» © наш программист).
Была выбрана QTE-модель управления, похожая на управление экшн (стрессовыми) сценами в Heavy Rain: в определенный момент времени всплывают кнопки/серии кнопок, которые надо успеть нажать. Успел нажать — хорошо, не успел — потерял часть здоровья/самооценки. Если уровень здоровья упадет до 0 — на ближайшем чекпоинте произойдет переход в тупиковую дорожку.
Было решено заимствовать элементы игрового интерфейса у десктопных и консольных игр. В итоге у нас есть: аватар главного героя, его эмоции, мысли, пульс и здоровье.
Перед нами возникла необходимость выводить много кастомных вещей.
Использование html в нашем случае предполагает большую нагрузку на DOM, каждое обновление которого вызывало перестройку и перерисовку всех объектов, и, рано или поздно, мы бы уперлись в ресурсы компьютера.
Было решено изменить средство вывода и использовать Canvas, который позволяет делать нам кастомные вещи и перерисовывать их тогда, когда нам нужно. На данный момент мы столкнулись с тем, что на одном канвасе много статичных элементов, которые редко обновляются, и элементы, которые обновляются очень часто. И при перерисовке частого элемента могут перерисовываться тяжелые элементы. В будущем думаем либо поднять 2 канваса (для часто меняющихся и для редко меняющихся), либо редко меняющие сделать на html (нагрузка на DOM будет минимальна).
Элементы управления, используемые нами:
1) скролл мышки — формально отвечает за бег главного героя на видео. Если не крутить колесико мышки в течение 2,5 секунд здоровье/самооценка начнет очень быстро падать.
2) Нажатие клавиш отвечает за какие-то действия главного героя на видео (модель управления напоминает типичный шутер: WASD — направления, E — дейтсвие, SPACE — прыжок и т.д.)
• Неправильно нажатая / не нажатая клавиша — отнимает уровень здоровья. На нажатие клавиши дается определенное время
• Ввод серии клавиш
• Ввод отдельных фраз и предложений
Про нажатия клавиш стоит упомянуть, что реакция у всех людей разная.
Решение: мы собираем статистику по времени задержки на нажатие клавиш (от момента, когда клавиша появилась до момента нажатия). Каждый раз, когда нам нужно показать очередную клавишу, мы показываем ее со средним для данного пользователя упреждением. В итоге пользователь нажимает на клавишу практически в тот момент, когда нужно произвести действие. Самая первая клавиша в таком подходе ничего не решает и служит для инициализации упреждения (практически как в сапере: первое поле никогда не может быть миной). Но нажать эту клавишу необходимо, чтобы дальнейшее управление было комфортным. Для этой особенности пришлось ввести вес клавиш. И у первой серии клавиш в первом видеоряде максимальный вес (неправильное нажатие / не нажатие клавиши сразу сбрасывает уровень здоровья до нуля. В нашем случае проще отправить юзера в тупик и на реплей, чем дать ему поиграть с некомфортным, запаздывающим управлением). Естесвеннно, модель управления не зависит от языковой раскладки клавиатуры: событие ожидает клавишу, а не букву.
В дальнейшем мы планируем расширить управление с проведением мышкой по заданной траектории, а также добавить возможность взаимодействовать с несколькими объектами (например кадр переходит в slowmotion и за несколько секунд надо выбрать предмет из представленных в кадре).
Вся модель управления накладывается на видео путем вызова определенного события в конкретный момент времени.
Работа с видео
В работе с браузерами столкнулись с некоторыми ограничениями, например в Google Chrome, можно одновременно предзагрузить 10 видеофайлов (мы не поместились в это ограничение даже с нашим первым MVP). За счет того, что Safari — тот же Web Kit, поведение в нем очень похоже. Для Firefox ситуация была аналогична. Пришлось искать другое решение
Вариант 1. Есть пул сюжетных и тупиковых видеодорожек. Пока юзер взаимодействует с текущей сюжетной дорожкой, в фоне предзагружаются следующая сюжетная и тупиковая. Как только он достигает чекпоинта (доли секунды до конца текущего видео) мы смотрим насколько круто пользователь играл и показываем ему либо концовку текущей дорожки, либо пускаем его дальше по сюжету. Все что уже не понадобится — удаляется.
Итого: 1 файл проигрывается, два в предзагрузке. Предыдущие удалены.
Плюсы: Легко синхронизировать кадры (делается на уровне продакшена видео, когда последний кадр текущей дорожки является началом следующей сюжетной и тупиковой ветки)
Минусы: Легкий фриз на месте перехода из одной дорожки в другую.
Вариант 2. Одна длинная сюжетная дорожка и пул тупиковых. Чекпоинт задается определенным таймингом, на котором осуществляется переход на тупиковую ветку. В фоне предзагружается ближайший тупик.
Итого: 1 проигрывается, 1 в предзагрузке. Удалены только предыдущие тупики.
Плюсы: Нет фризов при движении пользователя по сюжетной ветке.
Минусы: Почти невозможно синхронизировать кадр перехода в тупик, потому что событие изменения позиции в видео файле приходит с некоторыми интервалами, на которые мы никак не можем повлиять. В результате переход в тупик начинается не с нужного кадра, да еще и со фризом.
Вариант 3: Все видеорожки в одном файле, синхронизированные по времени переходов (в одном большом файле в один момент времени параллельно воспроизводятся все видео). С помощью WebGL мы сможем показывать часть этого файла, равную по размеру одному конкретному видеофайлу внутри. Звучит страшно, на вид несуразно, но все же хотим пробовать в ближайшем будущем.
Плюсы: В теории безфризовая модель: переход от одной части с видео до другой это один кадр отрисовки и при 60 fps это 1/60 секунды.
Минусы: Пока не ясен размер получаемого файла и как на него отреагируют браузеры.
Возникает вопрос, как работать со звуком, скорее всего придется колдовать над его синхронизацией. В вариантах выше звук пришит к видеодорожкам.
Главный минус всех трех подходов: если пользователь совершил критические ошибки вначале текущей сюжетной дорожки, то он с нулевым здоровьем продолжит движение по сюжету до ближайшего чекпоинта.
Решение: мы максимально сокращаем по времени сюжетные ветки, чтобы «расплата» за совершенное или несовершенное действие была незамедлительной. На данный момент некоторые дорожки имеют тайминг около 5 секунд. Оптимальный тайминг одной сюжетной видеодорожки после тестирования на фокусгруппе около 1000 человек составил 15-20 сек.
Да-да, посмотрев на это вы скажете: «Тут и не пахнет управлением видеорядом, максимум на что это потянет — псевдоуправление».
Это действительно так. Как бы мы не старались, о полной свободе управления видео речь идти не может. Для кинематографа, на наш взгляд, абсолютной свободы управления и не требуется. Какая разница что вы дадите главному герою на завтрак, гречку или овсянку? Оденете на него кеды или кроссовки. Под управлением мы понимаем ключевые действия, которые могут повлиять на ход сюжета: их должно быть много и они должны быть очень динамичными. Ежеминутные погони, драки, перестрелки, выбор фраз диалога — одним словом Хардкор, только с джойстиком в руках. Управление мелодрамой — это не для данного подхода.
В итоге был выбран Вариант 1 работы с видео.
С точки зрения продакшена с поспродакшена самой сложной частью было скрыть «телепортации» героя с локации на локацию и немного компьютерной графики. Количество монтажных стыков в 5-минутном ролике было больше 20. Звуку было уделено отдельное внимание: на площадке записывались каждые шорохи. Количество параллельных звуковых дорожек больше 100.
Немного серверной истории
Изначально мы пробовали запустить в вебе под имеющимся у нас железом, и смотрели слайдшоу. С учетом предполагаемой нагрузки встал вопрос завести контентный сервер, который предназначен для отдачи больших объемов видео с хорошим каналом. Плюс самый дешевый трафик у CDN, и видеоряд грузится пользователю с ближайшего к нему физического сервера. В итоге всю статику завели под CDN, сайт, скрипты и статистика работает под другим сервером.
Продакшн
Это было испытанием силы воли, стойкости духа, пределов физических и психологических возможностей человека. На съемки была отведена неделя. В это время входило: написание сценария, location scouting, поиск массовки, сами съемки. В среднем съемочный день длился 18-20 часов.
К слову, шагомер главного героя не переварил такого объема данных и умер. Runtastic продюссера, который бегал в 5 раз меньше главного героя, показал 91 км пройденной дистанции за неделю.
Некоторые сцены были простые, некоторые требовали колоссальных приготовлений и снимались кусками в разные дни. Часть сцен писали вслепую без playback. Например, на сцену с Касперским было всего 5 минут: 6 дублей подряд с надеждой, что будет кадр и потом выберем из имеющихся лучший. Свои 5 копеек вносила погода: для съемок интро нужны были подходящие полетные условия. В итоге дождались их на 6ой съемочный день. На сцену было всего 20 минут, пока не сядет костер. В итоге он сел и мы доснимали с рук. Также проблемы с коптерами поджидали на последней сцене. По сценарию в один момент времени в ограниченном пространстве, окруженном тоннами металлоконструкций, должны были летать 5 коптеров. Датчики сходили с ума, коптеры бросало из стороны в сторону. И на съемки этой сцены у нас было так же 20 минут с учетом тестов (самый большой гексакоптер садил один аккумулятор за взлет, и между делом своим воздушным потоком разбрасывал коптеры поменьше). Благо за штурвалом находились асы пилотирования (студенты университета иннополис, которые занимаются робототехникой)
Тестировщики попадают в рай без очереди
Это видео преследует их в кошмарах. Они знают, во что был одет человек из массовки, сидящий на оранжевом кресле-груше слева на предпоследнем ряду на кадре с таймингом 1:55 мин (не ищите: голубая футболка и синие штаны). Они знают сколько дверей было открыто, сколько шагов сделал главный герой, как изменялся его пульс и так далее. Количество реплеев превысило отметку в 3000 раз за 2 недели, что примерно составляет 250 часов просмотра и геймплея. Моменты появления клавиш выставлялись с точностью до 3х знаков после запятой. Сдвиг тайминга одного события на долю секунды мог поломать следующую серию кнопок в ожидании. Поэтому тестированию модели управления было уделено очень много внимания. Одним словом, тестировщики могут пройти эту игру, не потеряв ни единицы самооценки… Одной рукой… С завязанными глазами…
Университет Иннополис
Отдельное спасибо Университету Иннополис, что поддержали наши разработки и помогли воплотить их в жизнь. До этого у нас было 2 продукта, которые не были выложены в сети, жили только в localhost и ждали своего часа. После их презентации в университете будущего родилась идея нового продукта. В итоге, скрестив геймдев, видеопродакшен, программирование и кинематограф мы помогли команде ИТ-вуза показать отбор так увлекательно, как никто в мире не делал раньше.
В скором будущем
Мы планирум отрефакторить и переписать на TypeScript, так как в нем есть поддержка объектов и классов, что отсутствует в JavaScript и в последнем реализуется через костыли, плюс мы получим высокий с точки зрения производительности код.
Продумать запуск под мобильными браузерами и вариантами управлениями с тачскрина.
Сейчас мы готовим пилот с таймингом около 40 минут, несколькими сюжетными линиями и различными «плюшками». В планах на далекое будущее потестить камеру, которая пишет видеоряд в 360 и адаптировать продукт под vr очки.
А вот и обещанные ссылки
Демо версия (за которую нас чуть не убили в реальности. Доблестная полиция подумала, что происходит реальное похищение. Реагирование на 4х вооруженных клоунов в деловых костюмах на тонированном транспортере в 4 часа утра было молниеносным. Благо, после 20 минут обсуждения сотрудники полиции Казани с пониманием отнеслись к стартаперам из ИТ Парка). На базе данной завязки мы развиваем текущий полнометражный проект.
Be IT Hero — продакшн версия разработанная для Университета Иннополис. Где, как ни в городе будущего пробовать запустить подобные технологии?
Спасибо за внимание!
Автор: Innopolis University