На примере создания детской игры с загадками
И вновь приветствую всех! Пока продолжение прошлого поста, посвященное основам построения сюжета, еще в процессе написания, я попробую максимально доступно описать методы ветвления сюжета на примере детской игры с загадками (и, возможно, не самой лучшей графикой — не могу же я весь контент показать до релиза?).
Эта статья посвящена техническим моментам реализации новеллы при помощи инструментов движка RenPy, в частности — вариативности сюжетных линий.
В комментариях к прошлой записи несколько раз прозвучал вопрос о том, как реализована параллельность сюжета в новелле Spiritual Cavern, которая уже обзавелась собственной группой на Facebook.
Итак, для примера мы создадим крайне простую новеллу, в которой игрок должен отгадывать загадки кубика чтобы вместе с ним пойти на прогулку.
Спойлер: создание новеллы с графикой и написанием кода заняло 20 минут.
Графика: персонаж и фон
Какая новелла может обойтись без действующих лиц? Подготовим нашего персонажа, который будет загадывать загадки:
События происходят не посреди пустоты, потому нам потребуется фон:
Простейший сюжет
Подготовив материалы, мы можем приступить к составлению сюжета — в нашем примере он будет очень простым:
Суть сюжета очень проста: игрок трижды отвечает на вопросы, в зависимости от его ответа меняется настроение кубика. Кроме того, при каждом правильном ответе мы увеличиваем счетчик «Ответы», от которого в последствии зависит концовка игры: если был дан хоть 1
Итак, приступим. Я не буду описывать полный процесс написания кода в RenPy, так как уроков наэту тему довольно много. Но уделю отдельное внимание тем функциям, которые отвечают за ветвление сюжета.
Написание кода игры
Не пугайтесь, если показанные ниже примеры кода покажутся Вам сложными, или раньше у Вас не было опыта в работе с подобными редакторами — ниже описана структура любой графической новеллы в терминах языка RenPy, а также назначение каждой команды.
Кроме того, при создании нового проекта RenPy создает не пустой файл, а стандартную сцену, которая может быть основой для Ваших первых работ.
Основными конструкциями в RenPy являются:
- label имя_метки — место в коде, к которому в последствии можно перейти при помощи команды jump имя_метки
- scene — команда загрузки фонового изображения из папки images созданного проекта. Важно знать: в случае смены фона требуется заново ввести команду по выводу изображения персонажа.
- show — отобразить картинку (чаще всего — персонажа) поверх существующего фона.
- say — фраза, произносимая персонажем. Чаще всего используется в следующих форматах:Вариант первый: «автор» «фраза» — здесь мы явно указываем, кто говорит фразу и как эта фраза звучит.Однако, для удобства пользователя есть возможность упростить свою жизнь, заранее указав имя автора.Для этого перед меткой начала игры применяется следующая конструкция:define anna = Character(«Anna:»)В дальнейшем достаточно написать anna «фраза», что будет воспринято системой как «Anna:» «фраза»Важно понимать, что нет прямой связи между показываемой картинкой (show) и автором фразы — кроме той, которая формируется у игрока в процессе игры.
- menu — выбор игрока, в зависимости от которого происходит выполнение соответствующего кода, будь то простая фраза либо переход к конкретной метке.
Итак, что же происходит в первом фрагменте кода?
1) мы выводим на экран сцену «bg 1» из папки images нашего проекта
2) от имени игрока (define char = Character(«Я:») перед label start) выводим фразу «Интересно, где же кубик?»
3) плавно (with dissolve) выводим на экран изображение «cube wow»
4) от имени кубика (строка define e = Character(«Кубик:») перед label start) выводим фразу «А вот он я!»
5) после обмена фразами мы переходим к новой для нас команде — menu, отвечающей за выбор игрока и реакцию игры на этот выбор.
Ничего сложного, согласитесь? Требуется лишь следовать правилам составления сцены и корректно вводить команды.
У тех, кто был внимателен при прочтении нашего «сценария», может возникнуть вопрос: а как нам определить, хорошо или плохо заканчивается игра? Всё верно, при помощи команды menu мы можемпредоставить выбор игроку, а в данной ситуации требуется противоположное — сделать выбор на основе данных самой программы.
С этой целью мы добавляем в игру типичный для программ элемент -переменную под названием «answers» и устанавливаем её значение равным нулю.
В дальнейшем, при выборе игроком положительного (правильного) ответа, мы увеличиваем значение этой переменной следующим образом:
Таким образом, после трех вопросов её значение находится в диапазоне от 0 (если не было дано ни одного правильного ответа) до 3 (если все ответы были правильными).
Будем добрыми, и поставим простое условие: отгадал хоть одну загадку — добро пожаловать на прогулку. Для этого нам потребуется конструкция if-else, «если-иначе». Ниже — пример её применения в нашей новелле:
Итоги
Итак, мы создали новеллу, в которой присутствует как локальная (не влияющая на концовку), так и глобальная (определяющая финал истории) вариативность.
Было ли это сложно? Нет — у человека, ранее не работавшего с движком, подобная задача займет не более, чем два часа. Поиграть с Кубиком из нашего примера можно на ПК:
И на Android устройствах:
Стоит помнить: реальные проекты, геймплей которых длится от получаса и более, состоят из десятков, а порой — и сотен сцен, складывающихся порой в довольно запутанную структуру из параллельных сюжетных линий, локальных вариаций и сложных диалогов.
К примеру, в Spiritual Cavern на текущий момент присутствует порядка 1200 строк кода, реализующих первые шесть сцен игры — и, если бы не грамотная организация процесса, я давно потерялся бы в этих дебрях.
А о том, как стоит и не стоит организовывать процесс воплощения новеллы мы поговорим в следующей статье, которая выйдет в Воскресенье. Всем удачи, и приятных выходных!
Руководство для начинающих
Добро пожаловать в Руководство для начинающих по использованию движка визуальных новелл Ren’Py. Здесь мы, на примере создания с нуля игры Знакомство с Визуальными Новеллами, рассмотрим процесс написания простой визуальной новеллы.
Начало работы
Запустим центр управления Ren’Py. Для этого нужно запустить renpy.exe (renpy.sh для пользователей Линукса) из папки, в которую распакован архив с ним. В левом верхнем углу белым будет написано название активного проекта. Справа — ряд кнопок, поделённый на две секции:
- секцию «Текущий проект» («This project» в английской версии — Команды для текущего проекта), состоящую из команд
- «Запуск» («Launch» — запустить проект на исполнение),
- «Править скрипт» («Edit Script» — Редактировать код проекта),
- «Сменить тему» («Change Theme» — Сменить цветовую схему оформления проекта),
- «Папка игры» («Game Directory» — Открыть папку текущего проекта (всё, относящееся к проекту — код, ресурсы — должно лежать в ней))
- «Инструменты» («Tools» — Вспомогательные средства);
- секцию «Сменить проект», состоящую из команд
- «Выбрать проект» («Change Project» — Смена активного проекта, позволяет переключаться между созданными проектами. В поставку Ren’Py изначально входят проекты demo (демонстрация возможностей движка) и the_question (простейшая законченная визуальная новелла)) и
- «Новый проект» («New Project» — Создание нового проекта).
Мы хотим создать новую игру, потому выберем «Новый проект». ЦУ попросит выбрать шаблон проекта — выбираем template за неимением других опций. Затем ЦУ попросит ввести название проекта. Вводим. Следом ЦУ попросит выбрать цветовую схему оформления проекта. На вкус и цвет. В результате вернёмся в главное меню ЦУ с только что созданным проектом в качестве активного (обратите внимание на левый верхний угол). Можно запустить его кнопкой «Запуск», чтобы полюбоваться на интерфейс. Но лучше приступить к собственно написанию игры.
Где, что и как писать
Приступим к собственно написанию игры, для чего выберем «Править скрипт». В результате файлы с кодом проекта откроются для редактирования во входящем в поставку Ren’Py редакторе SciTE. Редактор многовкладочный, поэтому трём имеющимся изначально (от шаблона) файлам «script.rpy», «options.rpy» и «localize.rpy» будут соответствовать три одноимённые вкладки. Нам в данный момент нужна та, что озаглавлена «script.rpy».
Мы увидим следующее: Самая первая строчка — это комментарий. Комментарием является любое сочетание символов, предварённое символом # и завершающееся с концом строчки. Комментарии не воспринимаются обработчиком и никак не отражаются в игре. Используются они для оставления каких-то пометок-пояснений себе. Или для временного исключения из обработки какой-либо строки.
Начиная со строчки 3 идёт блок init.
Отступы и блоки — основа основ
Здесь надо пояснить базовую особенность языка Ren’Py: для определения контекста, к которому принадлежит строчка, используются отступы (конкретнее — сочетания из четырёх пробелов). Все строки, имеющие одинаковый (или больший) отступ, принадлежат одному контексту, или блоку. К примеру:
init:
# Эта строка — в блоке init
# Так же, как и эта.
python:
# Эта строка и в блоке python, и в блоке init.
# То есть, в подобной ситуации невозможно быть в блоке python
# но не быть в блоке init.
# эта строка всё еще в блоке init, но уже не в блоке python.
# так что можно сказать, что блок python «закрыт», т.к. туда больше не может попасть
# ни одна строка. Но мы можем продолжать добавлять строки в блок init.
# Эта строка НЕ в блоке init!
Зачем нужен блок init?
В любом проекте есть информация, такая как используемые изображения и персонажи, которая должна быть определенна до собственно начала истории. Такая информация объявляется в блоке init. Он может находиться в коде где угодно, но обычно его помещают в самое начало. Этот блок начинается со строчки:
init:
записанной без отступа, и все строчки с отступом, следующие за ней, принадлежат блоку init. Строчек этих может быть любое количество. Заканчивается блок первой же строкой БЕЗ отступа. И эта строка, конечно же, блоку init уже не принадлежит.
Метки.
Дальше обратим внимание на строчку 12:
label start:
Это так называемая метка. Метки позволяют давать названия нужным местам текста, дабы потом можно было переместиться к ним откуда угодно (но об этом позже). Меткой является строчка без отступа, начинающаяся с ключевого слова label и заканчивающаяся двоеточием. Слово, следующее за label — название метки. Название метки не должно содержать пробелов! (Но, как известно, настоящие_программисты_пробелом_не_пользуются ;-)). Также, название метки должно быть уникальным в рамках всего проекта! Существует специальная метка, необходимая в любом коде Ren’Py: label start: . Она обозначает место начала текста игры.
Поехали!
Можно приступать к работе. Для начала удалим блок init и всё в блоке label start, чтобы не мешалось. Теперь нам нужно заставить Ren’Py сказать первую реплику. Для этого в блоке label start напишем просто:
"Интернациональный Колледж Цифровых Искусств."
(Не забываем про отступ!) Подобная конструкция называется «высказывание» (say statement). Ren’Py автоматически осуществляет перевод строки, если выведенное высказыванием в текстовое окно сообщение в одну строчку не вмещается. Но если есть нужда перейти на новую строку в каком-то определённом месте, то в этом месте нужно поставить сочетание символов n. Вот так:
"Мне повезло, что я учусь здесь. nОсобенно, что на игровом направлении."
Каждое высказывание обновляет содержимое текстового окна.
Если в тексте высказывания необходимо использовать двойные кавычки » их необходимо предварить символом . Вот так:
"Сейчас по расписанию "Визуальные новеллы". Новый курс. Интересно, о чём же нам там поведают?"
Фоны.
Если сейчас сохранить изменения, запустить проект и выбрать «Начать игру», увидим этот текст в текстовом окне. На фоне чёрного экрана. Не особо хорошо, не правда ли? Что ж, добавим фоновый рисунок. Но для этого изображение, что послужит фоном, сначала нужно объявить в блоке init. Получим в итоге следующий скрипт:
init:
image bg uni = "uni.jpg"
label start:
"Интернациональный Колледж Цифровых Искусств."
"Мне повезло, что я учусь здесь. nОсобенно, что на игровом направлении."
"Сейчас по расписанию "Визуальные новеллы". Новый курс. Интересно, о чём же нам там поведают?"
Объявление изображения — вторая строчка. Сначала идёт ключевое слово image, затем псевдоним (внутреннее имя изображения), затем знак равно, затем имя файла с изображением, внутри двойных кавычек . Предполагается, что файл с изображением лежит в рабочей папке проекта (доступна по выбору «Game Directory» в ЦУ). Можно также завести отдельную папку для изображений, в рабочей папке проекта, но тогда имя этой папки нужно будет дописать перед именем файла. Например, если изображения лежат в подпапке Images рабочей папки проекта, объявление изображения будет вида:
image bg uni = "Images/uni.jpg"
Фоновые изображения должны быть того же размера, что и выбранное для игры разрешение. По умолчанию — 800х600 пикселей, наверное, самое удобное. Формат файла для фоновых изображений — JPEG или PNG. Теперь выведем это изображение в виде фона перед тем, как выводить текст. Для этого на следующей после label start строчке напишем (сдвинув высказывания на строчку вниз):
scene bg uni
Сначала идёт ключевое слово scene, затем псевдоним изображения, которое нужно использовать как фон. Смена фона на другой также производится этой командой. При применении команды в таком виде предыдущее фоновое изображение вместе со всеми прочими визуальными элементами немедленно заменяется на указанное в команде. Однако процесс перехода можно сопроводить эффектами. В Ren’Py есть ряд предопределенных эффектов, например fade («упрозрачнивает» старое изображение в чёрный фон за полсекунды, затем «упрозрачнивает» за полсекунды чёрный фон в новое изображение), dissolve («растворяет» старое изображение в новое за полсекунды) и pixellate (пикселизует за полсекунды старое изображение, затем за полсекунды распикселизует новое). Для применения эффекта надо только приписать к нужной команде вывода изображения ключевое слово with и название нужного эффекта. Проще это увидеть самому. Потому выведем этот фон с эффектом dissolve. А после высказываний сменим фон на другой с эффектом fade. Надо только не забыть объявить изображение в блоке init. Получим такой скрипт:
init:
image bg uni = "Images/uni.jpg"
image bg lecturehall = "Images/class.jpg"
label start:
scene bg uni with dissolve
"Интернациональный Колледж Цифровых Искусств."
"Мне повезло, что я учусь здесь. nОсобенно, что на игровом направлении."
"Сегодня начинается курс "Визуальные новеллы". Интересно, о чём же нам там поведают?".
scene bg lecturehall with fade
Украшаем текст.
Дальше хотелось бы, чтобы следующая реплика — мысленная речь героя — как-то выделялась. Например, вывелась курсивом. Нет ничего проще! Для подобной операции Ren’Py использует тэги, наподобие html, только с фигурными скобками вместо угловых. Так, текст, заключенный между тэгами {i} и {/i} будет курсивным, между {b} и {/b} — полужирным, а между {u} и {/u} — подчёркнутым. Также, тэги {size=<число>} … {/size} управляют размером заключённого в них текста (если <число> = число без знака, то заключённый в данные тэги текст будет размером в указанное число пикселей; если же <число> = число, предварённое знаком «+» или «-», то движок воспримет это как команду к увеличению или уменьшению размера шрифта для заключённого в теги текста на указанное число пикселей относительно размера по умолчанию). Наконец, текст, заключённый в теги {color=#rrggbb} и {/color}, будет изображён указанным цветом. #rrggbb — строка-идентификатор цвета формата RGB в виде стандартного шестнадцатеричного триплета. rr, gg и bb — соответственно интенсивности красной, зелёной и синей составляющей цвета. Могут принимать любое значение от 00 (нет этой составляющей цвета) до ff (255, максимум интенсивности). Так, #000000 = чёрный, #ffffff = белый, #ff0000 = ярко-красный, #0000ff = ярко-синий, а #аааа00 = ярко-жёлтый. Подобное представление цвета широко используется в Ren’Py, с ним нам ещё предстоит столкнуться. Важно: закрываются теги в порядке, обратном порядку открытия! Ладно, нам нужен был курсив. Потому пишем:
"{i}Преподаватель опаздывает.{/i}"
Кто сказал «Гав»?
Дальше идут простые высказывания, описывающие ситуацию — в зал вошла преподавательница. Но вот она обращается к нам, и в соответствующем высказывании неплохо было бы как-то её назвать, показывая, что реплика — от её имени. Поскольку имени её мы не знаем, обозначим её как «???». Для этого используется следующий формат высказывания:
"???" "Здравствуйте! Простите за эту задержку."
"???" "Я -- профессор Наталь, и я буду вести у вас курс "Визуальные Новеллы"."
Эти реплики выведутся со строкой «???» вверху текстового окна. Важно: если в первой строке (т.е. между первыми и вторыми двойными кавычками) используются русские буквы, то её необходимо предварить английской буквой ю («u»)! Так, если нужно вывести реплику главного героя — от первого лица — то высказывание будет выглядеть так:
u"Я" "Реплика!"
Вообще говоря, символом u следует предварять любую строку, содержащую символы кириллицы, но опыт показывает, что текст реплики в высказывании в подобном не нуждается.
Так, теперь, когда нам известно имя преподавателя, указывать его как «???» нельзя, а каждый раз набирать «Профессор Наталь» неудобно. Здесь на помощь приходят такие объекты Ren’Py, как «персонажи» (character object). Персонажи позволяют использовать в именных высказываниях вместо длинных имён короткие псевдонимы. Но сначала персонаж нужно объявить в блоке init. Делается это следующей строчкой:
$ eileen = Character(u'Эйлин')
Сначала идёт знак доллара, затем псевдоним персонажа, затем знак равно, ключевое слово Character и аргументы в скобках. В данном случае — имя персонажа (в кавычках), которое будет отображаться во всех его репликах. (Обратите внимание, поскольку имя персонажа дано кириллицей, его необходимо предварить символом u) Для облегчения написания кода псевдоним персонажа лучше делать как можно короче. Чаще всего имена персонажей выделяют цветом. Для этого нужно добавить в объявление персонажа аргумент color:
$ e = Character(u'Эйлин', color="#c8ffc8")
Также можно заставить все реплики этого персонажа выделяться определённым цветом. Для этого нужно добавить в объявление персонажа аргумент what_color:
$ e = Character(u'Эйлин', color="#c8ffc8", what_color="#c8ffc8")
Можно также автоматически применять теги ко всему тексту всех реплик персонажа. Для этого нужно добавить в объявление персонажа аргументы what_prefix со строкой открываемых тегов и what_suffix со строкой закрывающих тегов. Так, чтобы выделить всё, что скажет Эйлин жирным и курсивом, нужно записать:
$ e = Character(u'Эйлин', color="#c8ffc8", what_prefix = "{b}{i}", what_suffix = "{/i}{/b}")
Правда, лучше было бы это реализовать с помощью аргументов стиля:
$ e = Character(u'Эйлин', color="#c8ffc8", what_bold = True, what_italic = True)
Вообще, строка-значение аргумента what_prefix перед обработкой реплики приписывается движком к началу текста реплики, а строка-значение аргумента what_suffix — к концу. Персонажи ещё много чего могут, но мы сейчас ограничимся наиболее часто используемым минимумом:
$ p = Character(u'Профессор Наталь', color="#ff6666")
Теперь все высказывания вида
p "Прежде всего, что такое "визуальная новелла"?"
будут выводиться от имени профессора Наталь.
Портретное сходство.
Всё это хорошо, но неплохо было бы видеть профессора на экране, когда она что-либо говорит. Здесь в игру вступают изображения персонажей. Размером они обычно <~ четверть-треть ширины игрового окна>х<полная высота игрового окна> (т.е. если для игры выбрано разрешение 800х600, то изображение персонажа будет размером от 200х600 до 266х600). Также, вся область изображения, не занятая собственно рисунком персонажа, должна быть прозрачной! Выбранный формат файла для изображений персонажей — PNG. Объявляются изображения персонажей так же, как и фоновые изображения:
image prof norm = "prof_norm.png"
image prof smile = "prof_smile.png"
В подавляющем большинстве случаев для одного и того же персонажа нужно несколько изображений, с разными выражениями лица или в разной одежде. В данном случае применяются два изображения: с обычным выражением лица и с улыбкой. Можно заметить, что псевдонимы, использованные для этих изображений, совпадают первым словом. Это так называемый ярлык изображения (image tag). С его помощью удобно группировать изображения, а также скрывать любое из группы, независимо от того, какое именно сейчас на экране. Сообществом Ren’Py принято фоновые изображения отмечать ярлыком bg. Показывается изображение персонажа в игровом коде строчкой:
show prof norm
Сначала ключевое слово show, затем псевдоним изображения. Введённая в таком виде команда выведет изображение по центру игрового окна по горизонтали, нижний край изображения совпадёт с нижним краем окна. В Ren’Py есть предопределённые позиции для изображений: справа (at right) — правый край изображения совпадает с правым краем экрана; слева (at left) — левый край изображения совпадает с левым краем экрана; по центру (at center) — изображение отцентрировано горизонтально; за пределами экрана справа (игроку не видно) — at offscreenright; за пределами экрана слева (игроку не видно) — at offscreenleft. Во всех случаях нижний край изображения совпадает с нижним краем игрового окна. Чтобы показать изображение в нужной позиции, необходимо приписать название этой позиции к команде, выводящей нужное изображение, после псевдонима. Лучше всегда указывать позицию для вывода. Итак, чтобы вывести изображение профессора по центру, нужно написать:
show prof norm at center
Также, к изображениям персонажей тоже применимы эффекты, таким же образом, как и к фонам. То есть, приписыванием ключевого слова with и названия эффекта в конец команды вывода изображения (после указания позиции). Помимо эффектов появления можно показать изображение с эффектом выезда за полсекунды из-за края экрана: moveinright, moveinleft, moveintop, moveinbottom. Соответственно, справа, слева, сверху и снизу. Также есть эффект увеличения за полсекунды из точки: zoomin. Так, чтобы профессора по центру с выездом справа, нужно написать:
show prof norm at center with moveinright
Изображения без приписки эффекта выводятся мгновенно, то есть при последовательном выводе без эффектов изображений с одинаковым ярлыком игрок увидит только последнее. А с припиской — по одному, то есть в результате исполнения такого скрипта:
scene bg uni with fade
show prof norm with moveinleft
show prof smile with dissolve
сначала сменится фон с эффектом fade, затем слева въедет изображение профессора, а потом оно растворится в свою улыбающуюся версию. Можно сказать, они сформировали очередь, и пока одно изображение с эффектом не выведется, следующее за ним не начнёт показываться. Если, конечно, игрок не нажмёт на какую-нибудь кнопку, что прерывает все эффекты и заставляет движок сразу отобразить конечный результат. Если же нужно отобразить всю сцену, состоящую, скажем, из фона bg, изображения персонажа ааа слева и изображения персонажа bbb справа, с применением ко всей сцене сразу эффекта dissolve, то следует после команд на вывод изображений без эффектов написать строчку with dissolve:
scene bg
show aaa at left
show bbb at right
with dissolve
По историческим причинам это не одно и то же, что и:
scene bg
show aaa at left
show bbb at right with dissolve
Данный скрипт выведет фон и первое изображение персонажа моментально, затем второе изображение персонажа с эффектом dissolve.
Ren’Py следит за тем, что выведено, и при выводе нового изображения с тем же ярлыком, что и у уже находящегося на экране, старое изображение автоматически скрывается. Однако Ren’Py не следит за позициями, и поэтому при попытке вывести новое изображение в позицию, уже занятую изображением с другим ярлыком, новое изображение наложится на старое. Во избежание подобных эксцессов ненужные изображения следует скрывать. Делается это командой hide с ярлыком изображения, которое нужно скрыть, или же его полным псевдонимом. Так, чтобы немедленно скрыть любое изображение профессора, нужно использовать строчку:
hide prof
В команде hide также может быть использован эффект, любой кроме zoomin и группы moveinчто-то. Зато есть их эквиваленты: moveoutright, moveoutleft, moveouttop, moveoutbottom — убирающие изображение за полсекунды с экрана вправо, влево, вверх или вниз соответственно; и zoomout, уменьшающий за полсекунды целевое изображение в точку.
Выбери свою судьбу!
Ладно, пока это может подождать. Пойдём дальше. Профессор объясняет, что такое визуальная новелла. Вот, она останавливается, словно ожидая вопросов. Самое время игроку повлиять на ход новеллы. Но как? Самый часто используемый метод — меню. Перед игроком возникают несколько вариантов реакции (например, варианты реплики в разговоре, или варианты действия в игровой ситуации), игрок выбирает один, и от этого выбора зависит дальнейшее течение повествования. В Ren’Py меню реализуются так: Сначала идёт строчка
menu:
открывающая блок, т.е. все последующие строчки до конца меню идут с отступом на четыре пробела больше. Дальше может быть строчка-сообщение, которое будет находиться в текстовом окне, когда меню на экране. Это простое высказывание. Затем идут варианты меню — строки, заканчивающиеся двоеточием. Каждый вариант открывает свой блок, в котором записываются результаты выбора этого варианта. Например:
menu:
"Хорошая возможность задать вопрос." # Фраза, которая будет в текстовом окне
"А как это выглядит с точки зрения игрока?": # Пункт №1 меню.
"Я поднял руку, показывая, что у меня есть вопрос." # Результаты
<…>
"Ничего не спрашивать": # Пункт №2 меню.
pass # Результаты
Если реакции для какого-то пункта меню вообще не предусматривается, то есть данный пункт ничего не делает, в его блоке следует написать pass, как это сделано в примере с пунктом №2. Варианты могут быть любой длины, и их может быть любое число, главное, чтобы они все поместились на экране. Результаты выбора пункта меню также могут содержать любое число строк и состоять из любых команд, в том числе и из других меню.
А я помню…
Довольно часто возникает необходимость запоминать, какой выбор сделал игрок, дабы припомнить это ему позднее. Как в данном случае, если игрок задал вопрос о том, как визуальная новелла выглядит с точки зрения игрока, и профессор ему это объяснила, то когда она будет говорить про реализацию визуальных новелл, неплохо было бы, чтобы она заметила, что повторяется. Это можно сделать с помощью переменных. Надо завести логическую переменную (подобная переменная может принимать два состояния — истинно и ложно) и придать ей значение истинно, если вопрос задан (т.е. в результатах выбора варианта меню с вопросом) и ложно, если вопрос не задан. Ren’Py не требует предварительного объявления переменных, то есть их можно вводить просто по ходу скрипта. Но для удобства перед началом работы всем используемым переменным стоит присвоить начальные значения (скажем, ноль для цифровых, ложно для логических, хотя это сильно зависит от того, как эти переменные будут использоваться в дальнейшем). Это можно сделать сразу после метки старта, или вообще в блоке init (но лучше — после метки старта). Присваивается переменной значение так:
$ question_asked = False
Сначала знак доллара и пробел, затем имя переменной (одно слово, т.е. без пробелов) затем символ присвоения — знак равно, затем присваиваемое значение (в данном случае, False — «ложно»; «истинно» будет True). C цифровыми и строковыми переменными обращаются так же:
$ string_var = u"Это строка."
$ ppoints = 0
С помощью цифровых переменных организуются концовки, базирующиеся на очках. Скажем, если игрок к исходу новеллы набрал менее половины из возможных очков, его ждёт плохая концовка, если более половины, но не все, то хорошая, а если все возможные, то наилучшая. Или, концовка зависит от того, какая из нескольких переменных имеет наибольшее значение (Скажем, в переменных хранятся значения атрибутов — силы, ума и удачи. Если наибольшее значение имеет атрибут силы, то игрок стал чемпионом мира по тяжёлой атлетике. Если ум, то игрок получил Нобелевскую премию по всем наукам. Если же удача, то игрок выиграл в лотерею миллиард рублей. И ещё какие-нибудь концовки в случае ничьих).
В нашем случае мы воспользуемся логической переменной для отметки, был ли задан вопрос, и цифровой для хранения набранных игроком очков. Присвоим им начальные значения (False и 0 соответственно) в блоке init. В блоке результатов выбора пункта меню с вопросом присвоим логической переменной значение True (тогда если игрок выбрал другой пункт меню, логическая переменная останется с False). В этом же блоке заведём ещё меню (скажем, преподаватель спрашивает игрока, как он сам считает, каков ответ на его вопрос) и в блоке результатов пункта меню с правильным ответом увеличим значение цифровой переменной на единицу. Делается это следующей строчкой:
$ ppoints += 1
Знаки плюс-равно означают «прибавить к текущему значению данной переменной число, стоящее справа». Это может быть любое число, не только единица. Если нам нужно было бы уменьшить значение переменной, нужно было бы использовать вместо += знаки -= (минус-равно). А вот если… Позднее, когда профессор говорит о составляющих визуальной новеллы и повторяет сказанное в ответе на вопрос игрока, нам нужно проверить значение логической переменной и если её значение — «истинно», то вывести реплику вроде «Что я, впрочем, уже говорила.». Проверяются значения переменных конструкцией «Если-То-Иначе», которая выглядит так:
if <условие>:
e "Блок выполняющийся, если условие истинно."
else:
e "Блок выполняющийся, если условие ложно."
Если в случае, если условие ложно, делать ничего не нужно, то else со своим блоком просто не пишут.
Можно также создать цепочку проверок, каждая следующее из которых осуществляется, только если все предыдущие оказались ложны:
if <условие 1>:
e "Блок выполняющийся, если условие 1 истинно."
elif <условие 2>:
e "Блок выполняющийся, если условие 1 ложно"
e "а условие 2 истинно."
elif <условие 3>:
<...>
else:
e "Блок выполняющийся, если все условия ложны."
В качестве условия может выступать равенство значений (переменная == значение, или переменная1 == переменная2 (используются два знака равно), или неравенство (больше либо равно: «переменная >= значение»; строго больше: «переменная > значение»; меньше либо равно: «переменная <= значение»; строго меньше: «переменная < значение»). Условие может быть составным, т.е. состоять из нескольких элементарных (таких, как те, что были описаны только что), связанных между собой логическими операциями И (and или &&), ИЛИ (or или ||), Исключающее ИЛИ (xor). Также возможно использование операции логического отрицания (not). Также, в случае логических переменных вместо «имя_переменной == True» можно просто писать «имя_переменной» В нашем случае конструкция будет выглядеть так:
if question_asked:
p "Что я, впрочем, уже говорила."
Также, Ren’Py позволяет модифицировать состав меню в зависимости от значения переменных. Для этого в строчке нужного пункта меню после строки с текстом пункта, но до двоеточия нужно приписать if <условие>. Например, профессор снова делает паузу, и игрок вновь может задать вопрос. Создаём меню, один из пунктов которого — вопрос «какая из составляющих важнее», другой — «как визуальная новелла выглядит внешне», а третий — об интерактивности, но его можно задать, только если в первом меню был задан вопрос:
menu:
"Может, и правда, спросить?"
"Спросить, какая из составляющих важнее.":
"Я поднял руку, показывая, что у меня есть вопрос."
<…>
"Спросить о реализации визуальной новеллы.":
"Я поднял руку, показывая, что у меня есть вопрос."
<…>
"Спросить о её оговорке, связанной с интерактивностью." if gameplay_asked:
<…>
Заодно в блоке результатов первого или второго пункта во второй раз увеличим значение цифровой переменной на единицу.
Вызовите доктора!
Для пущего интереса вновь сделаем в одном из пунктов ещё одно меню. Но на этот раз не будем загромождать блок результатов пункта, а вынесем реализацию этого меню в другое место. И в нужный момент передадим туда управление, чтобы дальше новелла исполнялась с этого места кода. Для этого нужно во-первых обозначить нужное место меткой, а во-вторых перейти по этой метке. В Ren’Py возможно два варианта переходов: прыжок, когда управление просто передаётся на указанную метку и исполнение игры идёт с обозначенного меткой места, и вызов, когда управление передаётся на метку, а по окончании управление возвращается на строчку, следующую за вызовом. Нам, нужен именно вызов. Сначала пишем реализацию вынесенного куска скрипта, которую будем вызывать: после окончания меню, откуда будет идти вызов, пишем:
label submenu_priority:
<реализация>
return
Обратите внимание: Блок метки, в котором записана нужная нам реализация, нужно закончить ключевым словом return — эта команда и вернёт управление в точку вызова. Также, надо удостовериться, что обычным образом в этот блок игра никак не попадёт. Для этого как раз перед меткой submenu_priority сделаем конец игры. Осуществляется это той же командой return. Можно объяснить сей факт так: игра вызывается из главного меню и в конце возвращает управление туда. Теперь нужно выполнить сам вызов. Для этого в блоке результатов пункта меню, где надо осуществить вызов, пишем:
call submenu_priority
Всё!
Только, когда вы закончите писать скрипт, если используете вызовы, ОБЯЗАТЕЛЬНО запустите вспомогательный инструмент «Добавить From к Call’ам» из пункта «Инструменты» ЦУ Ren’Py! Без этого структура вызовов рискует не заработать в конечном варианте игры, что вы будете распространять.
Спой, светик, не стыдись…
Хм, если оставить всё как есть, конец у данной игры выйдет какой-то оборванный. Лучше сделаем так: После того, как игрок задал второй вопрос (первый, если в первом меню он выбрал пункт «Ничего не спрашивать»), звенит звонок, преподаватель отпускает всех и идёт определение концовки. Но как заставить звонок прозвенеть? Логично будет проиграть звуковой файл. Ren’Py делает это по команде:
play
sound "имя_файла_со_звуком.wav"
Звук должен быть в файле формата WAW и лежать в рабочей папке проекта. (Конечно, можно завести в рабочей папке отдельную подпапку для звуков, так же, как и для картинок, только тогда надо будет добавлять имя папки перед именем файла). Данная команда проигрывает указанный звуковой файл единожды. При этом если до этого проигрывался ещё какой-либо звуковой файл, его проигрывание прерывается. Во время проигрывания звука игра не останавливается. Поэтому, если по задумке во время воспроизведения звука больше ничего не должно происходить, стоит воспользоваться командой паузы:
$ renpy.pause (2.0)
Сначала знак доллара, затем ключевое слово renpy.pause, потом в скобках длительность паузы в секундах. Правда, при нажатии игроком на какую-либо управляющую клавишу или кнопку мыши пауза прерывается, как и любой эффект. Также Ren’Py умеет воспроизводить фоновую музыку. Это делается следующим образом:
play music " имя_файла_с_музыкой.ogg "
Музыка может быть в формате OGG, MP3 или MIDI и лежать там же, где могут лежать все остальные ресурсы. Данная команда проигрывает указанный музыкальный файл постоянно, то есть при достижении конца воспроизведение начинается сначала. При этом если до этого проигрывался ещё какой-либо звуковой файл, его проигрывание прерывается. Если нужно остановить проигрывание музыки, применяется команда:
stop
music
Аналогично, если нужно остановить проигрывание звукового файла, применяется команда:
stop sound
Ко всем командам вывода звуковой информации может быть приписано fadeout <значение>. В этом случае воспроизведение завершается спадом громкости за <значение> секунд.
Всё хорошо, что хорошо кончается.
Всё, что осталось, это определить, какую концовку заработал игрок. Поскольку мы считали достижения игрока в очках и максимум, достижимый в данном примере — 2, то определение сводится к цепочке проверок, начиная с максимума. Также, неплохо был бы вывести сообщение об обретенной концовке не в тестовом окне, а, скажем, по центру экрана. Это достигается путём использования специального персонажа centered. Собственно код, определяющий концовку, будет выглядеть так:
if ppoints == 2:
show prof smile
p "И, я с нетерпением жду продолжения занятия с вами!"
scene black with fade
centered "Поздравляем, вы пришли к лучшему окончанию!"
elif ppoints > 0:
p "Надеюсь, вам было интересно."
scene black with fade
centered "Поздравляем, вы пришли к хорошему окончанию."
else:
scene black with fade
centered "Нормальное окончание."
return
Ветвление как форма размножения.
Всё равно как-то коротковато игра выходит, даже для примера. Добавим-ка ещё одну ветку, со своим центральным персонажем. Причём, чтобы не загромождать редактор, вынесем её в отдельный файл. А в дальнейшем нам не придётся делать фактически никаких лишних действий для доступа к ней. А всё потому, что область видимости Ren’Py — весь проект, все его файлы. Сначала сделаем небольшие приготовления — объявим в блоке init нужные изображения (в нашем случае yuki norm и yuki smile) и персонажа. Теперь создадим новый файл (File > New в редакторе — откроется новая вкладка, озаглавленная Untitled) и сохраним его под каким-нибудь именем и с расширением rpy (File > Save as.. , ввести имя — например script2.rpy — в нужное поле). Теперь можно работать с ним. Прежде всего, нужно создать метку, по которой будут попадать в эту ветвь (Скажем, yuki_branch) . Теперь, в первом файле со скриптом создадим ситуацию, позволяющую туда попасть. Пусть во время рассказа преподавателя герой слышит со стороны соседа смешок и, если решит посмотреть, в чём дело, попадёт в новую ветку, а если проигнорирует, останется в первой. Реализуется, естественно, с помощью меню:
"Слева от меня кто-то чуть слышно усмехнулся"
menu:
"Взглянуть.":
jump yuki_branch
"Не отвлекаться":
pass
Собственно переход осуществляется командой jump <имя_метки>. Это как раз и есть прыжок, о котором я говорил ранее. Напомню, при нём управление просто передаётся на указанную метку, и исполнение игры идёт с обозначенного меткой места. Положим, герой бросает взгляд на соседа (соседку, вообще-то). Можно это отобразить появлением на экране её образа вдобавок к изображению профессора:
show prof norm at right
show yuki norm at left
Заодно это автоматически уберёт образ преподавателя из центра, где он находился раньше, вправо.
Одновременно на экране может находиться сколь угодно много изображений персонажей, только при большом их числе многие будут перекрываться. Впрочем, обычно на экране присутствует не более трёх, в трёх предопределённых позициях. Вот поэтому изображения персонажей делают не шире трети экрана.
Герой с соседкой разговариваются, и всё внимание героя сосредотачивается на ней. Здорово было бы изобразить это сдвигом изображения профессора за границы экрана, а соседки — в центр. Можно реализовать это, скрыв изображение профессора с эффектом moveoutright, и затем показав изображение соседки в центре:
hide prof with moveoutright
show yuki norm at center
Но лучше было бы всё это совершить единым движением. Этого можно добиться, показав изображение профессора вне экрана справа, изображение соседки — по центру, и применив к ним эффект move. Он находит изменяющие своё положение изображения и сдвигает за полсекунды их из старого положения в новое. Нужный кусок кода выглядит так:
show prof norm at offscreenright
show yuki norm at center
with move
hide prof
Нужно не забывать скрывать ненужные изображения.
По мере разговора игроку будет предлагаться реагировать на высказывания собеседницы, и, если реакция её не устроит, лицезреть прекращение ветки, плохие окончания и конец игры. Если же все реакции окажутся подходящими, игрок придёт к хорошей концовке. Подобное построение сюжета носит название линейного с препятствиями (в отличие от вариативного у ветки из первого файла скрипта, где разные реакции игрока пускали сюжет по различным линиям в рамках единого сюжета, или ветвящегося, если брать эту игру в целом, где сюжет в зависимости от решений игрока идёт по практически независимым веткам).
Конец игры в данной ветке можно обставить обычным return’ом, но, вероятно, лучше сначала сделать титры. А ещё лучше, чтобы титры предваряли завершение и первой ветки. Для этого разместим титры (обычные высказывания с прославляющим создателя и всё, с помощью чего он создал подобный шедевр, текстом) в блоке метки (скажем, credits), помещённом в первом файле после определения концовки, но до завершающего игру return’a. А в концовках ветви из второго файла поместим команды прыжка по этой метке. Тогда первая ветка попадёт в титры своим ходом (ведь прерывающий ход игры return стоит после блока с титрами), а вторая ветка — прыгнув по метке титров. И конец игры будет происходить в одном месте.
Завершающие штрихи.
Ну вот, работа со скриптом игры завершена. Теперь не мешало бы подправить разные мелочи, вроде заголовка окна или фона главного меню. За это и многое другое отвечает файл options.rpy. Все опции снабжены подробным комментарием. Первое, что нужно сделать, это поменять config.developer = True на config.developer = False. Это запретит пользователю применять приёмы, предназначенные для облегчения жизни разработчика, такие как быстрая перезагрузка игры по нажатию Shift+R или вывод значений всех переменных по нажатию Shift+D. Следующее, это установить нужный заголовок. Находим config.window_title и вписываем в кавычки нужное название. В нашем случае строчка будет выглядеть так:
config.window_title = u"Знакомство с Визуальными Новеллами"
Затем нужно установить фон для главного меню и внутриигрового меню (доступно во время игры по нажатию Esc). Для этого присваиваем строки с именами нужных файлов переменным mm_root и gm_root. В нашем примере:
mm_root = "Images/uni.jpg"
gm_root = "Images/uni.jpg"
Дальше стоит задать, будет ли игра иметь звуковое, музыкальное и голосовое сопровождение, присвоив значения True, если да, или False, если нет, следующим переменным: config.has_sound (звук), config.has_music (музыка) и config.has_voice (голос). Вообще, в этом блоке есть ещё и переменные, отвечающие за звуки интерфейса, но по умолчанию они закомменчены. Самая интересная — это config.main_menu_music, управляющая музыкой, которая должна играть в главном меню.
С помощью этой группы переменных можно поменять положение главного меню:
# style.mm_menu_frame.xpos = 0.5
# style.mm_menu_frame.xanchor = 0.5
# style.mm_menu_frame.ypos = 0.75
# style.mm_menu_frame.yanchor = 0.5
Если, конечно их раскомментить (убрать решётку).
xpos и ypos определяют точку на экране, а xanchor и yanchor — точку собственно главного меню, которая будет соответствовать точке привязки на экране. Если значения — целые числа, то это расстояние в пикселях от верхнего левого угла экрана и главного меню соответственно. Если же, как по умолчанию, десятичных дроби, то они воспринимаются как доли ширины и высоты экрана и главного меню соответственно.
Напоследок необходимо сказать ещё о двух переменных. Только их значения, по уму, следует устанавливать в самом начале работы над игрой. Ибо они контролируют разрешение экрана игры, от которого зависят размеры игровых изображений. config.screen_width устанавливает ширину экрана, а config.screen_height — высоту. Важно: стоит придерживаться стандартных расширений, иначе при переключении в полноэкранный режим могут быть глюки. По умолчанию установлено:
config.screen_width = 800
config.screen_height = 600
Вот, в сущности, и всё. Теперь осталось только хорошо протестировать игру, отловить все дырки в игровой логике и просто очепятки, и можно готовить к выпуску. Также необходимо не забыть запустить из пункта «Инструменты» ЦУ «Добавить From к Call’ам» («Add From to Calls»), если в игре используются вызовы (call) и «Проверить скрипт (Lint)», обнаруживающий шероховатости, могущие плохо сказаться на работе игры на некоторых платформах.
Когда игра готова идти «на золото», обязательно нужно удалить со всем содержимым папку saves в рабочей папке проекта (saves, кстати, генерируется каждый раз при запуске игры на исполнение, если её нет). Стоит также подготовить файлы license.txt (c пользовательским соглашением) и readme.txt (со всей прочей информацией, что вы хотели бы сообщить пользователю — аннотация к игре, управление, благодарности и приветы…). И ещё решить, будет ли проводиться прятанье ресурсов от конечного пользователя. Ren’Py позволяет убрать из открытого доступа изображения и «зашифровать» скрипт игры. Последнее делается при каждом запуске проекта на исполнение, в виде сборки любого .rpy-файла в его аналог расширением .rpyc. Эти файлы достаточны для работы игры, так что если не хотите, чтобы ваш скрипт кто-то видел, можете удалить после финального запуска проекта все файлы .rpy вместе с папкой saves. Изображения архивируются в один файл командой «Архивировать файлы» («Archive Files») пункта «Инструменты» ЦУ Ren’Py. Кстати, в случае архивации смысла складировать изображения в отдельную папку нет.
В любом случае, для отправки «на золото» служит команда «Выпуск игры» («Build Distributions») из всё того же пункта «Инструменты». Сначала игру ещё раз проверят Lint’ом, после чего спросят, хотим ли мы продолжать (если Lint что-то нашёл, стоит выбрать «Нет» и исправить; иначе можно смело жать «Да»). Затем последует риторический вопрос «Хотите ли вы, чтобы Ren’Py создал распространяемые архивы для Windows, Linux x86 и MacOS X» (опять «Да»). Потом спросят имя игры (сразу введено имя проекта и в подсказке предлагается дописать версию) — вводим что надо, затем жмём Enter. Наконец спросят, файлы каких расширений вы не хотите включать в финальную версию — можно смело жать Enter ничего не меняя. Теперь нужно немного подождать, и можно забирать готовые архивы из папки Ren’Py. Поздравляю, создание визуальной новеллы завершено.
Как написать впечатляющую новеллу, чтобы её хотелось пройти на разные концовки?
Написание цепляющей визуальной новеллы непростая задача для писателя вне зависимости от его опыта.
В отличие от книги, нужно уметь с первых строк зацепить внимание читателя, а объёмные описания атмосферы передать с помощью визуальной и музыкальной составляющей игры.
При написании сюжета, любому писателю приятно узнать, если читатель историю не только завершил, но и прошёл на несколько концовок, поделился ими со своими друзьями. Впоследствии аудитория вашей новеллы увеличится. Это показывает, что новелла зацепила читателя.
Но как сделать новеллу настолько увлекательной для чтения?
Погружайте в историю
Начало вашей новеллы — самая важная часть работы. Она создаёт антураж, задаёт ритм повествования и знакомит с сюжетом. У неё главная роль — зацепить внимание читателя. Если он не увидит что-то интересное, то перестанет читать, отвлечётся на окружающие факторы. Даже если ваш сценарий гениален, игрок может попросту отвлечься и забыть почему начал читать.
Рассказывая о сеттинге и героях, начните играть на человеческих эмоциях. Есть несколько простых способов как это сделать:
- Задайте загадку.
Всем свойственно любопытство в той или иной степени. Начиная рассказывать о сеттинге, надавите на него. Вы можете задать читателю интересную загадку в рамках своего сеттинга, зацепить таинственным героем, поступком или происшествием. Вызовите вопросы у читателя, а за поиском ответов он сам устремится и поневоле погрузится в происходящее.
Чтобы суметь использовать этот приём, посмотрите на ваш сценарий, структуру новеллы, и подумайте: какой интересный поворот можно вытащить в начало? Что вызвало бы любопытство у меня или моих друзей?
Вы можете намеренно создать странную «дыру» в сюжете, но помните, что в развязке (или развязках, если у вас несколько концовок) вы должны дать ответы на все вопросы и закрыть все дыры. Иначе любопытство превратится в разочарование.
- Пощекочите нервы.
Создайте угрозу для персонажа или его вселенной. Особенно хорошо этот писательский приём применим в жанре ужасов, детективах.
Вызовите тревогу, страх, непонимание, чтобы читатель задумался, мол, «если такое происходит в начале, то что будет дальше?»
Тщательно подумайте какое событие хотите вынести, чтобы не проспойлерить сюжет. Также дальнейшие происшествия должны сохранить градус напряжения, лучше если они его повысят.
- Уроните главную проблему.
Популярный приём, используемый в сценариях фильмов, сериалах, аниме. Вы начинаете с центральной проблемы, конфликта, чтобы читатель задал вопросы: «как это произошло?» и “как быть дальше?” Следом возвращаетесь к событиям как такое могло произойти, порционно даёте ответы и интригуете развязкой.
- Истина или ложь?
Суть заключается в том, что персонаж говорит одно, а совершает противоположный поступок. Допустим, герой объясняется в любви к женщине, а следом выстреливает. После этого начинается повествование. Не самый миролюбивый пример, но у читателя точно появляются вопросы.
Конечно, не стоит сразу же давать ответ, сохраните интригу до следующего крючка или развязки. Достойно раскройте этот момент в сюжете, объясните истинные причины произошедшего, мотивацию героя.
- Сломайте ожидания.
Создайте небольшую рутину, чтобы читатель подумал, что предвидит следующий шаг героя, а затем сделайте внезапный поворот. Главный герой может быть добропорядочным гражданином, совершать справедливые поступки, но вдруг делает неожиданное исключение, исходя из своей мотивации или биографии. Его поступок сдвигает сюжет с мёртвой точки и вызывает вопрос читателя «Почему он так поступил?» раскрыть который необходимо во время повествования
Какие выборы захватят внимание читателя?
Выборы отличают вашу новеллу от книги и это является преимуществом. Опираясь на них, вы даёте читателю принять решение как поведёт себя персонаж и какое влияние окажет на сюжет.
Алексей Скребнёв, автор новелл для BestNovels:
Выборы в истории должны испытывать вашего героя (не важно, речь о сражении, моральных решениях, поисках ответов или чём-то ещё). И если герой уже понравился игроку, то теперь вы сможете заставить его сопереживать своему альтер-эго.
Могу посоветовать основное внимание уделить как самой истории (она должна быть яркой, интриговать, обладать живыми персонажами), так и её интерактивности. У игрока должны быть логичные выборы и развилки. Каждая ветка, пусть и тупиковая (ведущая к проигрышу), должна быть ценна эмоциями и информацией. Расширять вашу историю.
Этой интерактивности должно быть достаточно много, мы же создаем игру, а не пишем рассказ. Благо, инструментов платформа предоставляет достаточно.
Вызываемые эмоции и интерес игрока — это и есть самое важное, залог успеха вашей истории. Создавайте их так, чтобы даже в случае проигрыша, читающий новеллу видел новую грань истории, сопереживал персонажу, за которого «играет».
Антон Пашков, автор новелл для BestNovels:
Я стараюсь делать выборы по ходу истории, чтобы играя, человек неосознанно собирал собственную модель поведения, которая ему приятна.
Если брать «Кровавую семью», то в зависимости от предпочтений игрока, главный герой либо устал от жизни и хочет быть с женой, либо хитрый и властный стратег.
В хорошо придуманных выборах читатель отражает свою позицию, мнение, догадки. Ключевое — оказывает влияние на сюжет, иначе очень обидно принимать множество решений, которые по итогу ни на что не повлияют.
Хорошие выборы в новеллах:
-
исходят из контекста сцены
-
влияют на развитие сюжета
-
имеют последствия
-
раскрывают модель поведения близкую игроку
Плохие выборы бессмысленно водят по локациям, где не даётся ни одной зацепки, ничего не происходит.
Например, персонаж находится в зале гостинной, он детектив, решает обыскать место. Есть выбор — выйти в коридор, в спальную комнату, в столовую. Игрок заходит в выбранное место. Снова даётся выбор обыскать местность, везде — пусто. Предлагается выбор других локаций доступных для поиска. Снова пусто, никаких значимых предметов, зацепок. Лишь спустя время находится ключ. Читатель тратит время, а автор тянет хронометраж новеллы.
Знайте чувство меры в выборах. Они должны разнообразить процесс прохождения новеллы и не занимать весь сюжет. При огромном количестве выборов и вариантов вы приложите множество усилий, расписывая. Игрок может растеряться, выбрать один или два варианта, а дальше идти по сюжету, т.к не хочет потерять нить повествования.
Сделайте интересные концовки
Когда занимаетесь прописыванием финалов, уделите особое внимание всем выборам, которые вы предложили своему читателю. При прочтении финала он должен понимать, что всё могло быть иначе, если бы он принял другое решение.
Модель поведение, отношение к окружающим, действия по ходу истории — все последствия должны присутствовать в финале.
Читателю хочет узнать какое влияние на сюжет он оказал.
Если вы упустите хотя бы одно последствий выборов в новелле, это окажет негативное влияние на работу, а весь вложенный труд останется недооценённым.
Выводы
Помните, что ключ к созданию захватывающей новеллы — единое целое из интересного сторителлинга, выборов и финала. Когда вы даёте ответы на все вопросы читателя и он осознает в какое русло повернул сюжет новеллы своими решениями, он захочет перепройти её снова.
Надеемся, эта статья поможет вам в создании вашей визуальной новеллы. Возможно, именно она возглавит топ. Напомним, что наши истории выходят только на русском языке, а создать свою новеллу вы можете абсолютно бесплатно. Мы очень ждём именно вашу историю!
Do you have a story idea that you’d like to turn into a novel? How about adding visual appeal and interactivity to that novel?
A Visual Novel might be the game genre you are looking for. And this tutorial is here to help set you up in 10 minutes, with minimal coding experience required. Let’s get started!
We will be using the Ren’Py Visual Novel Engine, which is built on top of Python 2.7. As Python itself is a scripting language, you will be able to «script» your visual novel project in Ren’Py.
Since the arrival of Python 3, Python 2.7 has been sunsetted and is no longer actively maintained. Rest assured — Python 2.7 has all the features we need to create an awesome visual novel. Moreover, the newest release of Ren’Py, Ren’Py SDK 7.4, provides a compatibility mode for Python 3. The developers also express the hope of integrating fully with Python 3 in the next release, Ren’Py 8.0.
How to Download and Set up Ren’Py
You can download the latest version of Ren’Py for your operating system (Windows, Mac, Linux) on its official site.
Once you have downloaded and installed Ren’Py, you may open the Ren’Py launcher, select one of the starter projects (Tutorial, The Question) on the left, and click on Launch Project.
Check out the Tutorial to get a sense of the full power of this engine, or The Question to see a very basic visual novel that you can make in 10 minutes.
How to Create a New Project in Ren’Py
Let’s create a new project. I called mine Forest Hike🌲, featuring a simple scene where two kids explore a forest trail.
Pay attention to the resolution you choose: The default is 1280 x 720. When we add images, our background images should also conform to these dimensions.
How to Run the Boilerplate Project
Launch the boilerplate project. Press Start from the main menu. After two brief lines of dialogue, the script ends and we are brought back to the main menu.
How to Script Our Project
Let’s start scripting our game based on the boilerplate.
Text Editors like Sublime Text and Atom both have syntax highlighting for Ren’Py scripts ending in .rpy
. Check out this Sublime Text package and this Atom package.
The two lines of dialogue we saw are located in script.rpy
. Open that file and its content should look like the following. Just like in Python, lines that start with #
are comments and won’t be evaluated as part of the Ren’Py script. The comments and the code below are pretty self-explanatory.
# Declare characters used by this game
define e = Character("Eileen")
# The game starts here
label start:
# Show a background
scene bg room
# This shows a character sprite
show eileen happy
# These display lines of dialogue.
e "You've created a new Ren'Py game."
e "Once you add a story, pictures, and music, you can release it to the world!"
# This ends the game.
return
The label
is used for control flow, which we will cover in the following section.
The return
statement on the last line is what brought us back to the main menu.
How to Declare Characters and Add Dialogues
Let’s replace the boilerplate character declaration and dialogues with those from our story. Here is how my story goes:
define laura = Character('Laura')
define tom = Character('Tom')
label start:
laura "Wait up, Tom!"
laura "Tom!"
laura "I said wait up!"
laura "...Tom?"
tom "Boo!"
laura "Yikes... not again."
tom "Are you scared?"
laura "Not at all."
laura "Running off like that is dangerous, you know."
laura "We are in the forest. We could get lost."
tom "Okay okay mom. I won't do it again."
return
How to Add Images and Transitions
If you aren’t an artist yourself, you may consider looking for assets in the creative commons domain. itch.io, a marketplace for indie games, is a great place to look for assets.
I found this set of character sprites for my project. For the background images, I simply applied artistic filters to creative commons pictures, giving real-life pictures a nice watercolor aesthetic.
I put all my images inside game/images
. Note that it’s okay to use whitespaces in the image file names.
Then we add to script.rpy
those images as well as some transitions. Ren’Py applies transitions when it sees keywords like with
and at
. You can read more about transitions in Ren’Py’s ATL (Animation and Transition Language) docs.
label start:
scene bg forest day with fade
show laura angry
laura "Wait up, Tom!"
laura "Tom!"
laura "I said wait up!"
laura "...Tom?"
hide laura
scene bg forest day with vpunch
show tom happy at right with moveinbottom
tom "Boo!"
show laura angry at left with moveinleft
laura "Yikes... not again."
tom "Are you scared?"
laura "Not at all."
show laura sad
laura "Running off like that is dangerous, you know."
laura "We are in the forest. We could get lost."
tom "Okay okay mom. I won't do it again."
return
With the addition of visuals, our story is coming together nicely.
How to Add Choices
A game with different branches and endings more than doubles the fun. Adding a choice menu to a Ren’Py script is simple:
menu:
"Which way should we go?"
"Left":
tom "Let's check out the trail on the left!"
"Right":
tom "Right is always the right way to go!"
How to Use Python Variables and Control Flow
We may define Python variables in a Ren’Py script and alter the flow of our story depending on their values. Python statements start with a $
or an indented python:
block.
Adding variables to our previous choice menu:
menu:
"Which way should we go?"
"Left":
tom "Let's check out the trail on the left!"
$ is_lost = True
"Right":
tom "Right is always the right way to go!"
$ is_lost = False
scene bg forest noon with Dissolve(3.0)
scene bg forest dusk with Dissolve(3.0)
show laura sad at left with moveinleft
laura "It's getting late. Are you sure we aren't lost?"
if is_lost:
show tom sad at right with moveinleft
tom "I hope not, but I have a bad feeling about this."
else:
show tom happy at right with moveinleft
tom "We are fine. Look! There's the end of the trail."
tom "I'm the best scout around."
See the end of this post for my handcrafted resources for working with Python in Ren’Py.
How to Play Music
According to Ren’Py’s Audio docs, playing music and sound effects is as easy as the following:
play music "mozart.ogg"
play sound "woof.mp3"
How to Save and Load the Game
Ren’Py has done all the heavy lifting for us and has a built-in save and load system.
Other Customization You Can Do
Currently in our dialogue, the entire line of text is displayed at once, instead of character by character. We may change the variable preference.text_cps
(CPS stands for character per second) in options.rpy
like this.
default preferences.text_cps = 20
There is even more that we can customize in gui.rpy
(GUI stands for Graphic User Interface, which includes the textbox and menu choice items that we have seen) or screens.rpy
.
What Else is Ren’Py Capable of?
Ren’Py’s capability extends way beyond displaying text and images. I may go as far as to say that Ren’Py is about as capable and versatile as Python itself.
With the Pygame module, it is possible to create complex mini games in Ren’Py. I myself have created and open-sourced a few mini games, including a chess engine that integrates with the Stockfish chess AI as well as a rhythm game engine that automatically generates the beat map for any music file.
Ren’Py Chess Game 2.0 by r3dhummingbird
PvP and PvC Chess Game Powered by Stockfish in Ren’Py
Studio Madeleine Chaiitch.io
Ren’Py Rhythm Game by r3dhummingbird
Play a rhythm game in your Ren’Py Visual Novel game!
itch.io
Resources
This tutorial should help get you started with Ren’Py. It’s always useful to refer to the official documentation as you learn the more advanced features to add buzz to your project.
I’ve also created some course material to help you brush up on Python fundamentals and their capabilities in Ren’Py scripts.
RuolinZheng08/python-for-renpy-dev
[Udemy Course Material] Python Basics for Ren’Py Developers — RuolinZheng08/python-for-renpy-dev
RuolinZheng08GitHub
Python Basics for Ren’Py Developers
Learn the Python basics to build complex components like an inventory system or a minigame in your Ren’Py project
Udemy
Check out my course intro video on YouTube:
Thanks for reading and have fun telling your story!
Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started
Do you have a story idea that you’d like to turn into a novel? How about adding visual appeal and interactivity to that novel?
A Visual Novel might be the game genre you are looking for. And this tutorial is here to help set you up in 10 minutes, with minimal coding experience required. Let’s get started!
We will be using the Ren’Py Visual Novel Engine, which is built on top of Python 2.7. As Python itself is a scripting language, you will be able to «script» your visual novel project in Ren’Py.
Since the arrival of Python 3, Python 2.7 has been sunsetted and is no longer actively maintained. Rest assured — Python 2.7 has all the features we need to create an awesome visual novel. Moreover, the newest release of Ren’Py, Ren’Py SDK 7.4, provides a compatibility mode for Python 3. The developers also express the hope of integrating fully with Python 3 in the next release, Ren’Py 8.0.
How to Download and Set up Ren’Py
You can download the latest version of Ren’Py for your operating system (Windows, Mac, Linux) on its official site.
Once you have downloaded and installed Ren’Py, you may open the Ren’Py launcher, select one of the starter projects (Tutorial, The Question) on the left, and click on Launch Project.
Check out the Tutorial to get a sense of the full power of this engine, or The Question to see a very basic visual novel that you can make in 10 minutes.
How to Create a New Project in Ren’Py
Let’s create a new project. I called mine Forest Hike🌲, featuring a simple scene where two kids explore a forest trail.
Pay attention to the resolution you choose: The default is 1280 x 720. When we add images, our background images should also conform to these dimensions.
How to Run the Boilerplate Project
Launch the boilerplate project. Press Start from the main menu. After two brief lines of dialogue, the script ends and we are brought back to the main menu.
How to Script Our Project
Let’s start scripting our game based on the boilerplate.
Text Editors like Sublime Text and Atom both have syntax highlighting for Ren’Py scripts ending in .rpy
. Check out this Sublime Text package and this Atom package.
The two lines of dialogue we saw are located in script.rpy
. Open that file and its content should look like the following. Just like in Python, lines that start with #
are comments and won’t be evaluated as part of the Ren’Py script. The comments and the code below are pretty self-explanatory.
# Declare characters used by this game
define e = Character("Eileen")
# The game starts here
label start:
# Show a background
scene bg room
# This shows a character sprite
show eileen happy
# These display lines of dialogue.
e "You've created a new Ren'Py game."
e "Once you add a story, pictures, and music, you can release it to the world!"
# This ends the game.
return
The label
is used for control flow, which we will cover in the following section.
The return
statement on the last line is what brought us back to the main menu.
How to Declare Characters and Add Dialogues
Let’s replace the boilerplate character declaration and dialogues with those from our story. Here is how my story goes:
define laura = Character('Laura')
define tom = Character('Tom')
label start:
laura "Wait up, Tom!"
laura "Tom!"
laura "I said wait up!"
laura "...Tom?"
tom "Boo!"
laura "Yikes... not again."
tom "Are you scared?"
laura "Not at all."
laura "Running off like that is dangerous, you know."
laura "We are in the forest. We could get lost."
tom "Okay okay mom. I won't do it again."
return
How to Add Images and Transitions
If you aren’t an artist yourself, you may consider looking for assets in the creative commons domain. itch.io, a marketplace for indie games, is a great place to look for assets.
I found this set of character sprites for my project. For the background images, I simply applied artistic filters to creative commons pictures, giving real-life pictures a nice watercolor aesthetic.
I put all my images inside game/images
. Note that it’s okay to use whitespaces in the image file names.
Then we add to script.rpy
those images as well as some transitions. Ren’Py applies transitions when it sees keywords like with
and at
. You can read more about transitions in Ren’Py’s ATL (Animation and Transition Language) docs.
label start:
scene bg forest day with fade
show laura angry
laura "Wait up, Tom!"
laura "Tom!"
laura "I said wait up!"
laura "...Tom?"
hide laura
scene bg forest day with vpunch
show tom happy at right with moveinbottom
tom "Boo!"
show laura angry at left with moveinleft
laura "Yikes... not again."
tom "Are you scared?"
laura "Not at all."
show laura sad
laura "Running off like that is dangerous, you know."
laura "We are in the forest. We could get lost."
tom "Okay okay mom. I won't do it again."
return
With the addition of visuals, our story is coming together nicely.
How to Add Choices
A game with different branches and endings more than doubles the fun. Adding a choice menu to a Ren’Py script is simple:
menu:
"Which way should we go?"
"Left":
tom "Let's check out the trail on the left!"
"Right":
tom "Right is always the right way to go!"
How to Use Python Variables and Control Flow
We may define Python variables in a Ren’Py script and alter the flow of our story depending on their values. Python statements start with a $
or an indented python:
block.
Adding variables to our previous choice menu:
menu:
"Which way should we go?"
"Left":
tom "Let's check out the trail on the left!"
$ is_lost = True
"Right":
tom "Right is always the right way to go!"
$ is_lost = False
scene bg forest noon with Dissolve(3.0)
scene bg forest dusk with Dissolve(3.0)
show laura sad at left with moveinleft
laura "It's getting late. Are you sure we aren't lost?"
if is_lost:
show tom sad at right with moveinleft
tom "I hope not, but I have a bad feeling about this."
else:
show tom happy at right with moveinleft
tom "We are fine. Look! There's the end of the trail."
tom "I'm the best scout around."
See the end of this post for my handcrafted resources for working with Python in Ren’Py.
How to Play Music
According to Ren’Py’s Audio docs, playing music and sound effects is as easy as the following:
play music "mozart.ogg"
play sound "woof.mp3"
How to Save and Load the Game
Ren’Py has done all the heavy lifting for us and has a built-in save and load system.
Other Customization You Can Do
Currently in our dialogue, the entire line of text is displayed at once, instead of character by character. We may change the variable preference.text_cps
(CPS stands for character per second) in options.rpy
like this.
default preferences.text_cps = 20
There is even more that we can customize in gui.rpy
(GUI stands for Graphic User Interface, which includes the textbox and menu choice items that we have seen) or screens.rpy
.
What Else is Ren’Py Capable of?
Ren’Py’s capability extends way beyond displaying text and images. I may go as far as to say that Ren’Py is about as capable and versatile as Python itself.
With the Pygame module, it is possible to create complex mini games in Ren’Py. I myself have created and open-sourced a few mini games, including a chess engine that integrates with the Stockfish chess AI as well as a rhythm game engine that automatically generates the beat map for any music file.
Ren’Py Chess Game 2.0 by r3dhummingbird
PvP and PvC Chess Game Powered by Stockfish in Ren’Py
Studio Madeleine Chaiitch.io
Ren’Py Rhythm Game by r3dhummingbird
Play a rhythm game in your Ren’Py Visual Novel game!
itch.io
Resources
This tutorial should help get you started with Ren’Py. It’s always useful to refer to the official documentation as you learn the more advanced features to add buzz to your project.
I’ve also created some course material to help you brush up on Python fundamentals and their capabilities in Ren’Py scripts.
RuolinZheng08/python-for-renpy-dev
[Udemy Course Material] Python Basics for Ren’Py Developers — RuolinZheng08/python-for-renpy-dev
RuolinZheng08GitHub
Python Basics for Ren’Py Developers
Learn the Python basics to build complex components like an inventory system or a minigame in your Ren’Py project
Udemy
Check out my course intro video on YouTube:
Thanks for reading and have fun telling your story!
Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started
#набор_кураторов_и_лидеров
#конкурс_актива
#плиз_в_подборку
Содержание:
__ __ __ __ __ __ __ __
| •Идеи
| •Персонажи
| •Выбор движка
| •Графика
| •Аудио
★•°•.•°•★•°•.•°•★
Идеи
Начните с выбора жанра. Подумайте, будет ли ваша новелла ужастиком, или может симулятором свиданий с хентай сценами? От жанра зависит целевая аудитория новеллы (возраст, пол, люди, принадлежащие к каким-либо обществам и т.п.) Лично я делаю новеллу для подростков и детей моего возраста (11-16 лет). Выбрал я жанр, как вы поняли квест, психология и повседневность. Так же немного хоррора.
Далее придумайте, о чём повествует ваша новелла? Придумайте сеттинг, в котором будут происходить действия. Продумайте его тщательно, ибо музыка, графика и прочие элементы игры подстраиваются под сеттинг, чтобы создать атмосферу.
Когда будет достаточно идей, приступайте к персонажам.
Совет: предлагаю начать с новеллы по мотивам какого-либо произведения, например, книги, фанфика, аниме, манги, даже театральной пьесы! Это поможет не морочиться с придумкой некоторых элементов, что удобно, если вы делаете новеллу в первый раз.
★•°•.•°•★•°•.•°•★
Персонажи
Как вы наверное заметили, персонажи в новеллах очень разнообразны и контрастируют между собой. Например беспечная Ульяна и ответственная Славя, или робкая Лена и смелая, бойкая Алиса. Придумайте побольше самых разных персонажей, особенно, если это симулятор свиданийг, или эроге. На выбор но в таком случае будет несколько персонажей, среди которых он может выбрать кого-то и выйти на его рут. Можно также добавить популярных клише, типо родственницы, лоли, лучшая тян в классе, староста тян, можете даже трапа туда закинуть) Главное, чтобы персонажи были раскрытыми и реагировали на ситуацию по разному.
★•°•.•°•★•°•.•°•★
Сценарий
Вам нужно хорошо продумать сценарий, прежде чем приступать к программированию. Продумайте, какой будует концовка, или концовки, с чего всё началось, как героя можно привести от начала до этих концовок. Как другие персонажи реагируют на выбор гг. Всё это очень важно для сюжета.
★•°•.•°•★•°•.•°•★
Выбор движка
На свете есть множество удобных движков для создания визуальных новелл, правда большинство из них японские. Вот некоторые движки, которые наиболее известны в интернете:
PONScripter / ONSlaugh
Blade Engine
KiriKiri Adventure Game System
Novelty
Ren’Py.
Большинство из движков сложны в освоении, поэтому сегодня я расскажу вам про последний. Ren’Py — движок для создания визуальных новелл и прочих похожих игр, написанный разработчиком Py’Tom на языке программирования Python. Программирование осуществляется максимально просто, движок поддерживает управление переменными, постоянными переменными, возможностью добавлять картинки, аудио и некоторые другие игровые элементы. Движок поддерживает многие языки, включая русский. В движок так-же встроен пример новеллы и новелла — туториал. Лично я тоже использую данный движок. Достаточно посмотреть пару туториалов на Ютубе и уже начать что-то понимать в программировании на ренпае.
Факт: Такие новеллы, как Тук тук литературный клуб, или Бесконечное лето были сделаны на движке ренпай.
★•°•.•°•★•°•.•°•★
Графика
Как наверное уже многие заметили, почти ВСЕ новеллы имеют анимешную графику. Поэтому, если хотите иметь прямо очень новельную графику, вам придется научиться рисовать японские мультики. Или же пойти по моим стопам и отклониться от традииции. Я например рисую новеллу в своём стиле (векторный мультяшный лайн-арт мышкой :3).
Итак, что вам придется отрисовывать? Все игровые элементы, элементы меню, настроек, самой игры на всём её протяжении. Всех персонажей, по нескольким эмоциям на каждого. Также множество фонов. Вобщем, работы много, но графика есть графика.
Кстати, я рисую в sai2.
Процесс рисования Знайки, персонажа моей новеллы в моём мультяшно векторном стиле.
★•°•.•°•★•°•.•°•★
Аудио
Да, конечно написать самому музыку, когда тебе на ухо наступил медведь проблематично, но если ты знаешь базовые вещи, например строения тонического, субдоминантного и доминантнтого аккорда, или из чего состоит простейший бит. Есть множество удобных программ, таких как caustic, fl studio и подобные. Лично я пользуюсь именно ими)
Вам нужно написать большое количество треков, на разные моменты игры. Они должны быть разными по характеру, чтобы их можно было везде распихать. Звуки можно брать с сайтов с бесплатными звуками (не поверите, но все звуки из БЛ взяты с таких сайтов).
Итак, мы быстро пробежалась по основным моментам для создания новеллы. Поподробнее о данном деле можете узнать в моих будущих статьях.
Надеюсь, вы нашли для себя хоть что то полезное :3