Как сделать текст игры
Пишем текстовую игру на Python/Ren’Py
Как сделать текстовую игру? Да как угодно. Как сделать кроссплатформенную текстовую игру на русском с иллюстрациями, звуком, работающими сохранениями, без проблем с кириллицей, и с каким-никаким геймплеем? Да ещё и в свободное время, не отрываясь от основной работы? Вот это уже интересней и на самом деле — довольно несложно. Заинтересовавшихся прошу под кат.
Примерно год назад мы с товарищем задумали сделать небольшую текстовую игру приблизительно в духе Sunless Sea и 80 days: про мореплавание, торговлю, исследование странных поселений и общение со странными личностями. Там должна была фигурировать религия, а лучше несколько, главного героя хотелось видеть не спасителем, героем страны и прославленным мореходом, а умеренно неудачливым предпринимателем/авантюристом, до которого и дела никому нет, а модный выбор между меньшим и большим злом заменить на выбор между добром и добром: никакого набившего оскомину гримдарка ради гримдарка. Довольно быстро придумались основные фракции и персонажи, крупные порты, политическая обстановка и куча симпатичных мелочей вроде подводной охоты на осьминогов (изображена на КДПВ) и гениальной идеи дать почти всем персонажам венгерские имена, которые звучат экзотичней привычных европейских и вызывают некоторую неявную симпатию. В общем, деревянных домиков понабигало немало.
В команде у нас на тот момент был один писатель и один программист (то есть я). Требования в предыдущем абзаце относятся скорее к сетингу и духу игры, так что исполнять их должен был мой товарищ, а передо мной встали вопросы геймдизайна и функциональности движка. Во-первых, большую часть времени игрок будет тратить, читая текст и выбирая действия главного героя. Для этого нужна только сносная типографика и возможность писать сценарий с меню, опциями и переменными. Вскоре подключилась художница, так что надо было думать ещё и об иллюстрациях. Во-вторых, игра про исследования и торговлю, поэтому нужно где-то в доступном игроку виде хранить информацию о собранных слухах и купленных товарах (а также всячески её обрабатывать). И, наконец, в игре про мореходство нужна карта и возможность по ней перемещаться; просто команда “поплыть к тартарам и послушать сказки морских лошадей” явно не соответствует духу проекта. Значит, движок должен ещё и поддерживать хотя бы несложные мини-игры, а не ограничиваться только показом текста и обсчётом игровых переменных.
Почему Ren’Py
Сразу скажу, что писать движок с нуля мы даже не пытались: велосипедостроение увлекательно само по себе, но малоэффективно, если стоит цель всё-таки выпустить игру до выхода на пенсию. Также мы не рассматривали парсерную Interactive Fiction: у неё и на английском языке очень небольшая аудитория, а на русском наш проект, будь он парсерным, мог бы заинтересовать в лучшем случае несколько сот человек. А хочется если не заработать денег, то хотя бы пройти гринлайт и набрать какую-никакую репутацию. К счастью, большинство нынешних англоязычных разработчиков текстовых игр перешло от некоммерческих хобби-проектов к профессиональному геймдеву буквально несколько лет назад. Поэтому основные движки либо опенсорсны, либо, во всяком случае, бесплатны. Давайте посмотрим, что нам предлагают.
Первый вариант, пришедший мне в голову – Storynexus от Failbetter games, разработчиков Fallen London и Sunless Sea. Проекты на нём редактируются через браузер, хостятся Failbetter и через браузер же доступны игрокам. Возможности для монетизации с прошлого года удалили. Главный минус, однако, не в этом, а в том, что в Fallen London большая часть событий представлена картами, выпадающими из колоды, и сделать на Storynexus игру, не использующую эту метафору – задача нетривиальная. Да и вообще намертво привязывать свой проект к стороннему серверу с закрытым кодом, который теоретически может вообще прекратить работу в любой момент, довольно рискованно.
Есть ещё два хороших проприетарных движка для Choose Your Own Adventure, то есть игр примерно нашего типа: ChoiceScript и Inklewriter. Оба обещают прекрасную типографику, простоту разработки (браузерный редактор у Inklewriter, скриптовый язык у ChoiceScript) и возможность коммерческой публикации. К сожалению, оба позволяют делать только чистое CYOA: нет никакой возможности добавлять в игру что-то помимо собственно текста, меню и иллюстрациий. Внимательный читатель воскликнет: “Но как же так? В 80 days ведь был довольно сложный инвентарь и интерфейс путешествий, верно? А в Sorcery! я точно видел боёвку!” Увы, эти системы разрабатывались Inkle Studios под конкретные игры и в редакторе нет ни их, ни хоть какой-нибудь возможности сделать себе такие же. По той же причине (а также потому что он, эм, своеобразный) мы отказались от Twine.
Единственным устраивающим нас вариантом оказался Ren’Py. Это бесплатный опенсорсный движок для визуальных новелл (например, именно на нём сделаны “Бесконечное лето” и “Katawa shoujo”), который довольно легко настраивается для наших задач. Игры получаются кроссплатформенные: сборка дистрибутива под Win/Mac/Linux – вопрос нажатия одной кнопки, причём даже не надо иметь под рукой целевую ОС. Android и iOS также заявлены и Ren’Py-релизы под мобильные оси существуют, но мы сами пока на мобильный рынок не целимся и о разработке для него рассказать не можем. К тому же у Ren’Py очень дружелюбное и живое сообщество на русском и английском.
Простейший сценарий на Ren’Py
Ren’Py написан на Python 2.7 + Pygame и имеет собственный DSL. На этом языке, во-первых, за счёт команд типа “Показать bg_city_night_53.png в качестве фона без анимации” или “Произнести реплику «Cем… СЕМПАЙ. » от имени персонажа nyasha1” в императивном стиле пишется собственно сценарий. Во-вторых, подмножеством этого языка является Screen Language, на котором можно в декларативном стиле собирать из ограниченного набора Displayables (то есть виджетов: кнопок, изображений, текстовых полей и тому подобного) экраны и настраивать их функциональность. Если встроенных возможностей недостаточно, то с помощью Python можно добавлять собственные. Этим мы займёмся в следующей статье, а пока разберёмся со сценарием.
Сценарий в Ren’Py состоит из последовательности реплик, действий с экранами и ввода игрока. Про экраны и ввод чуть ниже, а для начала мы разберёмся с персонажами. В визуальной новелле они создаются так (код из официального туториала, с незначительными правками):
Создано два персонажа: протагонист и Сильви, оба пишут бледно-синим цветом в стандартное окошко внизу экрана. У Сильви к тому же есть портрет, который появится на экране перед тем, как она начнёт говорить. Выглядит это вот так:
Если бы мы создавали визуальную новеллу, то продолжали бы в том же духе, но мы-то не собираемся показывать портреты персонажей, да и иллюстраций пара десятков на всю игру. Большая часть текста вдобавок не является прямой речью персонажей, так что нелогично было бы привязывать её к кому-то из них. Лучше создадим виртуального персонажа-рассказчика:
Его зовут narrator; это специальное имя, которое отдаёт ему весь текст, явно не аттрибутированный другим персонажам (строго говоря, его зовут None, а narrator, как и m и s в предыдущем примере – переменная, в которую помещается объект персонажа и из которой вызываются его методы, например, say) Аргумент kind принимает два значения: adv и nvl. Первое – это дефолтное поведение, описанное выше, а второе включает nvl-режим, в котором портреты не показываются, а текстовое поле занимает большую часть экрана. Как раз то, что нам было нужно. Этот режим описывается экраном nvl_screen в файле screens.rpy и группой стилей styles.nvl* (файлы screens.rpy и options.rpy соответственно), в которых мы зададим шрифт, фон текстового поля, цвет меню и всё остальное.
Разберём построчно: сперва объявляется ярлык start, с которого начнётся игра. Это название зарезервировано и движок всегда будет переходить на него после нажатия кнопки “Новая игра”, где бы в сценарии он ни находился. Всё, что следует за ярлыком, логически находится “внутри” этого ярлыка, поэтому выделяется индентацией: она в Ren’Py работает так же, как и в чистом питоне. Инициализация картинки достаточно очевидна, а вот следующая строчка делает важную вещь: убирает весь текст с экрана nvl_screen. Автоматически это не делается, поэтому, если не расставлять nvl clear в конце каждой страницы, текст спокойно уползёт за пределы экрана и будет выводиться туда, пока экран не будет наконец очищен. Вроде бы мелочь, но на отладку пропущенных nvl clear я потратил намного больше времени, чем готов признать. Свежевымытый экран мы временно уберём, чтобы позволить игроку полюбоваться фоном, покажем фон, включим бесконечную паузу (то есть дождёмся клика) и начнём историю. Как только на nvl_screen начнёт выводиться текст, экран сам вернётся на место.
Строка с паузой, кстати, уже на питоне: для включения единичной строки её достаточно начать с ‘$’, а более длинные куски кода нужно писать внутри блока ‘python:’. Любой код, исполняемый игрой, видит модули самого Ren’Py и явно импортировать их уже не нужно.
Добавляем ветвление и переменные
К этому моменту игра представляет собой читалку, которая показывает текст, меняя при необходимости фоны. Сохранение, перемотка, главное меню и настройки уже работают из коробки. Однако если бы мы хотели написать иллюстрированную повесть, то мы бы её и написали, верно? Добавим перед текстом небольшое меню:
Теперь после включения игры пользователь (или, скорее, разработчик) сможет при желании войти в режим дебага или пропустить уже готовый кусок вступления и начать тестировать сразу кусок из последнего коммита. Строка show screen nvl закомменчена за ненадобностью – как я уже упоминал выше, экран покажется сам собой, когда на нём обновится текст. Комменты, как видите, работают абсолютно очевидным образом.
Ярлыки, меню и другие индентированные блоки могут быть вложены до произвольной глубины, но на практике мы стараемся дробить текст на эпизоды в десяток страниц. Каждый такой эпизод описан внутри отдельного ярлыка с нулевой индентацией (он уже не обязан быть внутри ярлыка start или даже в одном с ним файле), а переходы из одного эпизода в другой осуществляются прыжками. Так мы не только боремся с десятками уровней индентации, но и обеспечиваем модульность кода: каждый эпизод может тестироваться отдельно и довольно несложно проверить, какие переменные он читает, в какие пишет и куда позволяет перейти.
Внутриигровые меню и переменные устроены абсолютно так же. Поскольку и переменных, и ярлыков даже в небольшом эпизоде на десять минут игры разводится невероятное количество, мы приняли несложный вариант венгерской нотации: имя ярлыка ‘the_very_start_lazlo_nooptions’ состоит из трёх частей: названия локации the_very_start (то есть период от начала игры до первого выхода в море), названия эпизода lazlo (то есть пьянка у Лазло, на которой можно нанять молодых бездельников в матросы) и имени собственно ярлыка. При таком подходе имена получаются достаточно громоздкими, но лучше так, чем обнаружить при тестировании, что три месяца назад кто-то уже создал переменную ship_listing, выставил True бог весть где и теперь крен из одного случайного события влияет на исход другого случайного события на другом конце моря.
Вместо заключения
К этому моменту мы уже воспроизвели на Ren’Py функционал упоминавшихся выше Choicescript и inklewriter. Вроде бы наш кораблик готов к отплытию. В следующей статье я покажу, как можно создавать более сложный интерфейс с использованием экранного языка RenPy и ещё более сложный — на чистом питоне.
6 оупенсорсных средств создания текстовых игр
Вот вам пять оупенсорсных средств, с помощью которых можно написать свою собственную текстовую игру. Но до того как мы начнем, позвольте мне объяснить, что такое текстовая игра.
Интерактивная проза – категория компьютерных игр, в которых игрок может контролировать персонажа посредством текстовых команд. Одной из самых известных игр в этом жанре является Zork.
Более богатой на изображения версией текстовых игр является книга-игра. Книги-игры позволяют так же прокликать себе дорогу до финала. Графика, тем не менее, и в них особо сильного значения не имеет. Все фокусируется на тексте и сюжете. Отличным примером книги-игры является серия “Выбери себе приключение”.
Подыскать хорошую текстоую игрушку на английском языке можно здесь и здесь; на русском здесь, например.
Лучшие средства с открытым кодом для создания интерактивной прозы
Сегодня я покажу вам средства, с помощью которых можно создать интерактивную прозу на Linux. Программы не проставлены в каком-то определенном порядке.
1.Twine
Если вы еще хотите чего-то добавить в свою игру, то есть возможность облагородить творение переменными, условной логикой, изображениями, CSS и javascript. Результат Twine экспортирует в формате HTML. Такой подход дает возможность с легкостью делиться своими творениями.
На данный момент последняя версия Twine это 2.1.3, которая доступна для Linux, Windows, и Mac OS. Она лицензирована под GPL v3.
2.Quest
Как и Twine Quest можно расширить с помощью изображений, музыки, и звуковых эффектов. У вас даже есть возможность вставки роликов с YouTube или Vimeo и модификации интерфейса финальной версии игры с помощью HTML или javascript.
Последняя версия для Windows 5.7.0. Если у вас Linux или Mac, то можете использовать онлайн редактор. Он лицензирован под MIT. Исходный код доступен здесь.
3.Squiffy
Самый актуальный релиз Squiffy 5.0. Его можно запускать на Linux, Mac и Windows; можно использовать в браузере. Она лицензирована под MIT. Исходный код здесь.
4.TADS
TADS или Text Adventure Development System – это “прототипный предметно-ориентированный язык программирования и набор стандартных библиотек” для создания интерактивной прозы. Наиболее свежая версия языка TADS основана на C++ и javascript. Она предоставляет компилятор как для создания игр, так и для самой игры.
TADS вне всяких сомнений самый сложный вариант из представленных в этом списке. Не уверен какая у него лицензия, но если верить официальному сайту, то любая созданная на нем игра может быть распространена и продана без ограничений.
5.Inform
У Inform есть библиотека созданных пользователями расширений, которые могут добавить возможностей вашим историям. Авторы написали электронную книгу, призванную помочь писателям в освоении программы. Inform можно запускать на Linux, Mac и Windows. Linux версия использует фреймворк GNOME. Наиболее актуальный релиз Inform 7.0.
6.Ren’Py
Как и несколько ранее уже упомянутых вариантов, Ren’Py работает со своим собственным языком, но при этом предоставляет поддержку кода на скриптовом языке программирования Python. Ren’Py предлагает поддержку Linux, Windows и Mac. В игры, созданные на нем, так же можно играть на iOS и Android. Вы даже можете создать версию игры для загрузки в Steam. Большая часть Ren’Py лицензирована под MIT. На исходный код можно взглянуть здесь. Актуальная версия 6.99.12.
Интерактивная проза была первой попыткой программистов познать еще зарождавшийся мир компьютерных игр. Сегодня они до сих пор не потеряли актуальности, так как в них можно играть где угодно, да и средств для их создания достаточно.
Когда я был моложе, то прочел много книг из серии «Выбери свое приключение», так что мне понятна притягательность такого рода игр. Замечательно, что сегодня сделать что-то подобное не представляет особых сложностей.
Вы когда-нибудь играли в/создавали интерактивную прозу? Есть ли у вас любимые представители жанра? Может я не упомянул какие-то средства? Вы вольны оставить любые замечания, так как они будут очень полезны.
Если статья показалась вам интересной, пожалуйста, поделитесь ей с другими. Спасибо!
Как создать текстовую игру?
Бен Сервисс (Ben Serviss), программист, геймдизайнер и игровой продюсер из Нью-Йорка, в своем блоге описал этапы создания текстовой игры. Мы с его разрешения перевели текст и делимся им с вами.
Сочинять тексты — сложно. Сочинять тексты для интерактивной игры со множеством вариантов ответов — еще сложнее.
Умеете грамотно построить фразу? Отлично. Постройте семь. При этом каждая должна быть хорошо написана, подходить трем разным персонажам и встраиваться в четыре разных контекста. Сочинять сюжет и диалоги к нелинейной текстовой игре — означает упражняться в упорстве, изворотливости и трудолюбии.
Скажем, у вас есть описание текстовой игры. Вы знаете, о чем она, кто главные персонажи, какие основные события происходят в каждой главе и что за способности есть у игрока. Все составные части игры у вас на руках. Время начать писать — но вы в ступоре. Как написать историю, в которой может случиться что угодно? С чего вообще начать?
Я недавно выпустил свою первую полноценную текстовую игру для Choice of Games под названием The Last Monster Master (в ней примерно 250 000 (!) слов). В процессе я пришел к определенным базовым схемам, — они помогли написать игру глава за главой. Я использовал отличный (и бесплатный) Chat Mapper, чтобы создать каждую нелинейную главу. Затем я перевел окончательный вариант текста в ChoiceScript, собственный язык программирования Choice of Games, удобный для создания текстовых игр.
Скриншот из игры The Last Monster Master
Я упростил процесс, разбив работу над каждой главой на шесть этапов. В Chat Mapper есть очень удобная функция — она позволяет присваивать свой цвет каждому текстовому блоку. Я использовал эту фичу, чтобы отслеживать ключевые моменты работы с текстом, — изменял цвет каждый раз, как заканчивал этап (это можно увидеть на приведенных ниже скриншотах)
Этап 1. Текстовые заготовки (без цветового маркера)
На первом этапе нужно создать общую структуру главы. Не пишите настоящие диалоги или описания, — вместо этого используйте текстовые заготовки, чтобы обозначить, кто и что скажет, когда он это скажет и какие будут возможности выбора у игрока.
Если возникают сюжетные ответвления, которые зависят от статуса игрока или от других условий, обозначьте этот статус или условия в вопросах и опишите варианты ответа в самых простых выражениях. Не нужно переживать о внутренней логике. Это придет позже.
На этом этапе избегайте чрезмерных правок (или вообще любых правок, — если получится). Главная цель — описать структуру главы так, чтобы это было читабельно. Когда вы закончите, у вас должна получиться карта того, над чем вы потом будете работать — в первом приближении.
В приведенной ниже схеме из The Last Monster Master один из монстров игрока застрял в дереве во время атаки. Игрок может использовать телепатию или навык чтения языка тела, чтобы помочь монстру отразить атаку, или подбежать и помочь напрямую.
Этап 2. Ревизия текстовых заготовок (цвет — желтый)
На этом этапе сконцентрируйтесь на проверке того, что уже создали. Пока что вас должно волновать только то, как расположены диалоги — не переживайте насчет грамотности или красоты текста, поскольку все, что вы написали, еще не раз может подвергнуться переделке.
Нужно в первую очередь искать варианты выбора, которые не имеют смысла или противоречат сюжету, спорные повороты и тупиковые сюжетные ветки, которые не связаны с основной историей.
Затем убедитесь, что в получившейся схеме задействованы все варианты статуса игрока и его возможностей, которые вы планировали использовать в данной главе. Если вы не применили все, что намеревались, — либо пересмотрите первоначальный план и добавьте дополнительные опции, либо оставьте себе напоминание задействовать эти возможности в будущих главах.
Этап 3. Текст в первом приближении (цвет — оранжевый)
Теперь, когда структура игры улучшена и реорганизована, можно наконец-то заняться тем самым текстом, который увидит игрок. Этот этап — не особенно сложный, но и тут важно не терять из вида конечную цель.
Не заботьтесь о том, что не имеет отношения непосредственно к тексту. На этом этапе вас не должны волновать варианты выбора, структура этапов и так далее. Именно эта часть самая интересная — и она же отнимает больше всего времени.
Этап 4. Проверка текста (цвет — фиолетовый)
Выжили после того, как написали целую главу? Отлично! Дальше все пойдет быстрее. Включаем режим беспощадного редактора.
Прочитайте написанный вами текст. Будьте безжалостны. Проверьте все, что относится к тесту — грамматику, пунктуацию, будьте точны в выборе слов, описании персонажей или мест и так далее. Повторюсь: сосредоточьтесь на тексте. Заставьте его зазвучать.
Этап 5. Варианты (цвет — голубой)
Со структурой разобрались, текст выглядит пристойно. Теперь пройдитесь по всей главе еще раз. Ищите все места, где возникает вариативность, особенно те, где меняется статус игрока или где от него зависит поворот сюжета. Возможно, на этом этапе придется добавить варианты взаимодействия с уникальными артефактами, персонажами, появляющимися только один раз — и так далее.
Оцените повороты сюжета с точки зрения их уместности и влияния на игровой баланс.
Если заведете отдельный документ, в котором отражено, насколько статус игрока задействован в главе или в важном сюжетном повороте, — это вам здорово поможет.
Например, если сила игрока должна быть на уровне в 45 единиц, чтобы вышибить деревянную дверь в четвертой главе, то логично, что в шестой главе ему понадобится 65 единиц, чтобы выбить металлическую дверь (то есть, соответственно, статус реквизитов должен расти вместе со статусом игрока).
Этап 6. Экспорт и игровая логика (цвет — зеленый)
Время поместить почти готовую главу в программу, которую вы используете непосредственно для разработки игры. К счастью, Chat Mapper экспортирует файлы в формате XML, JSON, Excel и Rich Text, — что дает вам возможность выбирать. В случае с The Last Monster Master я просто скопировал каждый ключевой элемент в файл ChoiceScript, видоизменив их по мере необходимости.
Если вам необходимо дописать игровую логику, то нужно начать это делать сразу, как только вы вставите текст в игру. К счастью, поскольку вы уже решили, что, когда и где произойдет, создание каждого отдельного скрипта происходит отдельно от основного контента, — что упрощает решение проблемы.
Другие методы
Представленный вариант — не единственный подходящий для создания нелинейных текстовых игр, однако в случае с моим проектом он сработал. В зависимости от того, какого стиля разработки вы придерживаетесь и тех программ, которые вы используете, можно попробовать экспортировать текст в игру на более ранних этапах — чтобы в нее можно было сыграть как можно раньше. Добавлю, скрипты для Chat Mapper можно писать с помощью Lua, — а значит, игровую логику можно задавать прямо в программе.
Вне зависимости от того, что вы выберете, выполняйте по одной задаче за раз, хвалите себя за каждый пройденный этап и старайтесь записывать в процессе, что можно улучшить. Разобраться с нелинейным сюжетом не так-то просто — почему бы и из этого не сделать игру?