Охота на Вампуса. Переосмысление классической игры для Алисы

Привет! Меня зовут Кирилл Богатов, я дизайнер голосовых интерфейсов в команде TORTU и заядлый геймер. Когда эти две страсти сталкиваются, рождаются необычные концепты для голосовых игр.

Месяц назад я выпустил игру «Охота на Вампуса» для голосового ассистента Алисы. Игра получила много положительных отзывов и побывала в топ-10 развлекательных навыков. В этой статье я поэтапно расскажу о процессе её создания: от переосмысления идей первоисточника — до технической реализации.

0582fe4a25d890c93070d870c3959c1f.jpg

Почему я решил поделиться своим опытом?

Рассказывая о своих проектах, я увидел определённый интерес со стороны геймеров, молодых родителей и любителей настолок. Люди начали делиться со мной концептами голосовых игр, многие из которых были ну просто «Оу, май!». Кроме того, меня регулярно спрашивают о планах создать полноценную D&D для Алисы или адаптацию игро-книг Браславского.

Как геймер, я хочу видеть больше комплексных голосовых игр вместо очередных викторин и «Угадай %name%», а как VUI-дизайнер — способствовать развитию этого направления, рассказывая о своём опыте и вдохновляя людей на реализацию их идей.

Часть 1. Общий обзор

Первоисточник

В основе игры лежит классическая текстовая аркада Hunt The Wumpus, написанная в 1972 году Грегори Йобом. От оригинала были позаимствованы название и базовые механики. Впоследствии игра обросла собственными идеями и сильно изменилась по настроению.

2c4c42a7d4f0f3f3df6d4102cc1babfd.jpeg

Действие игры происходит в пещере из 20 комнат, связанных между собой коридорами. Цель игры — выследить и подстрелить монстра Вампуса. Если игрок окажется с ним в одной комнате, то игра закончится, а убить монстра можно только выстрелом из соседней комнаты. 

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

Новые идеи

50 лет назад для создания атмосферной игры было достаточно сказать «пещера» и «воняет Вампусом». Сегодня такой трюк не пройдёт. Чтобы удержать внимание игрока и мотивировать его на исследования, игра должна удивлять и регулярно подбрасывать что-то новое. По этой причине я внёс в игру ряд нововведений, которые изменили её до неузнаваемости.

  • Тематические локации. Вместо безликих комнат игрок теперь исследует уникальные места: ледяной туннель, руины подземного города, гейзеры и многие другие. 

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

  • Сундуки. В оригинале игрок просто перемещался между комнатами и изредка стрелял во что-нибудь — и это быстро надоедало. Чтобы разнообразить геймплей, я добавил загадочные сундуки. В каждом из них может попасться как ценный артефакт, облегчающий прохождение, так и ловушка или забавная записка.

  • Ловушки. Время от времени игрок сталкивается со случайными ловушками. Они не могут навредить ему, но каждый такой момент вносит в игру разнообразие и поддерживает общий дух приключений в стиле Индианы Джонса.

  • Катаклизмы. Особые события, повышающие сложность игры и преображающие комнаты. Подробнее расскажу ниже.

  • Таблица очков. В конце похода игра подсчитывает заработанные очки и сравнивает их с результатами других игроков. Так абстрактные цифры превратились в показатель крутости игрока.

  • Достижения. Если игрок попадает в комичную ситуацию, показывает хороший результат или произносит определённые фразы (задает вопросы, грубит или хвалит), то может получить за это ачивку в конце похода.

17de0bc97bd8675bec7f6d6c18f8a081.jpg

Часть 2. Рассказчик

Персона

Персона — это то, как голосовой навык общается с пользователем. Поскольку в основе взаимодействия с игроком лежит диалог, то именно от персоны зависит то, как пользователи будет воспринимать игру. 

Персона есть во всех голосовых навыках, даже если это обычная викторина. Сравните, как одна и та же реплика могла бы звучать в навыках с разной персоной:

  • Нейтральный: Здравствуйте. В этой викторине мы проверим, насколько хорошо вы знаете популярных блогеров. Готовы начать?

  • Инициативный: Привет. Прошерстила тренды и приготовила новые вопросы о ваших любимых блогерах. Готовы проверить свои знания?

  • Неформальный: Йоп! Бот-блогеровед здесь. Готовы блеснуть знаниями в моей викторине?

Есть игры без персонажей, но нет игр без персоны.

Создавать персону с нуля крайне тяжело. Чем больше реплик, тем больше вероятность ошибиться при выборе нужных слов. В этом случае я рекомендую сделать следующее:

  • Описать Tone of Voice по методике «Четырёх измерений».

  • Взять за основу одного-двух реально существующих персонажей.

В «Вампусе» персона завязана на Рассказчике — харизматичном компаньоне, который сопровождает игроков во время их спуска в пещеру. При его создании я вдохновлялся Бобом — владельцем таверны на полях сражений Hearthstone. Выбрал его за умение подбодрить и заполнить неловкую паузу.

fc51d3e86583027fc0a14445c35e494d.jpg

Персонаж

Если вводите в игру персонажа, продумайте его биографию и запоминающиеся черты:

  • Как персонаж связан с миром игры? Как попал в него?

  • С какими ситуациями уже сталкивался персонаж? О каких событиях знает и как реагирует на них?

  • Что нравится и не нравится персонажу? Чего он боится? Чем занимается в свободное время?

  • Есть ли что-то особенное в том, как персонаж говорит или мыслит?  

  • Есть ли истории, которыми персонаж мог бы поделиться с игроком?

  • Понимает ли персонаж, что он — часть игры?

5a4056fe8a21078fcc61a26bf30bafd5.jpg

Если не уделять внимание деталям, то на выходе получится очередной весёлый болванчик или покорный «раб-компаньон». Это простительно для игр с низким уровнем персонификации, но не подходит для тех проектов, где общение с персонажем является важной частью игрового процесса или инструментом создания атмосферы.

Уберите детали и персонаж превратится в болванчика.

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

42818dcc1e3ca192bc9edafbcfc5104e.jpg

Через реплики Рассказчика игрок также опосредованно получает информацию об окружении. Например, Рассказчик может пожаловаться на холод или сырость в пещере, отогнать змею или испугаться тарантула.

Голос

Рассказчик говорит голосом Эрмила из Yandex.SpeechKit. Его завораживающий тембр позволил составлять реплики, звучащие не то из программы «В мире животных», не то с экрана загрузки третьего «Ведьмака». Стандартный же голос Алисы был слишком весёлым и не вписывался в атмосферу игры.

При тестировании оказалось, что Эрмил слишком торопится и не понимает вопросительных интонаций. Вот что я делал, чтобы справиться с этим:

  • разбивал фразы, которые нельзя прочитать на одном дыхании;  

  • переформулировал неестественно звучащие фразы;

  • вручную расставлял паузы между словами и предложениями;

  • использовал вопросительные слова и частицу «ли», чтобы фраза воспринималась как вопрос даже без нужной интонации.

Допиливайте голос вручную.

Реплики Рассказчика часто выходят за рамки озвучивания текста с экрана. Он как ассистент, который зачитывает инструкцию и комментирует происходящее: «Здесь можно повернуть налево или направо. О, смотрите какой интересный гриб за тем камнем!». С одной стороны это сокращает количество текста на экране. С другой стороны — добавляет живости и делает реакцию Рассказчика неожиданной для игрока.

Часть 3. Поиск идей

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

Концепция латерального мышления построена на разрывах шаблона. Исследователь берет за основу привычное состояние системы и применяет к ней ряд провокаций.

Для примера возьмем базовую механику «Вампуса» и сгенерируем на её основе несколько новых идей для сиквела:

  • Базовое состояние — игрок выслеживает монстра с помощью звуков в пещере.

  • Дополнение — игрок выслеживает монстра и разгадывает загадки.

  • Инверсия — монстр выслеживает игрока / пещера следит за игроком и монстром.

  • Исключение — игрок никого не выслеживает, просто изучает локации.

  • Гиперболизация — игрок выслеживает нескольких монстров.

  • Изменение порядка — игра начинается с того, что игрок уже нашел монстра / монстр съел игрока.

Не сковывайте себя рамками адекватности или технических трудностей. Фантазия не терпит ограничений!

Собранные идеи рекомендую анализировать по методике «Шести шляп мышления». Даже если вы работаете в одиночку, это поможет рассмотреть ваши идеи с разных сторон и отобрать лучшие.

Часть 4. Игровой процесс

Чтобы быстро разобраться в механике и получить полное впечатление о возможностях игры — посмотрите вот это видео:

Пещера и базовые механики

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

3487b86adfe937fc18720e533b023beb.jpg

Когда игрок находится рядом с Вампусом и промахивается, монстр начинает паниковать и перемещается в одну из трех соседних комнат. C вероятностью 33% он оказывается в одной комнате с игроком. В этом случае игрок либо умирает, либо перемещается в случайную комнату с помощью летучей мыши. Иногда это приводит к курьёзным ситуациям и мыши переносят его в яму.

Связи между комнатами и пути отступления Вампуса пришлось прописывать вручную. Это был самый нудный и кропотливый этап проектирования.

fb6a5c23b12d1976e423474395ae2e55.jpg

События

Чтобы разбавить монотонный процесс осмотра комнат, в игре периодически что-то происходит. Вот как выглядят первые 10 ходов игрока (ходом считается переход в комнату):

957fb968ce84104f9f522489f2d1fdaa.jpg

Первый (малый) сундук всегда содержит что-нибудь приятное или полезное. Это сделано для того, чтобы сформировать у новых игроков позитивный первый опыт. Если бы в первом же сундуке оказался монстр или ловушка, игрок бы подумал, что в сундуки лучше вообще не лезть.

Большие сундуки подстраиваются под текущую ситуацию. Если у игрока осталось мало стрел, то он с большей вероятностью найдёт в сундуке именно стрелы. Если же из первого сундука выпал фрагмент компаса, то из последующих сундуков может выпасть другой фрагмент.

Ловушки и трёп рассказчика нужны для поддержания атмосферы и разбавления геймплея.

Катаклизм помогает встряхнуть игроков, которые уже пробежали часть комнат и начали скучать. Катаклизм случается на 10 ход и представляет собой одно из трёх событий: землетрясение, потоп или выброс лавы. В это время происходит несколько важных вещей:

  • Вампус и летучие мыши перемещаются в другие комнаты.

  • В пещере появляется ещё одна яма.

  • Меняется описание 2/3 комнат. В зависимости от типа катаклизма они становятся либо разрушенными, либо затопленными, либо сгоревшими. Некоторые комнаты получают особые названия вроде Обсидианового туннеля, который возникает после воздействия лавы на Ледяной туннель.

Иллюзия общения

При проектировании «Вампуса» мне хотелось отойти от чисто утилитарного использования голоса. Поэтому Рассказчик умеет не только озвучивать обстановку, но и поддерживать диалог, создавая тем самым иллюзию общения. 

Чтобы определить темы для диалогов, я выписал себе все сущности, которые встречаются в игре. Это комнаты, сокровища, опасности и диковинки. Получилось порядка 200 сущностей, из которых Рассказчик может отреагировать примерно на 50–70. Для остальных пока не нашлось остроумного ответа. 

55807a750d1a484b06ea4fded01d39c5.jpg

Рассказчик также умеет реагировать на типовые ситуации: приветствие, прощание, похвалу, оскорбления и т. д. Многие пользователи пытаются разговаривать с ботами как с живыми людьми, поэтому подобные вещи следует учитывать.

Выходите за рамки основного сценария.

Разнообразие

У большинства событий и реплик в игре есть от 4 до 15 различных вариантов. Это делает каждое прохождение непохожим на предыдущее. Нет ничего хуже, чем бот, который всё время повторяет одно и то же.

Особое внимание уделено вступлению. Оно должно было создавать правильный настрой и не наскучить спустя несколько партий. Для этого я составил десяток реплик, вдохновляясь любимыми книгами и играми.

Стартовые реплики при втором, десятом и двадцатом запуске игрыСтартовые реплики при втором, десятом и двадцатом запуске игры

Игра подстраивается под успехи пользователя. Чем больше игр сыграно, тем короче становится приветственная реплика (постоянным игрокам не нужно каждый раз напоминать о сути игры).

Сделайте реплики вариативными.

Часть 5. Звуки

Каждый звук в «Вампусе» выполняет определённую функцию — предупреждает об опасности или задаёт атмосферу. Например, звук натяжения тетивы создаёт небольшую напряженную паузу между репликой игрока и оглашением результата выстрела.

Моя любимая хитрость — звук зажигания факела в конце некоторых реплик Рассказчика. С одной стороны, это добавило в игру больше контекста — в комнатах темно и сыро, поэтому нужно периодически обновлять факелы. С другой стороны, помогло отделить друг от друга несколько реплик, не прибегая к длинным паузам, которые нужны пользователям для того, чтобы успеть осмыслить происходящее и подготовиться к следующей порции информации.

Звуки создают атмосферу и заполняют неловкую паузу.

Напоследок — несколько выводов по работе со звуком:

  • Оптимальная продолжительность звукового эффекта — 3–5 секунд. Длинные звуки отделяют пользователя от основного геймплея, и он начинает скучать.

  • В одной реплике лучше не использовать больше двух звуков подряд. Иначе можно сбить пользователя с толку.

  • Звуки позволяют подчеркнуть изменение окружения. Например, запуск новой партии или переход к подведению итогов отделяют их от других частей игры.

  • Звуки хорошо подходят для визуализации действий. Например, звук бросания предмета или срабатывания ловушки помогают создать в голове яркие образы.

Часть 6. Удобство

Подсказки

В любой момент игры пользователь может задать вопрос в свободной форме:

  • Как победить Вампуса?

  • Для чего нужны сокровища?

  • Сколько у меня осталось стрел?

  • Почему дует сквозняк?

  • Как узнать, где находится яма?

  • Куда я могу пойти?

  • Напомни номера комнат.

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

fd065063ce2892d3df7ab3e53ae6396a.jpg

Обработка ошибок

Рано или поздно игрок скажет что-то, что не было предусмотрено системой. Это называется ошибкой No Match. В этом случае игрока нужно нежно вернуть на правильный путь и не показаться слишком навязчивым.

В «Вампусе» используется два уровня обработки No Match:

  • 1 уровень. Пользователь столкнулся с ошибкой. В этом случае Рассказчик просит его перефразировать свой запрос.

  • 2 уровень. Пользователь дважды столкнулся с ошибкой первого уровня. На третий раз Рассказчик предлагает ему ознакомиться со списком основных команд.

12a30459ea4a65408ef158bd7cfd2f91.jpg

Обучение и тренировка

Получая первые логи, я заметил серьёзную проблему. Четверть игроков переставала играть после озвучивания правил (это два экрана текста). Другие игроки начинали играть, не зная правил, после чего закономерно говорили о том, что игра слишком непонятная.

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

12b2adbcd2f572136325b186c9c0ac28.jpg

Игрокам подобная идея зашла и количество выходов на этапе обучения снизилось почти до нуля. А чтобы игроки не бросались играть, не зная правил, обучение запускается автоматически при первом спуске в пещеру.

Часть 7. Техническая реализация

Выбор инструмента

Проектировать голосовые игры можно разными способами: на Python, JavaScript или с помощью конструкторов диалогов. Последний вариант будет особенно полезен тем, кто мало знаком с языками программирования.

Изначально я делал «Вампуса» в конструкторе Aimylogic. Но вскоре стало понятно, что мой проект слишком большой и сложный для этого. Поэтому я перешел в JAICP.

JAICP — это платформа для разработки голосовых интерфейсов. Работает на собственном языке DSL, поддерживает Kotlin и JavaScript. На базовом уровне осваивается за пару вечеров.

Ниже я расскажу о том, как реализовать несколько полезных функций и покажу, как работают комнаты в «Вампусе». Материал рассчитан на людей, слабо знакомых с программированием.

Важно: перед началом работы в Aimylogic или JAICP обязательно ознакомьтесь с их тарифами. От выбранного тарифа зависит максимальное количество новых пользователей, которые смогут сыграть в вашу игру.

Основы DSL

Подробно об использовании языка DSL можно узнать из документации Just AI. Я лишь кратко опишу базовые вещи, необходимые для понимания этой статьи.

В основе работы голосовых навыков лежат стейты (state). Стейт — это текущее состояние системы: что сказал пользователь и как на это отреагировал бот.

      state: Main
        intent: / Привет
        script: $session.hello = 1
        a: Здравствуйте! Готовы начать новую игру?
        buttons:
            "Да" -> ./NewGame
            "Нет" -> ./Exit

        state: NewGame
            intent: / Согласие
            intent!: / Новая игра
            a: Рад это слышать. Приступим!
            go!: ./Engage

Что может входить в стейт:

  • intent — намерение пользователя (фразы, на которые должен отреагировать бот);

  • intent!  — тоже намерение, но может срабатывать в любом месте диалога;

  • script — различные скрипты (например, назначение переменных);

  • a — ответ бота;

  • buttons — кнопки (саджесты);

  • go!  — переход в другой стейт.

Глобальные и локальные переменные

Переменные выполняют в игре множество функций: считают ходы игрока, убирают  собранные предметы и размещают опасности в случайных комнатах.

Переменные бывают локальными и глобальными:

  • $session — локальные, обнуляются при выходе из игры.

  • $client — глобальные, сохраняются для текущего пользователя и не обнуляются при выходе.

В «Вампусе» глобальные переменные считают количество завершенных игр и убитых Вампусов. Чем больше игр сыграно, тем короче становится приветственное сообщение. Чем больше монстров убито, тем выше ранг пользователя.

При работе с глобальными переменными может возникнуть проблема, связанная с отсутствием стартового значения при первом запуске. Вот как её можно обойти:

       script:
        if: $client.session_number > 0
            script: $client.session_number += 1.
        else: 
            script: 
                $client.session_number = 0.
                $client.session_number += 1.

Локальные переменные определяют всё остальное: ачивки, экипировку, количество стрел и так далее. Стартовые значения для них задаются и обнуляются перед запуском новой партии. Например:

    #объекты
            $session.wampus = $jsapi.random(20) + 1;
            $session.bat_1 = $jsapi.random(20) + 1;
            $session.bat_2 = $jsapi.random(20) + 1;
            $session.pit_1 = $jsapi.random(20) + 1;
            $session.pit_2 = 0;
            
    #экипировка
            $session.player_ammo = 9;
            $session.player_shot = 0;
            $session.hook = 0;
            $session.compas = 0;
            $session.compas_left = 0;
            $session.map = 0;
                
    #события
            $session.score_total = 0; 
            $session.wampus_dead = 0;
            $session.items = 0;
            $session.moves = 0;
            $session.rooms = 0;

Рандомизация

В «Вампусе» рандом встречается на каждом шагу: от наименования комнат — до путей бегства монстра.

Чтобы события происходили случайно, я использую системную переменную $jsapi.random (х) +1, где x — количество возможных значений. Затем прописываю поведение системы для каждого значения переменной (с помощью условного оператора).

    state: Disaster
        intent: / Предсказание
        script: $session.disaster = $jsapi.random(3) + 1;
        if: $session.disaster == 1
            a: Будет землетрясение.
        elseif: $session.disaster == 2
            a: Будет потоп.
        else:
            a: Будет выброс лавы.

Обратите внимание, что оператор = записывает значение в переменную, а оператор == сравнивает с этим значением.

Рандом в фразах делается с помощью YAML-справочника. В нём хранятся варианты фраз для каждого случая:

pit:
  summary: Игрок угодил в яму
  answers:
    - Ещё один путник сгинул в бездонной яме. Охота окончена
    - Вы искали славы, но нашли лишь бездонную яму. Охота окончена
    - Теперь мы знаем, что даже у бездонной ямы есть дно. Охота окончена
    - Вы упали в яму. Как жаль, что с её дна не видно звёзд на небе. Охота окончена

sorry:
  summary: Диалог восстановился после ошибки
  answers:
    - Давайте вести себя так, будто всё заработало с первого раза.
    - Прошу прощения за это недоразумение. Попробуем ещё раз.
    - Ума не приложу, как это могло произойти. Давайте ещё раз.

Чтобы фраза выбиралась случайно, в стейт добавляется скрипт с методом $reactions.random:

       script: $temp.index = $reactions.random(phrases.pit.answers.length);
       a: 
    
            

© Habrahabr.ru