В рамках подготовки к Месяцу шпагата и написания национальных романов я работал над относительно небольшой тестовой историей, чтобы получить мои морские ноги для шпагата 2. Процесс был морально утомительным… но конечные результаты были замечательными.

Шпагат 2?

Twine — это веб-/настольное приложение, созданное для создания собственной интерактивной фантастики (например, истории выбери свое приключение) и вывода ее в один HTML-файл. Вывод является автономным, исполняемым сам по себе для просмотра в вашем браузере или может быть размещен в виде статической веб-страницы на любом веб-сервере. Twine существует около семи лет и превратился в Twine 2, надежный, универсальный движок, достойный использования в любом тексто-ориентированном проекте интерактивной фантастики.

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

В мельчайших подробностях

Когда я использовал Twine со снеговиком для создания истории, я думал, что это будут сплошные улыбки. «Я знаю, как писать JavaScript, я знаю HTML/CSS, без проблем!» Как обычно, дерзость была моей первой ошибкой.

Давайте сделаем небольшой рассказ? В редакторе Twine вы сначала выбираете «Снеговика» из форматов по умолчанию, щелкнув заголовок своей истории, а затем нажав «Изменить формат истории». Затем вы должны ввести что-то вроде следующего в первом проходе по умолчанию, чтобы начать:

There's paths on the left and right. 
[[Go left]] 
[[Go right]]

Легко, верно? Приведенный выше код выведет это в редакторе…

…и это в браузере:

Не слишком сложно. Затем в редакторе вы дважды щелкаете по вновь созданным отрывкам, которые соответствуют сделанным вами ссылкам, редактируете их, идете и идете, и в конечном итоге вы получаете целую историю:

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

  • Наличие ссылки выхода закрывает вкладку при нажатии (не идеально)
  • Переход к следующему прохождению через скрипт (подробнее об этом позже)
  • и ... это все, насколько я знаю

Хотя линии могут быть полезны в качестве обзора соединения, они имеют тенденцию загромождать редактор и не могут быть отключены. Не веселое время. Но! После того, как вы завершили что-то подобное, все это того стоит. Нажмите здесь, чтобы увидеть, как этот пример выглядит в дикой природе. Чем красивее вы хотите стать, тем больше вы должны понимать. Се ля ви, нет?

Копать глубже

Создание чего-то более сложного, чем то, что я только что показал, — это не прогулка по парку с другими форматами.

Различия форматов

Формат по умолчанию (Harlowe) слишком ограничен в том, что он может делать, поскольку вы ограничены предоставленными макросами. Если они подходят для вашего варианта использования (а в большинстве случаев так и будет), то, во что бы то ни стало, действуйте. Это будет означать, что вам придется думать в Harlowe при написании сценариев, если вы привыкли думать в JavaScript, и это будет слишком раздражающим для некоторых (включая меня).

Второй предоставленный формат (SugarCube) слишком простой английский, на мой вкус, и оставляет странные пробелы в окончательной публикации без видимой причины, если не отформатирован абсолютно идеально и жестко, недостаток, разделяемый Харлоу. Мало того, SugarCube основан на синтаксисе TiddlyWiki для форматирования прозы, что для меня слишком нетрадиционно.

Третий предоставленный формат Snowman использует краткую систему шаблонов на основе Underscore.js для кода, позволяющую простое объявление и вызов функций или переменных с помощью обычных соглашений JavaScript. Все без каких-либо странных пробелов! Возможно, лучше всего то, что прозаический синтаксис для Snowman — это Markdown! Все, что находится за пределами скобок подчеркивания, анализируется с помощью Markdown Markdown перед обработкой с помощью Twine, создавая такие вещи, как ссылки, которые вы ожидаете увидеть.

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

Харлоу:

(if: $checkpointName is "leave")[ 
"Well then. Where did we leave off? Oh yes, you're not among the living anymore." 
] 
(else:)[ 
"Alright. There's a lot you don't know about me, or this place. Or why you're invisible to everyone but me. So, let's keep things simple: I'm a medium. You're dead." 
] 
(if: $checkpointName is "stand")[ 
The force holding you in place lifts completely. You feel that you are able to move again. 
] 
[[You're taken aback.|surprised at dead]] 
[[You quietly await more information.|quietly wait]] 
(if: $checkpointName is not "leave")[ 
[[You get up and leave without another word.|leave]] 
]

Кубик сахара:

<< if story.checkpointName eq "leave" >> 
"Well then. Where did we leave off? Oh yes, you're not among the living anymore." 
<< else >> 
"Alright. There's a lot you don't know about me, or this place. Or why you're invisible to everyone but me. So, let's keep things simple: I'm a medium. You're dead." 
<< /if >> 
<< if story.checkpointName eq "stand" >> 
The force holding you in place lifts completely. You feel that you are able to move again. 
<< /if >> 
[[You're taken aback.|surprised at dead]] 
[[You quietly await more information.|quietly wait]] 
<< if story.checkpointName not eq "leave" >> 
[[You get up and leave without another word.|leave]] 
<< /if >>

Снеговик:

<% if (story.checkpointName == "leave") { %> 
"Well then. Where did we leave off? Oh yes, you're not among the living anymore." 
<% } else { %> 
"Alright. There's a lot you don't know about me, or this place. Or why you're invisible to everyone but me. So, let's keep things simple: I'm a medium. You're dead." 
<% } %> 
<% if (story.checkpointName == "stand") { %> 
The force holding you in place lifts completely. You feel that you are able to move again. 
<% } %> 
[[You're taken aback.|surprised at dead]] 
[[You quietly await more information.|quietly wait]] 
<% if (story.checkpointName != "leave") { %> 
[[You get up and leave without another word.|leave]] 
<% } %>

Если какой-либо из приведенных выше синтаксисов неверен, пожалуйста, сообщите мне об этом в комментариях.

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

Рассмотрим отрывок в моем примере, отрендеренном в Harlowe (с использованием режима отладки, чтобы показать проблемы):

по сравнению со Snowman (режим отладки не отображается, так как отладка выполняется с помощью инструментов в браузере):

В Harlowe несовпадающие части условных выражений остаются в макете, как и строки разметки Harlowe. Если вы просматриваете его без режима отладки, весь не-Harlowe текст остается на месте, как вы видите выше, со странными пробелами. Это, как и следовало ожидать, создает проблему, когда вы хотите скрыть части текста от пользователя, чтобы он не подозревал, что на самом деле там есть какой-либо текст. С помощью Snowman любой скрипт анализируется, не оставляя разметки в макете; сценарии отодвинуты на задний план как JavaScript. Это поведение, которое я ожидаю встретить для синтаксиса сценария истории, такого как этот. Это позволяет мне формировать исходную структуру в наиболее удобной для меня форме, но не дает пользователю знать, что перед ним есть что-то кроме истории. А+.

Интерактивность/Шаблонирование

У вас уже есть несколько отрывков, и вы хотите сделать их еще больше необычными, не так ли? Вы можете начать с добавления интерактивности в историю и действительно сделать ее своей. Если вы знаете, как манипулировать DOM или получать значения из входных данных HTML, вы можете использовать эти навыки в игре с помощью встроенного в Twine jQuery. Snowman помогает с шаблонами на основе Underscore.js, показывая в следующем источнике отрывок с выбором пола (с некоторыми пояснениями в комментариях):

/* 
Using <%= %> instead of just <% %> to surround code lets you render the value of the contained variable outright. Perfect for when you set your player's name in one passage and then want to retrieve it for showing later. 
*/ 
Assured that "<%= story.state.yourName %>" is your name, the blanks begin to refill in your mind as you slowly remember your identity. The next thing you struggle with is remembering how you preferred to be addressed: 
/* 
Notice the use of bare html for links here. Compared to Twine's link syntax, this lets you use actions on click as shown below. This technique is cross-format. 
*/ 
<a onclick='story.state.setHe()'>Him/his.</a> 
<a onclick='story.state.setShe()'>Her/hers.</a> 
<a onclick='story.state.setThey()'>They/theirs.</a> 
<a onclick='story.state.setIt()'>It/its.</a> 
/* 
Code within a template block is executed on load, so these functions are set before the player even starts reading. Each function sets the pronouns variable to be an array of pronouns, and stores it in the story.state object. Then, the start2 passage is navigated to. Connecting passages using script like that prevents connection lines from being drawn in the editor view. 
*/ 
<% 
story.state.setHe = function (){ 
  story.state.pronouns = ["he","him","his","his","he's"];
  story.state.cPronouns = ["He","Him","His","His","He's"]; 
  story.show('start2'); 
}
story.state.setShe = function (){ 
  story.state.pronouns = ["she","her","her","hers","she's"]; 
  story.state.cPronouns = ["She","Her","Her","Hers","She's"]; 
  story.show('start2'); 
}
story.state.setThey = function (){ 
  story.state.pronouns = ["they","them","their","theirs","they're"]; 
  story.state.cPronouns = ["They","Them","Their","Theirs","They're"]; 
  story.show('start2'); 
}
story.state.setIt = function (){ 
  story.state.pronouns = ["it","it","its","its","it's"]; 
  story.state.cPronouns = ["It","It","Its","Its","It's"];   
  story.show('start2'); 
} 
%>

Выход:

По сути, при нажатии на одну из этих ссылок происходят две вещи:

  • Переменные для всей игры устанавливаются и добавляются к объекту story.state, который содержит все, что должно быть доступно для истории в целом для легкого доступа или повторного объявления позже.
  • Затем рассказ переходит к следующему отрывку.

Выглядит немного многословно в исходном коде, но таким образом у вас есть полный контроль над тем, что делается в каждом добавляемом вами взаимодействии. Кроме того, если вы хотите реализовать этот выбор пола на протяжении всей истории, вы можете напрямую вызывать эти массивы pronouns так, как был вызван story.state.yourName. Теперь, когда они определены, вы можете даже отбросить часть story.state и сократить ее до s.

Таким образом...

"<%= s.cPronouns[2] %> name is <%= s.yourName %>, why not say hi?"

…выполнил бы…

«Его зовут Ноэль, почему бы не поздороваться?»

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

«Переверни страницу, чтобы узнать!»

За последнюю неделю или две изучения Twine я пришел к выводу, что я лишь коснулся поверхности возможностей Twine и Snowman. Благодаря сочетанию прямого CSS в Twine, чистого JS со Snowman и тщательному рассмотрению HTML-структуры Twine, все возможно для преданных и увлеченных. Любой, кто готов запачкать руки основами веб-технологий, будет щедро вознагражден в виде точного контроля, чистого вывода и широко открытого мира возможностей для своей интерактивной фантастики. Даже если вы не хотите так глубоко углубляться в веб-код, другие форматы историй могут завести вас очень далеко и позволят проделать большую работу.

Я оставляю вам список ресурсов, которые я нашел полезными в этих начинаниях как для себя, так и для других энтузиастов Twine:

  • Twine wiki — исчерпывающая база знаний обо всем, что связано с Twine, от макросов до информации о форматировании и часто задаваемых вопросов.
  • Шпагатные форумы — Для тех случаев, когда документы вас подводят, а вы рвете на себе волосы.
  • phiolme.la — Если вы не хотите платить за веб-хостинг для своей игры на Twine, но у вас есть аккаунт в Twitter, не ищите дальше.
  • Учебники Dan Cox’s Twine 2 — информативный набор обучающих видеороликов, в которых рассказывается об использовании множества различных методов создания игр Twine, в том числе о том, как создавать определенные типы игр, такие как классическая пошаговая Candy Box 2.
  • Depression Quest — отличный пример того, что Twine умеет не только текстом и прозой.

Ах да, если вы хотите увидеть Невидимку, историю, из которой я взял примеры формата, вы можете щелкнуть здесь. Это продолжается и будет продолжаться какое-то время, пока я сосредоточусь на предстоящем джеме Twine/NaNoWriMo. Моя запись пока будет называться Точки останова и будет отслеживаться на сайте NaNoWriMo.

Всем приятного письма!

Первоначально опубликовано на сайте blog.noelquiles.com 28 октября 2016 г.