Вы находитесь на странице: 1из 545

Изучаем

Ren’Py
2018 Ren’Py

Изучаем
Ren’Py
Разработка визуальных
новелл, rpg и создание
приложений
Романов Сергей (Andredron)

2
2018 Ren’Py

Содержание
Благодарности
Введение
Для кого написана данная книга
Почему именно Ren’Py?
Философия питона
Основы. Начало работы
Ориентирование в главном меню Launcher Ren’Py
Знакомство с текстовым редактором jEdit
Прописываем персонажей в проект
Меню, прыжки, вызовы
Комментарии
3 способа прописать изображение в проект
Фоновое изображение
Спрайт и вызываемые слои изображений
Изображение которое меняется от значения переменной
Основные ошибки при написании ConditionSwitch
Создаем спрайт из нескольких изображений
Как убрать объект
Слои в ренпае
Стандартные координаты изображений [Таблица]
Дробные значение [Таблица]
Точные значения [Инструмент]
Как поменять фон, что бы в нем не пропали обьекты другие
3 способа прописать скорость текста

3
2018 Ren’Py

Как вызывать переходы изображениям [Ссылка]


Alt анимации
Трансформации
Screen
Как отобразить экран в проекте
Как отобразить текстовую кнопку
Графические кнопки
Редактируем главное меню
Добавляем звук в экран и в проект
Подробный разбор возможностей ренпая
Диалог, и все что прописывается в текстовом диалоге.
Множественный диалог
Пишем ответ вместо выбора
Список значений аргументов при создании персонажа:
1) window_
2) who_color и what_color
3) who_font и what_font
4) what_size и who_size
5) what_outlines и who_outlines
6) what_xalign и who_xalign
7) what_textalign и who_textalign
8) what_layout
9) None
10) what_prefix и what_suffix
11) kind
12) image
4
2018 Ren’Py

13) kind=nvl
14) ctc
Изображение, которое ставят в конце диалога
1) Пример из обучения
2) Мой пример
Изображение за диалоговым окном
1) пример из обучения
2) Мой пример
3) Пример из леммафорума 1
4)Пример из леммафорума 2. Вверх вниз
стрелка
5) Пример из леммафорума 3. Анимация
15) dynamic
16) voice_tag
Подробный разбор текстовых тег [Список]:
1) Добавить спец символы в ренпай \"
2) Строку перенести ниже \n
3) Полужирное начертание {b}
4) Курсивное начертание {i}
5)Подчеркивание текста {u}
6)Добавление линии, проходящее посередине текста {s}
7) Увеличить размер текста {size=+число}
8)Уменьшить размер текста {size=-число}
11)Вставить изображение или смайл в текст
{image=exclamation.png}
12)Поменять цвет текста{color=#008000}

5
2018 Ren’Py

13)Создать сверху текста надписи(их правильного


произношения) {rb}
14)Сделать текст вертикальным {vert}
15)Сделать горизонтальный текст{horiz}
16)Создать в проекте ссылку на сайт
{a=https://www.renpy.org}
17)Гиперссылка в тексте
18)Сделать текст прозрачным{alpha=0.1}
19)Заставить появляться текст с определенной
скоростью{cps=25}
20)Поменять шрифт текста{font=DejaVuSans-Bold.ttf}
21)Уменьшить отступы символов между собой
22)Сделать отступ горизонтальный(пустое пространство)
23)Сделать отступ вертикальный(между строками)
24)Немедленно перейти к следующему тексту и
использовать разные переходы
25)Что бы переменная отображалась в переводе, в конце
нее ставят !t
26)Вывести весь текст сразу на экран.
Как добавить случайную фразу в конце предложения
Выставляем позицию для имени персонажа
1)Костыль, но чуть ли не единственное решение, если у вас
сложная рамка.
2)Истинный но самое то для кучи имен с одинаковыми
значениями.
Картинки в кнопках выбора [menu]
Специальные персонажи в ренпае
1)Персонаж Centered

6
2018 Ren’Py

2)Персонаж vcentered
3)Персонаж extend
4)Персонаж expression
Подробный раздел координат изображений
Подробный раздел трансформаций[Список]
1)Смена фона с переходом (например, растворение)
2)Телепорт
3) Интерполяция времени linear
4) ZOOM ZOOM
5) Size
6)Альфа
8) Сrop. Обрезка
9) Алт трансформация
10) Оператор Вlock и time. Братья неразлучные
11) Оператор Parallel
1) Магия среди нас
2) Изображение скачет по экрану на все 4 стороны.
12) Оператор Сhoice
13) Выходим за пределы экрана.
14) Блок on
1)Кнопки
2)Растворение
3) Как задать спец мелодию при пропуске.
15) Contains
16) Function
17)Различные интерполяции Warpers
7
2018 Ren’Py

18) alignaround и clockwise circles


19)Around
20) Angle
21) Radius
22)Tile
23) Pan
24) Offset
25) randmotion
Автоматическое объявление анимации
Подробный разбор переходов и спецэффектов
Прописанные переходы
1) with Dissolve
2) with fade
3) with pixellate
4) with vpunch
5) with hpunch
6) with Pause(1)
7)Жесткая пауза
Переходы Move
Простые переходы
Переход moveout
Переход movein
Zoomin и Zoomout
CropMove
Переход в виде прямоугольника
Переходы PushMove
8
2018 Ren’Py

Переходы которые самостоятельно


создаются(ImageDissolve)
Жалюзи
Квадраты
Открываем и закрываем глаза
Телепорт(построчное изчезновление)
Переход AlphaDissolve
Как задать время переходам
Эффект dissolve, но с учетом прозрачности спрайта.
Эффект вспышки нужного цвета для смены фонов.
Примеры интересных трансформаций(Sprite).
1)Эффект падающих сверху снежинок или
листьев(SnowBlossom)
2 способ вызвать снег
2) Эффект Звездного неба(звезды двигаются справа на
лево)
3) С право налево вылетело изображение, которое плавно
вертится и исчезает
4) По экрану скачут шарики-изображения в случайном
порядке
5)Рандомные мерцающие звезды
6) Эффект репульсон(мы мышкой ищем вещи)
7)Сиськотряс
8) Маскировка снайпер
9) Фонарик
10) Компас(пример)
11) Метель

9
2018 Ren’Py

12) Звездное небо прямо в лицо


13) Эффект Двоения в глазах(Пьяный)
14) Взрыв частиц
Операции над изображением
1) Crop
2) im.Composite
3)LiveComposite
4) im.Scale
5) im.FactorScale
6) im.Map
7) im.Recolor
8) MatrixColor
Тусклый оттенок
Инвертировать оттенок
9) im.Grayscale
10) im.Sepia
11) im.Alpha
Аналог только с размытием(как будто в зеркале):
12) im.Flip
13) Text
14) Эффект размытия изображения
Режим Nvl
Очистить экран Nvl
Убрать и показать переход в NVL
Меню в Nvl
Как запретить откат назад на nvl
10
2018 Ren’Py

Как прописать автоматический переход на nvl


Убрать предыдущую строку в Nvl
Настраиваем экран NVL
1) Истинный
2) Костыльный
Ограничить максимальное число строк в nvl
Режим ADV
Как запретить откат назад в ADV
Как сделать, чтобы при перемотке назад у игрока не было
возможности сменить свой выбор
Подробный разбор звуков
Как добавить звуки и музыку в проект
Как изменить громкость звуков и музыки
Как обьявить в имя - музыкальный файл
Как добавить голос в диалог
Как сделать случайное воспроизведение музыки
Как вставить песню в главное меню
Как привязать к кнопкам звук
Частичное воспроизведение музыки
Альтернатива
Автоматическое обьявление мелодий и звуков
Поставить музыку на паузу
Музыка в меню от времени суток
Как показать громкость музыки в процентах
Саундчек, при смене громкости
Пользователь не может пропустить сцену пока играет музыка

11
2018 Ren’Py

Splashscreen
Метка splashscreen
Так же его можно модернизировать, прописать кнопку
пропуск сцены
Или задать одноразовый вопрос пользователю, А тебе
точно есть 18?
Изображение splashscreen
Экраны
Правильный пример как прописывать экран:
Как отобразить экран в проекте
Экран с 3 параметрами
Несколько параметров экранов
1) modal True
2)Zorder
3)style_prefix
4) tag menu
Python в экранах
Операторе default
Операторы if, elif, else
Оператор for
Оператор Frame(рамка для экрана)
Как убрать стандартную рамку в экране
Оператор Add и как добавить изображение в глав меню
Как прописать изображения в главное меню?
Оператор text
Как прописать музыку в экране

12
2018 Ren’Py

Как прописывать координаты объектам?


Оператор on
Как задать координату – куда будет двигаться мышке
Оператор Key
Управляем штруделем
Колесико мышки
Что то вроде предварительного сообщения, что появится
на ввод
Обьекты box и grid
Текстовые кнопки и экран уведомления Notify
А как изменить Notify?
Свой экран Notyfy2
Как прописать в экране вопрос при нажатии
Вызов screen с преобразованием
Список действий кнопок для textbutton
Функции при нажатии.
action ****
Действия данных
Menu Actions
File Actions
Audio Actions
Voice Actions
Other Actions
Imagebutton
Мой любимый способ
Текстовая кнопка с графическими элементами

13
2018 Ren’Py

Как прописать кнопке, не активировать прозрачные поля.


Как при наведении на кнопку сделать, что бы экран менял цвет
Плюсы и минусы кнопок
Графическая карта imagemap(hotspot)
Пример простейшей граф карты на главное меню.
Добавляем комментарии на карте
Графическая карта Меню Настройки
Графическая карта загрузки и сохранения
Обьекты-полоски (Bar )
Бар с точным значением
Существуют 3 вида стандартных в Gui прописанных
горизонтальных стилей баров.
Так же есть 3 стандартных вертикальных стилей баров
А так же существует бар для горячих точек,
Настройки баров прописаных
Как добавить свой бар в проект?
Как прописать старую версию бара в новом gui
Где взять коды старых баров?
Действия бара
Подробный разбор значений баров.
Настройки стиля бара
Список имен пунктов стилей(и другие значение стилей
подойдут, но эти чисто баров настройки)
Как прописать значение бара через переменную
Делаем круглый бар
Default

14
2018 Ren’Py

Viewport
1)Вертикальные и горизонтальные полосы (scrollbars "both")
2) Горизонтальные полосы (scrollbars "horizontal")
3) Вертикальная полоса( scrollbars "vertical")
Как установить начальную зону просмотра.(xinitial и yinitial)
Как клонировать обьекты в порте
Пример скрола с огромным числом текста
Drag and Drop
Экран загрузки
Подробный разбор значений drag
Как перенести изображение в область где должно
произойти событие
Простой способ смены суток
Простейший календарь
Прописываем отображение денег
Часы электронные и цифровые
Вызов call из экрана screen
Информационный экран, пополняемый
Информационный экран 2. Лист персонажа
Листаем страницы книги
Стили
Через стиль можно задать координаты
Через стиль можно задать размеры рамки
Изменяем текст воспроизведения для синтезатора речи
Удобный способ написания стиля в экранах
Настройки текста стиля в экранах и в персонажах

15
2018 Ren’Py

Вертикальный текст
Жирный текст
Курсивный текст
Нижнее подчеркивание
Цвет тексту
Шрифт тексту
Обводка теста
Сглаживание текста
Интервал расстояния текста
Отступ 1 строки текста
Дополнительный пробел между словами
Расстояние между каждой буквой
Интервал над строками
интервал под строками
Минимальная ширина строки
Скорость появления имени персонажа
Скорость диалога персонажа
зачеркнуть текст
Стиль рамок
Задний фон
Изменяем размеры внутри фона кнопки
Изменяем размеры вне фона кнопки
Передний фон
Сделать одинаковым размером все кнопки
Стиль кнопок
Звук при наведении и нажатии
16
2018 Ren’Py

Невидимая зона не активна у кнопки


Сфокусировать кнопку при помощи клавиатуры
Минимальный и максимальный размеры
Прописываем стиль кнопкам выбора
Прописываем в настройках цвета кнопок главного меню

Видео
Как проиграть видеозаставку до появления главного меню
Как добавить видео фоном
Как добавить видео-спрайт.
Как указать видео координаты
Как отключить возможность пропуска видео.
Режим разработчика
Клавиши которые работают в режиме разработчика
Интерактивный директор
Изменяем директора
Ввод имени персонажа
1)Пример из обучения
2) Более продуманный способ
3)Пример из хот спота
4) Прописываем имя и фамилию персонажа
5) "Герой без конкретного имени"
Имя пользователя которая прописана на вашем компьюторе
Создаем экранную клавиатуру
Генераторы случайных чисел
1) renpy.random.choice

17
2018 Ren’Py

Простой пример – камень ножницы и бумага с списком


Пример переменной с разными переменными
Как отобразить изображение рандомно
Генератор случайных чисел в тексте
2) renpy.random.randint
Числовые значения
Как прописать прыжки случайные по меткам
Как прописывать действия в процентном соотношении.
3) renpy.random.random()
4) renpy.random.shuffle
5) random.sample
Что-то типа чит-кодов
Как переменой прописать координаты
Создаем пароль
Таймеры.
Числовой таймер
Таймер в виде бара
Выборы меню изчезают каждые 2 секунды
Создаем хентай цензуру
Сохраняем и загружаемся прямо из скрипта
Настраиваем Главное меню
Создаем кнопку продолжить игру и текст подтвеждения
1 вариант
2 вариант
Создаем паузу в проекте
Красивый переход для главного меню
18
2018 Ren’Py

Меняем изображение рабочего стола


Разные фоны для главного меню в зависимости от концовок
Фон меню от времени суток на компьютере
Как вывести на экран время, проведенное в игре
Как отобразить % пройденной игры
1 вариант
2 вариант
Как отобразить текущее время на ПК
Добавляем выбор стиля для Quick Menu
Добавляем в настройки размер текста
Прописываем несколько разрешений экрана в проект.
Как создать раздел Повтор сцены
Как удалить файл/папку из ренпая
Как перезагрузить проект в главное меню
Как убрать курсор во время игры
Как создать отдельный архив
Изучаем питон
Особенности Python
Стиль программирования
Рекомендации по стилю
Отступы
Пустые строки
Как вызывать коды питона в ренпае
Зачем нужен блок init?
Связка if, elif, else
Основные действия с переменными
19
2018 Ren’Py

Логические выражения [Флаги]


Числовое значение
Текст в виде переменной
Изменение регистра символов в строках
Конкатенация. Объединение переменных
Удаление пропусков
Списки
Обращение к элементам списка
Изменение элементов в списке
Добавление элементов в список
Присоединение элементов в конец списка
Вставка элементов в список
Удаление элемента с использованием команды del
Удаление элемента с использованием метода pop()
Извлечение элементов из произвольной позиции списка
Удаление элементов по значению
Постоянная сортировка списка методом sort()
Вывод списка в обратном порядке
Определение длины списка
Перебор всего списка
Подробнее о циклах
Генератор список
Создание среза
Перебор содержимого среза
Копирование списка
Словари
20
2018 Ren’Py

Простой словарь
Работа со словарями
Обращение к значениям в словаре
Добавление новых пар «ключ—значение»
Создание пустого словаря
Изменение значений в словаре
Удаление пар «ключ—значение»
Словарь с однотипными объектами
Перебор всех пар «ключ—значение»
Перебор всех ключей в словаре
Упорядоченный перебор ключей словаря
Перебор всех значений в словаре
Список в словаре
Словарь в словаре
Циклы while
Пользователь решает прервать работу программы
Флаги
Использование цикла while со списками и словарями
Удаление всех вхождений конкретного значения из списка
Заполнение словаря данными, введенными пользователем
Функции
Определение функции
Необязательные аргументы
Возвращение словаря
Использование функции в цикле while
Изменение списка в функции
21
2018 Ren’Py

Запрет изменения списка в функции

Генератор цепи маркова


Первые шаги на пути портирования с pygame на RenPy.
Как сделать обратную связь с бетатестером
Как добавить сторонний модуль в ренпай (Sqlite3 и BerkeleyDB)
Создаем инсталлятор
Портируем проект на андроид/айфон
Портируем андроид
Как убрать логотип Ренпая на андроиде
Портируем на айфон
проблема всех начинающих кодировщиков.
Как сделать перевод проекта на другой язык
1) Костыльный
2) Истиный
Готовим проект к переводу
готовим код для создания перевода
Как вскрыть код другого проекта, написанного на ренпае.
Через специализированную программу Quest Viewer
Статья 272. Неправомерный доступ к компьютерной информации
Начало работы
unrpa
unrpyc
Создаем свою тему лаунчера ренпая
Создаем Свою иконку проекта
Сайты

22
2018 Ren’Py

Облака для хранения файлов


Всем спасибо! Что уделили моему маленькому учебнику внимание.

БЛАГОДАРНОСТИ

Эта книга никогда бы не появилась на свет без помощи следующих


людей:
Руслана Небыкова - http://renpyfordummies.blogspot.ru за то что в свое
время меня отсчитал, после чего я занялся за ум. Спасибо огромное
тебе
руководителя сообщества Cyber Craft https://vk.com/cyber_z_craft
Мастера Ирдиса, за то что создал первую серию видеороликов по
Ренпаю
Гардарика – за полезные плюшки и разъяснения связанные с работой
с дополнительными инструментами по ренпаю, а так же огромной
помощи с разделом переводы. https://vk.com/reneen

23
2018 Ren’Py

Al Loui – за то что помогает все новичкам, опытным советами, без


твоих подсказок я бы забросил давно сообщество ренпая, ибо на тот
момент когда я пришел в группу, ты всегда помогал советами.
Роману Панову – за то что открыл мне мир ренпая своим приложение
https://vk.com/topic-7553243_28095746 благодоря ему я узнал что такое
новеллы.
А так же отдельная благодарность сообществу https://vk.com/renpy и
https://lemmasoft.renai.us/forums/ что единомышленники могут помочь
советами друг другу.
Особое отдельно спасибо Дмитрию Галдину, за то сплотил
сообщество ренпая. Многие скажут когда это было, а старики еще
помнят твои посты-опросники, когда в группе было только 1000
человек. И что не смотря на на разочарование в русской комьюти, ты
продолжаешь пытаться изменить мир к лучшему. Что даже сам
Мистер Пайтон заметил это https://vk.com/wall-7553243_9667
Спасибо тебе Станислав Корелов что обьяснил что такое
программирование, и почему питон не всесилен, а так же как удобно
скрипты делать для создания сценариев. Обидно что многие были
неженками и тебя в игнор кинули.

ВВЕДЕНИЕ

ДЛЯ КОГО НАПИСАНА ДАННАЯ КНИГА

24
2018 Ren’Py

Цель этой книги – как можно быстрей ввести читателя в курс дела, что
бы тот мог писать на Ren’Py работоспособные приложения (игр,
визуализация данных), и одновременно заложить основу в области
программирования, которая ему пригодится на протяжении всей
жизни. Книга написана для людей, которые прежде никогда не
программировали на Python или вообще никогда не программировали.

ПОЧЕМУ ИМЕННО REN’PY?


Ren’Py - простой и гибкий движок для создания визуальных новелл.
Одним из его главных преимуществ является его бесплатность,
открытость для многих платформ(Windows, Linux, Android, IOS…)
Ренпай появился в 2004 году и с тех пор он постоянно развивается.
Языком программирования в нем является Python 2.7
Язык Python очень эффективен:
Ваше приложение делает больше, чем другие языки, в меньшем
объеме кода. Синтаксис Python позволяет писать «чистый код». Ваш
код будет легко читаем, и у вас будет меньше проблем с отладкой и
расширением программы, в сравнении с другими языками

ФИЛОСОФИЯ PYTHON
Долгое время язык программирования Perl был краеугольным камнем
интернет-программирования. На первых порах функционирование
многих интерактивных сайтов было основано на сценариях Perl. В то
время сообщество Perl руководствовалось девизом: «Это можно
сделать несколькими способами». Какое-то время разработчикам
нравился такой подход, потому что гибкость, присущая языку,
позволяла решать многие задачи разными способами. Подобный
подход был допустим при работе над собственными проектами, но со
временем стало ясно, что чрезмерная гибкость усложняет
долгосрочное сопровождение крупных проектов. Было слишком
трудно, утомительно и долго разбираться в коде и пытаться понять,
что же думал другой разработчик при решении сложной задачи.
Опытные программисты Python рекомендуют избегать лишних
сложностей и применять простые решения там, где это возможно.
25
2018 Ren’Py

Философия сообщества Python выражена в очерке Тима Питерса «The


Zen of Python». Я не стану воспроизводить все принципы, но приведу
несколько строк, чтобы вы поняли, почему они важны для вас как для
начинающего программиста Python.
Красивое лучше, чем уродливое.
Программисты Python считают, что код может быть красивым и
элегантным. В программировании люди занимаются решением задач.
Программисты всегда ценили хорошо спроектированные,
эффективные и даже красивые решения. Со временем вы больше
узнаете о Python, начнете писать больше кода, и когда-нибудь ваш
коллега посмотрит на экран вашего компьютера и скажет: «Ого, какой
красивый код!»
Простое лучше, чем сложное.
Если у вас есть выбор между простым и сложным решением и оба
работают, используйте простое решение. Ваш код будет проще в
сопровождении, а у вас и других разработчиков будет меньше
проблем с обновлением этого кода в будущем.
Сложное лучше, чем запутанное.
Реальность создает свои сложности; иногда простое решение задачи
невозможно. В таком случае используйте самое простое решение,
которое работает.
Удобочитаемость имеет значение.
Даже если ваш код сложен, он должен нормально читаться. Работая
над проектом, требующим написания сложного кода, постарайтесь
написать содержательные комментарии для этого кода.
Должен существовать один — и желательно только один —
очевидный способ сделать это.
Если предложить двум программистам Python решить одну и ту же
задачу, они должны выработать похожие решения. Это не значит, что
в программировании нет места для творчества. Наоборот! Но
большая часть работы программиста заключается в применении
небольших, стандартных решений для простых ситуаций в контексте
большого, более творческого проекта. Внутренняя организация ваших
программ должна выглядеть логично с точки зрения других
программистов Python.
Сейчас лучше, чем никогда.

26
2018 Ren’Py

Вы можете потратить весь остаток жизни на изучение всех тонкостей


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

 Красивое лучше, чем уродливое.


 Явное лучше, чем неявное.
 Простое лучше, чем сложное.
 Сложное лучше, чем запутанное.
 Плоское лучше, чем вложенное.
 Разреженное лучше, чем плотное.
 Читаемость имеет значение.
 Особые случаи не настолько особые, чтобы нарушать правила.
 При этом практичность важнее безупречности.
 Ошибки никогда не должны замалчиваться.
 Если не замалчиваются явно.
 Встретив двусмысленность, отбрось искушение угадать.
 Должен существовать один — и, желательно, только один —
очевидный способ сделать это.
 Хотя он поначалу может быть и не очевиден, если вы не голландец[10].
 Сейчас лучше, чем никогда.
 Хотя никогда зачастую лучше, чем прямо сейчас.
 Если реализацию сложно объяснить — идея плоха.
 Если реализацию легко объяснить — идея, возможно, хороша.
 Пространства имён — отличная штука! Будем делать их побольше!

ОСНОВЫ

27
2018 Ren’Py

НАЧАЛО РАБОТЫ
В этой части книги будут представлены базовые концепции
необходимые для написания программы.
Для начало работы вам необходимо будет правильно установить
Ren’Py
1) Скачайте Launcher Ren’Py http://www.renpy.org и выберите самую
последнюю версию
2) Установите его C:\Program Files\RenPy На пути установки не
должно быть иных символов кроме английского
3) Запустите его.
У вас высветится такое окно:

28
2018 Ren’Py

Для удобства работы, выберите ваш язык, для этого вам необходимо
будет выбрать Preferences (он обведен красным кружком) Найдите в
нем строку Languages и выберите пункт Russian.
Далее вам потребуется выбрать папку, где у вас будут создаваться
все проекты.
Для этого выберите раздел Настройки и нажмите на пункт Папка
проектов
Теперь все ваши проекты будут отображаться в выбранной вами
папке.
В Ren’Py существует 2 версии темы – старая и новая(GUI). Чем скорей
вы перейдете на новую версию(GUI) тем лучше. Все же полезней
использовать самую новую версию.

ОРИЕНТИРОВАНИЕ В ГЛАВНОМ МЕНЮ


LAUNCHER REN’PY

29
2018 Ren’Py

1) Проекты - здесь находится список проектов. Стандартные проекты


«Обучение» и «Вопрос» идут в каждом лаунчер ренпая.
Лаунчер – программа Ren’Py
2)Добавить новый проект – создать новый проект, где вам
программа предложит выбрать режим вашего будущего проекта(Gui
или Старая версия).
3) Активный проект – действия по изменению сценариев и открытия
папок выбранного проекта (В данном случае выбран проект
«Обучение»).
Сценарии – это файлы, в котором вы прописываете сюжет, Скрипты и
коды проекта.

30
2018 Ren’Py

4) Навигация по сценарию – этот под пункт состоит из нескольких


разделов:
Навигация по сценарию – нажав на эту кнопку, перед вами
раскроется инструмент по быстрому поиску в сценариях: меток,
файлов и т.д.
Проверить сценарий – проверяет проект на ошибки, количество
строк, персонажей и т.д.
Изменить Gui – изменяет проект(в основном цвета) на
стандартный набор.
Очистить постоянные – в процессе написания проекта в нем
создаются переменные(например, программа запоминает
сколько вы прошли сюжетной линии, а так же выбранные вами
настройки. А так же бывает что исправил ошибку, но оно не
уходит, хотя все прописано верно). И что бы очистить всю эту
информацию, выбирается данная команда.
Перекомпилировать – т.е. зашифровать файлы сценария. Вы
пишите в файлах сценариях, которое имеет расширение .RPY, а
нажав на команду. Перекомпилировать вы их зашифруете
в .RPYC и, удалив .RPY сторонний человек не сможет внести
изменения в файлы сценария.
Построить Дистрибьюв – преобразует проект в читаемый вид
для запуска проекта на различных платформах
Остальные пункты – из названий понятны их значения.
5)Запустить проект – запустить выбранный проект, а также
различные подпункты.
Документация – Вордовские документы на англ. языке, в
котором описаны все команды по Ренпаю.
Сайт – офф сайт Ренпая.
Список игр – Мистер Питон очень любит хвастаться проектами,
которые были написаны на его движке, и поэтому у него есть
свой список игр. Кстати это очень хорошая реклама для
проектов.
Обновить – обновить лаунчер ренпая на более новую версию.
Настройки – Здесь вы можете настроить ваш лаунчер(консоль
вызвать, выбрать место от куда ваш проект будет виден лаунчер
и т.д).
Спонсоры – список тех людей, которые поддерживают мистера
Пайтона деньгами(форум, сервер - все это стоит денег)

31
2018 Ren’Py

Что бы у вас было представление, что может данный движок,


запустите проект «Обучение» в лаунчер ренпая.

Для удобства ознакомления выберите раздел «Preferences», где вы


можете выбрать русский язык.
Потом выберите кнопку «Вернуться» и запустите проект кнопкой
«Начать»
Для начало работы вам нужно будет создать 1 будущий проект.
Для этого в Launcher Ren’Py выберите раздел Добавить новый
проект
Если вы включили в настройках отображение старых тем, то увидите
меню, где вам программа предлагает выбрать 2 вида тем.
В данном учебнике будет рассматриваться только новая тема.
По старой версии существует видео-уроки от Мастера Ирдиса
(смотрите в видео группы автора https://vk.com/cyber_z_craft)
Выбираем пункт «Новый Интерфейс Gui» и кнопку «Продолжить»
Введите имя проекту. Например «Test»
Запомните! Имя проекта, как и имена меток в сценарии, пишутся
только АНГЛИЙСКИМИ БУКВАМИ И ВПРЕРЕДИ НИКОГДА НЕ
СТАВЬТЕ ЦИФРЫ!

32
2018 Ren’Py

Приложение спросит у вас разрешение экрана проекта. Выбираете


разрешение 1280х720 (средний стандарт) и кнопку «Продолжить».
Далее программа вам предложит выбрать стандартную цветовую
схему будущему проекту. После выбора понравившейся вам темы,
нажмите «Продолжить».
В левом столбе, где проекты, у вас появилась кнопка, c именем
проекта, которое вы создали.
Что бы приступить к работе со сценариями в проекте, вам
понадобится нажать в лаунчер ренпая на подпункт «Все файлы
сценария»

У вас высветится такое окно

33
2018 Ren’Py

Текстовые редакторы распознают код Python и выделяют


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

ЗНАКОМСТВО С JEDIT

34
2018 Ren’Py

1)Панель инструментов – тут находятся все инструменты


программы.
2)Иконки быстрого доступа – самые часто используемые
инструменты.
3)Файлы сценариев – файлы, в которых мы будем работать,
прописывать код, создавать проект.
4)Диалоговое окно – окно, в котором мы пишем код.
5)Строка ориентирования- показывает где на какой строке мы
прописываем текст, а так же показывает где появилась ошибка при
написании.
В мире программирования издавна принято начинать освоение нового
языка с программы, выводящей на экран сообщение Hello world! —
считается, что это приносит удачу.

Приступим к работе

35
2018 Ren’Py

В файле сценария script.rpy полностью очистите всю информацию

Вам нужно создать метку(label), на которую ren’py будет ссылаться. Стандартная метка, с
которой начинаются все приложения ренпая - называется start.

Без отступов напишите имя метки start

36
2018 Ren’Py

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


start. Что бы ренпай понял, что происходит в метке старт start нужно в
конце написать знак двоеточие : этим мы показываем программе что
будет происходить в метке. Далее что бы программа не путалась
необходимо перейти на следующую строку и сделать от края 4
отступа(в jEdit программа автоматически добавит 4 отступа после
написания : ) и напишите в кавычке фразу "Hello Word" вот что у вас
должно получиться:

37
2018 Ren’Py

Потом нажмите клавишу CTRL+S , Вы сохранили файл сценария,


теперь в Launcher Renpy запустите ваш проект тест. Если вы все
правильно сделали, то у вас проект запустится и высветит
написанный вами текст.
Если вы написали неправильно код, то ренпай высветит, где у нее
конфликт идет.

38
2018 Ren’Py

В данном примере показано, что в файле game/script.rpy на 2 строке


у программы конфликт.

ПРОПИСЫВАЕМ В ПРОЕКТ ПЕРСОНАЖЕЙ


Для удобства пропишите персонажей в отдельном файле, создайте в
текстовом редакторе пустой файл (выберите изображение пустого
листа.) У вас создался пустой файл, сохраните его, при сохранении
пишите латинскими буквами имя файла и в конце запишите его
расширение .rpy
У вас появится файл pers.rpy
В ренпае нет разницы, где пишется код, он читает все файлы
сразу, т.е. ему не нужно указывать - из какого файла ему нужно
прочитать код.
В данном файле запишите в начале строки команду init: данная
команда показывает ренпаю что информацию, которую мы тут
записали, будет отображена в питоне (проще говоря, ренпай будет
видеть коды ваши в любом случае) и пропишем ваших первых
персонажей в проект:

39
2018 Ren’Py

init:
define katya = Character(_("Катя"), color="#008000", who_suffix = ':')
define shora = Character(_("Георг"), color="#008000", who_suffix =
':')
katya и shora – имена ссылки, мы будем вызывать данные имена в
проект что бы нам меньше писать в нем кода.
Character(_("Катя"), - персонаж с именем Катя, нижнее
подчеркивание необходимо для того что бы данный текст отобразился
в переводе
color="#008000", - Мы прописываем цвет имени персонажа, в нем
используются цветовая палитра. Весь список цветов вы можете
рассмотреть в гугле, также код необходимо заключать в кавычки.
Обратите внимание, если вы хотите сделать текст полупрозрачным,
вместо 6 знатного кода вам необходимо писать 8 чисел, первые 6 –
код цвета, следующие 2 цифры - % прозрачности. color="#00800085"
who_suffix = ':'- символ который будет после имени персонажа.
Больше команд и значений смотрите в Продвинутый разбор
Character
Теперь рассмотрим, как же вызывать короткие имена-ссылки
персонажей.
Зайдите в текстовом редакторе в файл-сценарий script.rpy и
запишите следующий текст:

label start:
"Раздался звонок в дверь"

40
2018 Ren’Py

"Открыв его, я увидел свою лучшую подругу"


katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
shora "Привет, я сегодня…"

После сохраните и запустите ваш проект. Как видите написать диалог


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

МЕНЮ, ПРЫЖКИ, ВЫЗОВЫ

41
2018 Ren’Py

Самый простейший вариант выбора – пункт меню. Рассмотрите


пример, как применяется пункт меню
label start: ###без отступов
"Раздался звонок в дверь"
"Открыв его, я увидел свою лучшую подругу"
katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
shora "Привет, я сегодня…" ###4 отступа от края
menu: ###4 отступа от края
"1) Буду занят": ###8 отступов от края
shora "…буду занят, прости"###12 отступов от края
katya "Блин жалко…."
katya "Завтро расскажи чем занят был то, хорошо?"
shora "Хорошо"
"Конец 1"
"2) Свободен": ###8 отступов от края
shora "…свободен.." ###12 отступов от края
katya "Класс!!!"
katya "Пошли тогда в кафешку перекусим!"
katya "Я сегодня сутра ничего не ела!"
shora "подожди 1 минуту я переоденусь"
"Конец 2"

42
2018 Ren’Py

Обратите внимание на данные отступы, после каждого знака : мы


делаем на следующей строке отступ в виде 4 пробелов.
Пункт menu заставляет пользователя сделать выбор, который в
дальнейшем повлияет на дальнейшие события.
"1) Буду занят": - после каждого пункта выбора, в конце мы ставим
знак : и прописываем события что в них будут происходить.
Можно и дальше прописывать варианты выбора такими отступами –
но представьте как будет выглядеть проект в котором около 40
вариантов выбора, представьте какой размер отступа будет в 40
варианте (4….8….12…16…..) что бы облегчить нам задачу, придуманы
команды прыжки и вызовы.

43
2018 Ren’Py

КОММЕНТАРИИ
Комментарии – это то, что пишется после символа #, и представляет
интерес лишь как заметка для читающего программу.

Комментарии чрезвычайно полезны в любом языке


программирования. До сих пор ваши программы состояли только из
кода Python. По мере роста объема и сложности кода в программы
следует добавлять комментарии, описывающие общий подход к
решаемой задаче, — своего рода заметки, написанные на понятном
языке.

Как создаются комментарии?


В языке Python признаком комментария является символ «решетка»
(#). Интерпретатор Python игнорирует все символы, следующие в коде
после # до конца строки. Пример:
label start:
"Раздался звонок в дверь" ###1 глава
"Открыв его, я увидел свою лучшую подругу"

Какие комментарии следует писать?

Комментарии пишутся, прежде всего, для того, чтобы объяснить, что


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

44
2018 Ren’Py

простых, лаконичных комментариев – одна из самых полезных


привычек, необходимых начинающему программисту.
Принимая решение о том, нужно ли писать комментарий или нет,
спросите себя, пришлось ли вам перебрать несколько вариантов в
поисках разумного решения для некоторой задачи; если ответ будет
положительным, напишите комментарий по поводу вашего решения.
Удалить лишние комментарии позднее намного проще, чем
возвращаться и добавлять комментарии в программу.
КАК НЕ СТОИТ ДЕЛАТЬ КОММЕНТАРИИ

https://tproger.ru/articles/comments-in-code/

Старайтесь в своих программах писать как можно больше полезных


комментариев, объясняющих:
• предположения;
• важные решения;
• важные детали;
• проблемы, которые вы пытаетесь решить;
• проблемы, которых вы пытаетесь избежать и т.д.

ПРЫЖКИ

Прыжки нам позволяют совершать перемещение к указанным меткам,


включая к тем меткам, которые находятся в других файлах-сценариях.
После общения с Станиславом Кореловым я стал по-другому
смотреть на файлы в ренпае. Каждое место действие писать в
отдельном файле, у которого будет 1 единый управляющий файл, в
котором прописана логика всего проекта. По началу, вам кажется оно
жуть как неудобно, но когда вы поймете суть этой идеи – вы с легкость
сможете писать патчи, моды, исправления вашего проекта потратив
на изменения минуту а так же минимум файлов скачивать в виде
обновлений.
Создайте новые файлы сценария kafe.rpy и internet.rpy
Пропишите следующее в kafe.rpy:

45
2018 Ren’Py

label kafe:
"Мы вместе классно посидели, пообщались "
"Давно я так не болтал с таким близким человеком"
Пропишите следующее в internet.rpy:
label internet:
"Катя ушла"
"Я решил сесть пообщаться с собеседниками в интернете"

И в script.rpy
label start:
"Раздался звонок в дверь"
"Открыв его, я увидел свою лучшую подругу"
katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
shora "Привет, я сегодня…"
menu:
"1) Буду занят":
shora "…буду занят, прости"
katya "Блин жалко…."
katya "Завтра расскажи чем занят был то, хорошо?"
shora "Хорошо"
jump internet
"2) Свободен":
46
2018 Ren’Py

shora "…свободен.."
katya "Класс!!!"
katya "Пошли тогда в кафешку перекусим!"
katya "Я сегодня сутра ничего не ела!"
shora "подожди 1 минуту я переоденусь"
jump kafe
"Я лег спать"
"Меня разбудило сообщение в телефоне"
Сохраните изменения и запустите проект

Теперь разберем что тут записано:


jump internet – мы перенеслись в метку интернет,
"Я лег спать" – обратите внимание на количество отступов, мы эту
фразу записали в метке start, и если в тексте не было бы прыжков, то
текст шел бы дальше, в не зависимости от выбора, что бы мы могли
совершать перемещение в другие метки, и мы вернулись назад – то
используют команды call

CALL
Подкорректируем наши записи в script.rpy
label start:
"Раздался звонок в дверь"
"Открыв его, я увидел свою лучшую подругу"
katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
shora "Привет, я сегодня…"
menu:

47
2018 Ren’Py

"1) Буду занят":


shora "…буду занят, прости"
katya "Блин жалко…."
katya "Завтра расскажи чем занят был то, хорошо?"
shora "Хорошо"
call internet
"2) Свободен":
shora "…свободен.."
katya "Класс!!!"
katya "Пошли тогда в кафешку перекусим!"
katya "Я сегодня сутра ничего не ела!"
shora "подожди 1 минуту я переоденусь"
call kafe
"Я лег спать"
"Меня разбудило сообщение в телефоне"
Как тут видно мы заменили jump на call. Сохраните изменения, и
запустите ваш проект. Как вы заметили, после выбора мы
перенеслись в записанные нами локации(интернет и кафе) и после
завершении действий в локации, мы возвращаемся обратно в наш
логический файл script.rpy В котором происходят дальнейшая
развязка (Жора уснул и проснулся от сообщения)
Теперь, когда вы увидели основы по вводу текста, приступим к
операциям по добавлению изображений и других ресурсов проекта.

ДОБАВЛЯЕМ ИЗОБРАЖЕНИЕ В
ПРОЕКТ

Создайте файл resurse.rpy


48
2018 Ren’Py

Существует 3 способа привязать в проект изображения.

1 СПОСОБ. ВРУЧНУЮ ПРОПИСАТЬ ЕГО

init: ###нет отступов


image imy ssylka ="put/k/kartine.png" ###4 отступа от края

Таким не замысловатым способом можно прописать все фоновые


картинки проекта и спрайты персонажей.
Обратите внимание, таким способом, обычно прописывают
модифицированные ренпаем изображения (например, чб
изображение, а по факту оно цветное и т.д)
Для сведенья в 40 часовой новелле может быть около 400
изображений… представляете, сколько бы пришлось вам
прописывать, если бы не было автоматической прописки
изображения….

2 СПОСОБ. ПРОПИСАТЬ АВТОМАТИЧЕСКОЕ


СЧИТЫВАНИЕ

init python:
config.automatic_images_minimum_components = 1 ###
минимальное количество тегов
config.automatic_images = [' ', '_', '/'] ### список разделителей для
создания тегов
config.automatic_images_strip = ["images"] ### здесь через запятую
можно указать и другие папки из директории game

49
2018 Ren’Py

"images/eileen/happy.png" будет объявлено как "eileen happy"


"images/eileen_happy.png" будет объявлено как "eileen happy"
"images/eileen happy.png" будет объявлено как "eileen happy"
но лучше вообще избегать имен файлов и путей с пробелами, на
некоторых операционках могут проблемы возникнуть (ибо как писал
мой знакомый программист «Настоящий программист пишет все без
пробелов и цифр в начале названий»)

3 СПОСОБ. ПРОСТО ВСТАВИТЬ ИЗОБРАЖЕНИЕ В ПАПКУ


GAME/IMAGES

И вызывать таким же способом как в предыдущем


способе(сокращенные имена)

ФОНОВОЕ ИЗОБРАЖЕНИЕ

В ренпае фоновым изображением может быть только 1 графический


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

label start:
scene black
"У нас черный задний фон"

50
2018 Ren’Py

Так же пример вызываемых изображений, изображение вставил в


папку проекта test\game\images\ и оно имеет имя dom.jpg и имеет
такое же разрешение как у вашего проекта (1280 на 720)
label start:
scene dom
"У нас фон-изображение"

СПРАЙТ И ВЫЗЫВАЕМЫЕ СЛОИ

Что бы добавить к фоновому изображению еще дополнительные


детали (облака по небу бегут как пример) а так же изображение
персонажей(спрайты) используют оператора show как пример
label start:
scene komnata
"Раздался звонок в дверь"
"Открыв его, я увидел свою лучшую подругу"
scene koridor
show katya ulibaetsya
katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
show shora kazus
shora "Привет, я сегодня…"

Как вы заметили,
show katya ulibaetsya
katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
show shora kazus

51
2018 Ren’Py

У нас на экране появились сразу 2 спрайта, друг за другом. Что тут


можно изменить? Тут несколько решений. Можно опять вызвать
фоновое изображение, тогда спрайт исчезнет

show katya ulibaetsya


katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
scene koridor
show shora kazus
А еще можно убрать изображение, или перенести его координаты.

ИЗОБРАЖЕНИЕ КОТОРОЕ МЕНЯЕТСЯ ОТ ЗНАЧЕНИЯ


ПЕРЕМЕННОЙ

Допустим вы создаете рпг или симулятор свиданий, и в нем вам нужно


что бы в проекте менялось изображение от переменной (например
live_hp = 100 или otnoschen = "love")
Стандартным способом у вас код будет выглядеть так:

image john = "john.png"


image john hurt = "john_hurt.png"
image john very"john_very_hurt.png"

label start:

52
2018 Ren’Py

$ live_hp = 100
label start2:
"У тебя жизни столько [live_hp]"
"И тебя стукнули по голове книгой"
$ live_hp -25
if (live_hp < 10):
show john very
"Вырубили тебя"
return
elif (live_hp <= 50):
show john hurt
"Почти пришибли"
else:
show john
"Больно!!!!"
"Начинаем все сначало"
jump start2

Все это работает, но это означает что вам потребуется прописывать


постоянно условия для каждого повреждения персонажа. А что если
нам потребуется прописать еще изображения для 80? 60 и т.д жизни
или отношения(не знакомый, знакомый, друг, близкий друг, партнер,
возлюбленный и т.д.)? Тогда у вас код может вырасти еще раза в 7 и
некоторые отказываются от разных вариантивностей в проекте.
Есть очень элегантный способ в разы сократить число писанины в
коде, для этого в ренпае используют ConditionSwitch
Пример из обучения:
image bg waterfront = ConditionSwitch(
"time_of_day == 'day'", "waterfront_day.jpg",
"time_of_day ==
'night'","waterfront_night.jpg",
)
label start:
$ time_of_day = 'day'
scene bg waterfront with dissolve
pause
$ time_of_day = 'night'
"Фон автоматически поменялся!!!!"
pause
$ time_of_day = 'day'

53
2018 Ren’Py

"Фон поменялся!!!!"
pause
Каждая строка представляет собой уникальное сочетание из условия
(первый аргумент в кавычки) , и изображение, которое должно быть
показано , если условие истинно (второй аргумент в кавычки). В то
время как изображение на экране, Ren'Py оценит , если первое
условие истинно. Если да, то он будет показывать изображение в
сочетании с условием. Если это не так, она будет двигаться ко
второму условию и проверить его и так далее.
Для числовых переменных код будет выглядеть примерно так

image john = ConditionSwitch (


"live_hp < 10","john_very_hurt.png",
"live_hp < 50","john_hurt.png",
"True", "john.png"
)
label start:
$ live_hp = 100
label start2:
show john
"У тебя жизни столько [live_hp]"
"И тебя стукнули по голове книгой"
$ live_hp -25
if (live_hp < 10):
"Вырубили тебя"
return
elif (live_hp <= 50):
"Почти пришибли"
else:
"Больно!!!!"
"Начинаем все сначало"
jump start2

Где True изображение по умолчанию, т.е. бедный джон здоровый

ОСНОВНЫЕ ОШИБКИ ПРИ НАПИСАНИИ CONDITIONSWITCH

Не правильно записали вариантивность

54
2018 Ren’Py

В данной функции начинает проверку с 1 значения если оно будет


верно то ниже оно не будет опускаться, и если вы запишете так
image john = ConditionSwitch (
"live_hp < 50","john_hurt.png",
"live_hp < 10","john_very_hurt.png",
"True", "john.png"
)
То вы никогда не увидите значение при 10
Забыл поставить запятую в вариантах
"live_hp < 50","john_hurt.png",
"live_hp < 10","john_very_hurt.png",
Пишут условие – запятая, потом пишут при условии какое будет
изображение и запятую, нажимают интер и еще условия прописывают
в самом последнем условии на конце запятая не нужна.

СОЗДАЕМ СПРАЙТ ИЗ НЕСКОЛЬКИХ ИЗОБРАЖЕНИЙ

Очень удобный способ, который позволяет вам:

Экономить размер проекта


Переносить такой шаблон как 1 единое изображение не прописывая кучу кода
Код будет выглядеть очень аккуратно

Что бы посмотреть пример кода такого откройте бесконечное лето скрипты, или скачайте
и посмотрите следующий проект

https://lemmasoft.renai.us/forums/download/file.php?id=24372

Много общего с предыдущей темой, по этому в кратце запишу код что бы понятно было
init-2:
## ------------- Принцесса Елена -------------------
image ElenaG = "ch/E_g/E_Gr.png"

# Note: png-изображение туловища персонажа - E_gr.png. где ch / E_g / обозначает


папку, в которой находится изображение
image Elena ulib = LiveComposite(
(465, 760), # Ширина и высота всего спрайта
(0, 0), "ch/E_g/E_Gr_00.png", # туловище
(0, 0), "ch/E_g/E_Gr_h_smile0.png", # Волосы
(0, 305), "ch/E_g/E_Gr_a_1.png" # руки, с указанием где руки
будут
)

image ElenaG grus = LiveComposite(


(465, 760),

55
2018 Ren’Py

(0, 0), "ch/E_g/E_Gr_00.png",


(0, 0), "ch/E_g/E_Gr_h_smileL.png",
(0, 305), "ch/E_g/E_Gr_a_1.png"
)
label start:
show Elena ulib at right with dissolve
pause
show Elena grus at center with dissolve
pause

КАК УБРАТЬ ОБЪЕКТ?


для этого используют команду hide imya_obyekta
show katya ulibaetsya
katya "Привет!!!"
katya "Ты гулять идешь? Ммм?"
hide katya
show shora kazus
shora "Привет, я сегодня…"
Обратите внимание на эту строку hide katya, мы записали лишь часть
имени, но изображение послушно исчезло, почему? Дело в том, что в
ренпае первая часть имени – вызываемый тег, 2 часть – его
уточняющее имя. И поэтому если вы запишите код
show katya ulibaetsya
katya "Привет!!!"
show katya prishur
katya "Ты гулять идешь? Ммм?"
Спрайт Кати, будет меняться автоматически, и не нужно будет
записывать hide katya, программа сама автоматически сделает это.
А если вам требуется что бы на экране, было одновременно
несколько персонажей, и что бы они ни стояли друг за другом? У

56
2018 Ren’Py

ренпая есть прописанные стандартные позиции, а так же вы сможете


сами прописать координаты для объектов.

СЛОИ В РЕНПАЕ
Откуда взял идею http://traumendes-madchen.com/blog/?p=1395
Простой пример. Вам нужно прописать движение облаков. Задача
усложняется тем что впереди у вас стоит здание замка, и между
зданиями вам нужно провести таким образом что 1 здание было
впереди неба, а 2 позади неба.
Для начала вам нужно узнать каким образом определяются слои в
ренпае.
label start:
centered "Пролог"
scene goluboe_nebo # 1 слой он же основной слой
show zamok_2 at right # 2 слой
show oblako at dvishenie # 3 слой
show zamok_1 at left # 4 слой
$ renpy.pause(10.0, hard=True) #Жесткая пауза
centered "Хризалида{p=1}Ветер перемен"
scene black with dissolve # сцена которая убирает все
pause
1 слой – это сцена, которая будет находиться позади всех
графических обьектов.
2 слой – это половина замка, будет находиться позади облака
3 слой – облако которое не будет прятаться за голубое небо и 2
половине замка, оно будет выше их. Но оно будет заходить за 1
половину замка.
4 слой – половина замка которая находится впереди всех обьектов
scene black – мы вызываем новую сценну и все наши графические
обьекты будут удалены.
Что бы у вас не пропадали ваши анимированные сцены, когда вам
нужно сменить фон, прописывайте анимации в экранах и вызывайте
их командой show screen zamok.
Так же обращаю ваше внимание на то что чем больше у вас
57
2018 Ren’Py

одновременно запущенно анимаций, экранов с постоянным


движением, тем быстрей у вас программа заглючит и высветит
ошибку о нехватке памяти (или будет глючить и тормозить – что
еще хуже)
Ниже ссылка на тот обьект что я прописал в примерах
http://traumendes-madchen.com/blogfr/wp-content/uploads/2016/03/Hallwa
y-finished.gif

СТАНДАРТНЫЕ КООРДИНАТЫ
ОБЪЕКТОВ[ТАБЛИЦА]

Пример: show imy_kartiny at center


+-----------------------------------------------------------+
|topleft, reset top topright|
| |
| |
| |
| |
offscreenleft | Truecenter | offscreenright
| |
| |
| |
| |
|left center, default right|
+-----------------------------------------------------------+

И как пример запишем в тестовом проекте


label start:
scene komnata
"Раздался звонок в дверь"
"Открыв его, я увидел свою лучшую подругу"
scene koridor
show katya ulibaetsya at center#координаты станд пишут через at
katya "Привет!!!"
show katya prishur

58
2018 Ren’Py

katya "Ты гулять идешь? Ммм?"


show katya prishur at left
show shora kazus at center
shora "Привет, я сегодня…"

ПРОПИСЫВАЕМ СВОИ КООРДИНАТЫ В


ПРОЕКТ.
А как вообще определить нужные координаты?
Питон поддерживает 2 вида чисел – Целые и дробные. Число 100 –
целое, а число 1.0 – дробное.
Ren’Py использует
Целые числа – для прописывания точных координат
Дробные – для % отображения(примерного). И у такого способа
огромные плюсы. Когда вы будете импортировать проект на андроид и
т.д. вам не придется заново прописывать все координаты. Координаты
пишутся обычно в конце объектов. Так как в ренпай 2д движок,
координаты в нем прописывают по принципу геометрии, где x –
ширина, у – высота.
Самые часто используемые операторы, которые чаще всего
используют в ренпае align(для дробных значений xalign и yalign) и
pos(для точечных значений xpos и ypos). Операторов, которые
отвечают за координаты много, но эти 2 самые часто используемые.

1)ДРОБНЫЕ ЗНАЧЕНИЯ (ИМЕННО ИХ


РЕКОМЕНДУЮ ИСПОЛЬЗОВАТЬ!) [ТАБЛИЦА]
Оно предназначена для % отображения(примерного) отображения.
Вот примерная карта для дробных значений
Где красная - х значения, желтая – у значение

59
2018 Ren’Py

+------------------------------------------------------+
0 | 0 0.5 1 | 0
| |
| |
| |
| |
0.5 | | 0.5
| |
| |
| |
| |
1 | 0 0.5 1 | 1
+------------------------------------------------------+

И существует куча способов прописать, таким образом координаты.


Вот одним из самых часто используемых способов
label start:
show katya ulibaetsya:
xalign 0.75 yalign 1.0
katya "Привет!!!"
Как вы увидели, мы прописали к изображению двоеточие, и в нем
прописали координаты (мы их подробней рассмотрим в разделе
Подробный разбор команд координатов)

2) ЦЕЛЫЕ ЧИСЛА [ИНСТРУМЕНТ]


Переведите вашу клавиатуру на английскую раскладку.
Нажмите на SHIFT + D, у вас высветится такой экран.

60
2018 Ren’Py

Далее нам потребуется выбрать раздел «Инструмент


позиционирования на изображениях».
Далее высветится список всех изображений, выбираете фоновое
изображение, которое вам необходимо и вы увидите в левом нижнем
углу координату, на которой находится мышка. Нажав на левую
кнопку, вы скопируете ее в буфер обмена.
label start: ###без отступа
show katya ulibaetsya: ###4 отступа от края
xpos 346 ypos 567 ###8 отступов от края
katya "Привет!!!" ###4 отступа от края
Что бы подробней рассмотреть координаты, зайдите в лаунчер ренпая
и запустите обучение. В нем выберите раздел Позиционирование на
экране. Там наглядный пример где и как располагать изображения.
Или выберите раздел Подробный разбор координат
Обратите внимание, все объекты вызываемые у вас появились
мгновенно(текст и изображения). Что смотрится не очень хорошо, что
бы исправить это почитайте следующие разделы.

61
2018 Ren’Py

КАК ПОМЕНЯТЬ ФОН, ЧТО БЫ В НЕМ НЕ ПРОПАЛИ


ОБЬЕКТЫ ДРУГИЕ

image bg komnata = "komnata.png"


image bg zal = "zal.png"
label start:
scene bg komnata
show katya prishur at left
show shora kazus at center
shora "Пошли в лес – город покажу"
katya "Ну пойдем!!!"
show bg zal # фон вызываем не превычным scene a show
katya "Похоже ты меня обманул насчет город покажу!!!"
Что мы сделали, мы прописали общий для фонов тег bg , и вызвав его
1 раз - мы задаем ему слой, и что бы поменять фон – не удаляя
обьекты, вам потребуется вызвать обьект с таким же тегом show bg zal

СКОРОСТЬ ПОЯВЛЕНИЯ ТЕКСТА


Существует 3 способа, которым можно задать скорость появления
текста.

1) Программное, для всего проекта.


Для этого зайдите в ваш файл-сценарий option.rpy и найдите такую
строку
## Стандартные настройки
#######################################################

## Контролирует стандартную скорость текста. По умолчанию, это 0 —


мгновенно,

62
2018 Ren’Py

## в то время как любая другая цифра — это количество символов,


печатаемых в
## секунду.

default preferences.text_cps = 0

Измените значение на 30
default preferences.text_cps = 30
Что бы изменения были внесены, вам потребуется выйти из проекта,
зайти в лаунчер ренпая и нажать на подпункт Очистить постоянные
Вы очищаете всю информацию что у него до этого было записано
(например сколько вы прошли текста для прокрутки а так же
системную информацию)

2) Прописать скорость через текстовые теги.


Текстовые теги – мини команды, которые влияют на текст
диалога(подчеркивание, курсив, скорость текста и т.д. подробней мы
рассмотрим в разделе Подробный разбор текстовых тегов) в
данном случае за скорость текста влияет тег {cps=25}текст{/cps}

Его можно применить в простом диалоге.

label start:
scene dom
"{cps=25}Быстро!!!! {/cps}{cps=5}очень медленно
медленно{/cps}"
{cps=25} - начало откуда у нас происходит действие тега, и до этого
момента тег на текст не влиял.
{/cps} – окончание действие тега. После него тег не действует.

63
2018 Ren’Py

3) Прописать тег персонажу


define e9 = Character("Eileen", what_prefix='{cps=25}',
what_suffix='{/cps}')
И потом где то в скрипте
label start:
e9 "Быстрый текст"
what_prefix='{cps=25}'- начало диалога у персонажа
what_suffix='{/cps}' – конец диалога у персонажа.

КАК ВЫЗЫВАТЬ ПЕРЕХОДЫ


ИЗОБРАЖЕНИЯМ?
В предыдущем разделе вы ознакомились, как настроить программно
скорость текста, теперь приступим к плавному появлению
изображения. Вызывают переходы оператором with. В ренпае есть 2
вида переходов – прописанный и те, которые вы сами создаете. Я
возьму в качестве основы 2 прописанных перехода и опишу их
значение.
Dissolve – плавное растворение. Данный переход растворяет
изображение, на который применяется он. Наиболее эффективен,
когда переходу подвергаются 2 одинаковых изображения (например, 2
спрайта, где в 1 глаза открыты – а в другом они закрыты) А так же при
смене фона.
Fade – вспышка! Очень быстрая смена изображения. Постоянно
применяется при смене локаций (была школа, бах with fade, и уже
локация дом!) а так же рекомендуется применять при переходе с фона
на одноцветный фон и наоборот. Пример как вызывать переход в
проект (вы можете скачать и рассмотреть более подробней
проект с изображениями по ссылке
https://yadi.sk/d/sZLgFFJ03USRik ).
label start:
scene komnata with dissolve
"Раздался звонок в дверь"
64
2018 Ren’Py

"Открыв его, я увидел свою лучшую подругу"


scene koridor with fade
show katya ulibaetsya at center with dissolve
katya "Привет!!!"
show katya prishur with dissolve
katya "Ты гулять идешь? Ммм?"
show katya prishur at left with dissolve
show shora kazus at center with dissolve
shora "Привет, я сегодня…"
menu:
"1) Буду занят":
show shora soshalen with dissolve
shora "…буду занят, прости"

show shora kazus at right with dissolve


show katya pechal at center with dissolve
katya "Блин жалко…."
show katya prishur with dissolve
katya "Завтра расскажи чем занят был то, хорошо?"
show katya prishur at left with dissolve
show shora kazus at center with dissolve
shora "Хорошо"
call internet
"2) Свободен":
show shora kazus with dissolve
shora "…свободен.."

65
2018 Ren’Py

show shora kazus at right with dissolve


show katya ulibaetsya at center with dissolve
katya "Класс!!!"
show katya prishur with dissolve
katya "Пошли тогда в кафешку перекусим!"
show katya ulibaetsya with dissolve
katya "Я сегодня сутра ничего не ела!"
show shora kazus at center with dissolve
show katya prishur at left with dissolve
shora "Подожди 1 минуту я переоденусь"
call kafe
В ренпае активно можно использовать анимации, для этого очень
часто принимают Alt анимации, а так же различные трансформации.

ALT АНИМАЦИИ
Анимации можно прописать отдельно, где нибудь в файле
сценария
init:
image ger_1:
"images/1/1.png"
pause 1.0
"images/1/2.png"
pause 1.0
repeat 2
и как вызвать в script.rpy
label start:

66
2018 Ren’Py

show ger_1 with dissolve


"Текст"

Теперь разберем что здесь записано


ger_1 – ссылка-метка
"images/1/1.png" – путь к 1 изображению
pause 1.0 – пауза длиной 1 секунда
"images/1/2.png" – 2 изображение, которое заменит 1
repeat 2 – число повторений, если просто записать repeat без цифр,
то она будет бесконечно повторяться(Что не рекомендую делать, т.к. я
прописал анимацию главного меню, каждую кнопку и т.д. запустил
проект и пошел по «неотложным делам» минут на 5. Возвращаясь я
увидел что ново-созданный проект вывел на экран ошибку, мол ему!
не хватило памяти, может быть со временем эту ошибку и исправили,
но я все равно по старой привычке ставлю ограничение 30
повторений, как говорится на всякий случай
Или сразу в тексте (минус – код выглядит громадным, а если
потребуется около 400 изображений прописать….)
label start:
show ger_1:
"katya shok1"
pause 1.0
"katya shok2"
pause 1.0
repeat 2
"Текст"

ТРАНСФОРМАЦИИ

67
2018 Ren’Py

Что такое трансформация? Это определенное имя со значением. В


данном случае это координаты по х и у.
Параметры х отвечают за горизонтальную плоскость.
Параметры y отвечают за вертикальную плоскость.
Нам нет необходимости постоянно прописывать координаты вручную,
ибо много писать, да и не нужно это, когда есть очень простой способ
прописывать данные координаты и вызывать их.
init:
transform pol_prav:
xalign 0.75
yalign 1.0
Как только вы ее объявите, вы сможете вызвать ее как стандартную
( через команду at )
show eileen happy at pol_prav
Мы их подробней рассмотрим в разделе Подробный раздел
трансформаций
Теперь, когда мы научились создавать простейшие диалоги и
вставлять изображения, нам нужно научиться изменять свое главное
меню и у вас получится простейшая новелла (по принципу Песня
Сайи, игра очень старая – но берет сюжетом, чего многим проектам не
хватает).
Что бы научиться редактировать главное меню вам потребуется
понять, что такое screen и как с ним работать. Это очень большой
раздел, в котором есть текстовые и графические кнопки, карты и т.д.

SCREEN
Прежде чем мы перейдем изменять главное меню, стоит лучше
познакомиться с экранами.
Экраны прописывают отдельно от диалогов, что бы ни путаться
создайте screen2.rpy
И пропишите в начале строки(как метки) следующий код:

68
2018 Ren’Py

screen simple_screen():
frame:
xalign 0.5 ypos 50
vbox:
text _("Это экран.")
textbutton _("Хорошо"):
action Return(True)
script.rpy
label start:
call screen simple_screen
Оператор screen говорит ренпаю, что это экран, и у него имя
simple_screen
Объект frame: используется, что бы показать на каких координатах
будет находиться данный экран и заключить ли в рамку этот экран
Объект vbox: расставляет вертикально все, что в нем пропишут
text _("Это экран.") – текст
textbutton – текстовая кнопка
action Return(True) – действие при нажатии

КАК ОТОБРАЗИТЬ ЭКРАН В ПРОЕКТЕ

1) show screen
show screen imya_ekrana
Данный экран будет показываться, пока его не скроют.
Скрывают экраны командой hide screen imya_ekrana
2) call screen

69
2018 Ren’Py

call screen imya_ekrana останавливает ренпай, пока экран либо не


вернется на какое либо действие, либо не прыгнет в другое место
Например
screen simple_screen():
frame:
xalign 0.5 ypos 50
vbox:
text _("Это экран.")
textbutton _("Хорошо"):
action Return(True)
laber start:
call screen simple_screen
У вас пропадет текстовый диалог, и пока вы не нажмете на «Хорошо»
и вы ничего не сможете сделать.
Когда заканчивается оператор call screen, экран автоматически
закрывается
В основном show screen применяется, что бы отобразить постоянные
элементы.(отображение кнопок инвентаря и т.д.)
А call screen, что бы отобразить короткие интерактивные экраны
(карта, вопрос какой нибудь)

КАК СОЗДАТЬ ГРАФИЧЕСКУЮ И


ТЕКСТОВУЮ КНОПКУ.

Самая простая кнопка – текстовая.


screen knopka:
frame:

textbutton _("Школа"):

70
2018 Ren’Py

xalign 0.5 ypos 50


action [ Jump("shkola"), Hide("inventar") ]

textbutton _("Дом"):
xalign 0.5 ypos 40
action [ Jump("home"), Hide("inventar") ]
textbutton _("Сумка"):
xalign 0.5 ypos 30
action Call ("inventar")

script.rpy
laber start:
"Что ты выберешь?"
call screen knopka

Это одна из самых простых кнопок, но смотрится она достаточно


скучно. Давайте пропишем ей текст уведомления при наведении и т.д.
screen knopka:
frame:

textbutton _("Школа"):
xalign 0.5 ypos 50
hovered Notify(_("Ты навел на кнопку"))
unhovered Notify(_("Ты отвел кнопку"))
action [Jump("shkola"), Notify(_("Ты нажал на кнопку"))]

textbutton _("Дом"):
xalign 0.5 ypos 40
hovered Notify(_("Ты навел на кнопку"))
unhovered Notify(_("Ты отвел кнопку"))
action [Jump("home"), Notify(_("Ты нажал на кнопку"))]
textbutton _("Сумка"):
xalign 0.5 ypos 30
hovered Notify(_("Ты навел на кнопку"))
unhovered Notify(_("Ты отвел кнопку"))
action [Call ("inventar"), Notify(_("Ты нажал на кнопку"))]

action Notify(_("Ты нажал на кнопку")) –при нажатии (action)


произойдет событие(Notify(_("Ты нажал на кнопку"))) – в данном
случае высветится надпись уведомления(Notify)

71
2018 Ren’Py

hovered – при наведении произойдет событие(обычно используется


что бы пояснять комментариями что произойдет при нажатии)

unhovered – как уберете кнопку, произойдет событие(используется


довольно часто, когда пользователю предстоит выбор)
А если вместо текста вы хотите использовать изображение, то
применяют imagebutton

ГРАФИЧЕСКИЕ КНОПКИ

Для создания такой кнопки вам потребуется 2 кнопки изображения,


кнопка в покое(idle), кнопка при наведении(hover)
screen imagebutton_example():
frame:
xalign 0.5 ypos 50
imagebutton:
idle "logo bw"
hover "logo base"
action Jump('ddde')

label start:
call screen imagebutton_example
Это мой самый любимый способ прописи графической кнопки. В нем
можно прописать модифицированные ренпаем графические
изображения(изображение цветное, а в ренпае сделали его чб)
Есть еще 1 способ, в нем автоматически берутся изображения.
screen gui_game_menu():
vbox xalign 1.0 yalign 1.0:
imagebutton auto "images/button_%s.png" action Jump('ddde')

label start:
call screen gui_game_menu

72
2018 Ren’Py

imagebutton auto –изображение которое автоматически(auto) берет


изображение с названием button_insensitive.png, button_idle.png,
button_hover.png и т.д.и автоматически будут действовать по заложенным
командам в их названии. используется для удобства(или теми кто не парится
насчет размера проекта, ибо нельзя будет применить различные
трансформации к изображениям). И не забудьте про _%s

"images/button_%s.png" – путь к изображению, где находится графическая


кнопка.

_%s – показывает программе что тут применяется авто подбор изображения

action Jum('ddde') – прыжок к метке ddde

У кнопок очень много возможностей, более подробней мы их


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

РЕДАКТИРУЕМ ГЛАВНОЕ МЕНЮ

Самый частый вопрос, который задавали в 2014-2016 году в


сообществе ренпая, был такой: КАК ДОБАВИТЬ ИЗОБРАЖЕНИЕ В
ГЛАВНОЕ МЕНЮ???
Объясняю. Главное меню у нас прописана в экране и находится он по
адресу screens.rpy и метка screen main menu():
screen main_menu():
tag menu
style_prefix "main_menu"
add gui.main_menu_background ###изображение меню
Изображения, анимации прописываются в экран через оператора add
как мы видим тут у нас gui.main_menu_background вы можете убрать
эту строку и записать свое изображение add "fon_menu" или зайдите в
файл gui.rpy и найдите эту строку

73
2018 Ren’Py

define gui.main_menu_background = "gui/main_menu.png"


и поменяйте путь к изображению.
Кнопки главного меню находятся в screen navigator():
В этом же файле находятся и другие экраны проекта(настройки –
screen preferences, истории - screen history, кнопки что в диалоге
появляются пропуск-сохранение – screen quick_menu(): ) – вы их все
можете самостоятельно отредактировать.

КАК ДОБАВИТЬ ЗВУК В ПРОЕКТ.


В экран
screen main_menu():
### Сразу прописываем музыку, что будет звучать в экране.
python:
renpy.music.play("menu.mp3", fadeout=10.0, fadein=15.0)
frame:
……………
Где "menu.mp3" путь к музыкальному файлу.
В проект
Что бы добавить фоновую музыку в проекте используют команду play
music
label start:
scene black
play music "illurock.ogg"
uchi "Приветствую Вас"
Музыка из-за канала music будет постоянно повторяться.
Так же можно при помощи питона вставлять музыку
$ renpy.music.play('theme.ogg')

74
2018 Ren’Py

Что бы звук 1 раз проиграл, используют канал sound


label start:
scene black
play sound "illurock.ogg"
uchi "Приветствую Вас"
Поздравляю, вы ознакомились с базовыми знаниями, которые вам
помогут создать свою простейшую визуальную новеллу. В следующих
разделах вы подробно рассмотрите основные функции и значения,
которые чаше всего применяются в ренпае, а так же питоновские
функции и фишки которые я чаще всего применяю при работе с
ренпаем.

ПОДРОБНЫЙ РАЗБОР
ВОЗМОЖНОСТЕЙ РЕНПАЯ
ДИАЛОГ, И ВСЕ ЧТО ПРОПИСЫВАЕТСЯ В
ТЕКСТОВОМ ДИАЛОГЕ.
Ранее мы прописывали в ознакомительной части как правильно
писать отступы, что бы ренпай мог запустить текст диалога.
label start: ### без отступа
scene komnata with dissolve
"Раздался звонок в дверь" ### 4 отступа
"Открыв его, я увидел свою лучшую подругу" ###4 отступа
Теперь мы подробней рассмотрим коды, которые помогут вам
улучшить внешний вид вашего проекта.

75
2018 Ren’Py

МНОЖЕСТВЕННЫЙ ДИАЛОГ
Иногда нам бывает необходимо вывести фразы сразу 2 персонажей,
что бы было сразу 2 фразы, используют команду multiple. Простой
пример такого кода:
define ele = Character(_("Жена"), color="#c8ffc8")
define lua = Character(_("Муж"), color="#c8c8ff")

label start:
ele "Где ты был?! Опять со своими дружками пил?!" (multiple=2)
lua "Дорогая я сейчас тебе все объясню! Только убери подальше эту
сковородку! Пока никого не поколечила!!!" (multiple=2)

ПИШЕМ ОТВЕТ ВМЕСТО ВЫБОРА

Более подробней здесь смотрите https://lemmasoft.renai.us/forums/viewtopic.php?


f=51&t=20704

reply.rpy
# Reply and Reply2
# by xavimat (cc-by, 2013)
# inspired by fiorica's "The Doll's Stories" and SusanTheCat's "Thera'Py"
# improved with help of jw2pfd

init python:

def reply(question = "Yes or no?",


answers = "yes,no",
invalid_character = None,
invalid_answer = "(Invalid answer)",
show_answers = True):

thequestion = question
found_it = ""
ans = answers.replace(" ", "")
ans = ans.split(",")

if show_answers:
thequestion += " {size=-10}("

for element in ans:


thequestion += element + ', '
thequestion = thequestion[:-2] + "){/size}"

76
2018 Ren’Py

while found_it == "":

phrase = renpy.input(thequestion)
phrase = phrase.lower()

for chara in ',.;:!?-+*()[]{}&%$':


phrase = phrase.replace(chara, ' ')
phras = phrase.split()

for element in ans:


for theword in phras:
if found_it == '' and element == theword:
found_it = element

if found_it == "":
renpy.say(invalid_character, invalid_answer)

return found_it

def reply2(question = "Yes or no?",


answers = "yes,no",
invalid_character = None,
invalid_answer = "(Invalid answer)",
show_answers = True):

thequestion = question
found_it = [ ]
ans = answers.replace(" ", "")
ans = ans.split(",")

if show_answers:
thequestion += " {size=-10}("

for element in ans:


thequestion += element + ', '
thequestion = thequestion[:-2] + "){/size}"

while found_it == [ ]:

phrase = renpy.input(thequestion)
phrase = phrase.lower()

for chara in ',.;:!?-+*()[]{}&%$':


phrase = phrase.replace(chara, ' ')
phras = phrase.split()

for element in ans:


for theword in phras:
if element == theword and element not in found_it:
found_it.append(element)

if found_it == [ ]:
renpy.say(invalid_character, invalid_answer)

return found_it
label start:
$ r = reply("Where can we go?", "park, beach, home")
if r == 'park':
# do something

77
2018 Ren’Py

elif r == 'beach':
# do something
else:
# do something

$ r2 = reply2("Where can we go?", "park, beach, home")


if "park" in r2:
e "You have chosen park"
if "beach" in r2:
e "You have chosen beach"
if "home" in r2:
e "You have chosen home"

$ l = len(r2)
if l > 2:
e "You have chosen too much."

#Note that with reply2() we don't use "elif" but separated "if" because all
of the keywords can be found. With "len()" you have the total of keywords
found in the user's reply.

СПИСОК ЗНАЧЕНИЙ АРГУМЕНТОВ ПРИ


СОЗДАНИИ ПЕРСОНАЖА
Ранее мы рассмотрели, как создается персонаж и почему нужны
нижнее подчеркивания (что бы в переводе имя отобразилось)
define uchi = Character(_("Учитель"), color="#008000", who_suffix = ':')
Теперь перейдем к значениям что используются в в персонажах.
Обратите внимание:
Все аргументы с
what_ -Связанны с именем
who_ -Связанны с диалогом
И подразумевают, что их можно использовать по отдельности
команды(шрифт имени и диалога например)

1) WINDOW_
Задаем фон заднего диалогового окна

78
2018 Ren’Py

define Sergey = Character(_("Sergey"),


window_background="gui/startextbox.png")

где "gui/startextbox.png" путь к изображению.


Убрать задний фон диалогового окна(нужна эта команда когда
создаешь диалог в виде субтитров)

define Sergey2 = Character(_('Sergey'), window_background=None)

Мы прописали только задний фон, а если требуется сделать спереди


фон диалог , то используют команду foreground.

define uchi = Character(_("Sergey"),


window_foreground="gui/textbox.png")

Очень часто его(foreground.) применяют при прописании головы


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

2) WHO_COLOR И WHAT_COLOR
Цвет имени и цвет диалога
define nino = Character(_("Нина"), who_color="#c8ffc8",
what_color="#ffc8c8")
Так же имени цвет можно задать командой color="#008000" вместо
who_color
define rish = Character(_('Рыжий'), color="#008000")

79
2018 Ren’Py

3) WHO_FONT И WHAT_FONT
Шрифт имени и шрифт диалога
define imya = Character(_("Имя"), who_font="font/Roboto-Regular.ttf",
what_font="font/Roboto-Light.ttf")
где "font/Roboto-Regular.ttf" путь к шрифту

4) WHAT_SIZE И WHO_SIZE
Размер букв диалога и имени
define imya = Character(_("Имя"), what_size=20, who_size=20)

5) WHAT_OUTLINES И WHO_OUTLINES
Обвести текст диалога и имени
define e5 = Character(_("Eileen"), what_outlines=[( 1, "#008000", 0, 0 )] )
Будет вот такой вид

define e6 = Character(_("Eileen"), what_outlines=[( 0, "#808080", 2, 2 )] )

6) WHAT_XALIGN И WHO_XALIGN
Контролирует где будет расположено в текст-боксе диалог

0.0 –Слева

80
2018 Ren’Py

0.5 –Середина

1.0 –Справа

define vasya1 = Character(_("Vasya"), what_xalign=0.5)

7) WHAT_TEXTALIGN И WHO_TEXTALIGN
Контролирует, как размещаются строки текста относительно друг
друга(обычно 0.5)
define vasya2 = Character(_("Vasek"), what_textalign=0.5)
_textalign и _xalign обычно всегда приводят в единое значение

8) WHAT_LAYOUT
Длина каждой строки.
Если поставить в значение what_layout='subtitle' то каждая строка
будет пытаться стать одинаковой по длине
define e7 = Character(_("Eileen"), what_layout='subtitle')
Помимо режима одинаковых строк (subtitle) есть режим все в 1
строку(nobreak)
define e7 = Character(_("Eileen"), what_layout='nobreak')

9) NONE
Диалог без имени
define e8 = Character(None)
И пример всего, что здесь прописывалось

81
2018 Ren’Py

define e8 = Character(None,window_background = None, what_size=28,


what_outlines=[( 1, "#008000", 0, 0 )], what_xalign=0.5,
what_textalign=0.5, what_layout='subtitle')

10) WHAT_PREFIX И WHAT_SUFFIX


what_prefix – Вставить в начале диалога (символы, курсив,
подчеркнутый….все теги что можно использовать в тексте)
what_suffix – Вставить в конце диалога (тоже самое только в конце)
define e9 = Character(_("Eileen"), what_prefix='"', what_suffix='"')

11) KIND
Копирует все аргументы имени-ссылки, что бы не печатать все кучу
раз то, что до этого прописывал, просто введите эту команду и
поменяйте нужные значение)
define frick = Character(kind=vasya1, what_outlines=[( 1, "#c00000", 0,
0 )] )

12) IMAGE
Добавить изображение в текст бокс
Пример. Прописываем ссылку-имя(дадим ему имя ru) на изображение
image side ru ="images/ru.png"

82
2018 Ren’Py

имя картинки ru.png находится в папке


imy_proekta/game/images
Далее, нам потребуется прописать в define эту картинку
define uchi = Character(_("Учитель"), color="#008000", image="ru",
who_suffix = ':')

Так же некоторые пользователи используют window_foreground

13) KIND=NVL

83
2018 Ren’Py

Перевести диалог из режима adv в nvl

define uchi = Character(_("Учитель"), color="#008000", image="ru", kind=nvl)

и наоборот

define uchi2 = Character(_("Учитель"), color="#008000", image="ru", kind=adv)

84
2018 Ren’Py

И из-за того что фразы-мысли написаны не через ссылку-имя, то они


будут вызываться в обычном adv режиме.
Шаблон для экрана nvl

define ser = Character(None, kind=nvl, what_prefix="Сергей: \"",


what_suffix="\"")

14) CTC
click to continue – нажми что бы продолжить

ИЗОБРАЖЕНИЕ, КОТОРОЕ СТАВЯТ В КОНЦЕ


ДИАЛОГА

Что бы пользователь знал, что фраза закончилась.

1) ПРИМЕР ИЗ ОБУЧЕНИЯ

Простейший пример из обучения. изображение arrow.png и


сделаем его плавно мигающим anim.Blink.
define uchi = Character(_("Учитель"), color="#008000", image="ru",
ctc=anim.Blink("arrow.png"), who_suffix = ':')

85
2018 Ren’Py

2) МОЙ ПРИМЕР

И пример который я делал при портировании на ренпай новеллы


"私は今日ここで死にます。" 4 изображения
- images/sys/icn размер 27 на 14
init:
image icn:
"images/sys/icn1.jpg" with dissolve
pause 0.5
"images/sys/icn2.jpg" with dissolve
pause 0.5
"images/sys/icn3.jpg" with dissolve
pause 0.5
"images/sys/icn2.jpg" with dissolve
pause 0.5
"images/sys/icn1.jpg" with dissolve
pause 0.5
"images/sys/icn.jpg" with dissolve
pause 0.5
repeat

define au2 = Character(None, window_background=None,


what_xalign=0.5, ctc=("icn"), what_layout='subtitle')###Autor ctc

86
2018 Ren’Py

3) Пример из леммы форума

image ctc_blink:
"GUI/arrow.png"
linear 0.75 alpha 1.0
linear 0.75 alpha 0.0
repeat

define gi = Character('Giselle',
color="#6699cc",
ctc="ctc_blink",
ctc_position="nestled")

ИЗОБРАЖЕНИЕ ЗА ДИАЛОГОВЫМ ОКНОМ


1) ПРИМЕР ИЗ ОБУЧЕНИЯ

define ectcf = Character(_('Eileen'), color="#c8ffc8",


ctc=anim.Filmstrip("sakura.png", (20, 20), (2, 1), .30, xpos=760, ypos=560,
xanchor=0, yanchor=0), ctc_position="fixed")
Пример на нижнем изображении.

87
2018 Ren’Py

2) МОЙ ПРИМЕР

И еще 1 пример который я делал при портировании на ренпай


новеллы "私は今日ここで死にます。"
Изображение "images/sys/icn_1.jpg" 162 на 14

define ke = Character(_('{color=6699ff}京介{/color}'), color="6699ff", what_prefix= '「 ',


what_suffix=' 」', window_background=None, what_xalign=0.5, what_textalign=0.5,
what_layout='subtitle', ctc=anim.Filmstrip("images/sys/icn_1.jpg", (27, 14), (6, 1), .30, xpos=978,
ypos=700, xanchor=0, yanchor=0), ctc_position="fixed")### Keoske

88
2018 Ren’Py

3) ПРИМЕР ИЗ ЛЕММАФОРУМА 1

image ctc_anchored:
"GUI/arrow.png"
yalign 0.96 xalign 0.95 #Adjust these numbers to fit your own textbox
linear 0.75 alpha 1.0
linear 0.75 alpha 0.0
repeat

define gi = Character('Giselle',
color="#6699cc",
ctc="ctc_anchored",
ctc_position="fixed")

4)ПРИМЕР ИЗ ЛЕММАФОРУМА 2. ВВЕРХ ВНИЗ СТРЕЛКА

image ctc:
"GUI/arrow.png", #This is your image
subpixel True #This line makes sure that ATL is smooth
yalign 0.96 xalign 0.95 #Adjust these numbers to fit your own textbox
linear 0.5 xalign 0.955
linear 0.5 xalign 0.95
repeat

89
2018 Ren’Py

5) ПРИМЕР ИЗ ЛЕММАФОРУМА 3. АНИМАЦИЯ

image ctc = Animation("GUI/ctc1.png", 1.0, #The second number is the time that
Ren'Py stays on this one image
"GUI/ctc2.png", 0.2,
"GUI/ctc3.png", 0.2,
xpos=1760, ypos=1000) #The position of the CTC, adjust for your own needs

15) DYNAMIC
должна быть строка, содержащая выражение питона. Эта строка
будет оценена перед каждой строкой диалога и результатом,
используемым в качестве названия символа.

define p = Character("player_name", dynamic=True)

(Корявый пример, дано условие if st > 5.0, и там прописываем имя Любимый,
который будет при условии st выше 5, в переменной player_name, а во всех
остальных условиях (Else) имя у персонажа будет Знакомый, а dynamic
позволяет включать питону проверку значений условий или нет)

16) VOICE_TAG
Это речевой тег, присваиваются к Character, речевые файлы(.ogg), которые
связаны с ним, могут отключать звук или воспроизводиться на
предпочтительном экране.

define l = Character("Lucy", voice_tag="lucy")

Пример из документации

define e = Character(_("Eileen"), voice_tag="eileen")


define l = Character(_("Lucy"), voice_tag="lucy")

90
2018 Ren’Py

screen voice_toggle:
vbox:
textbutton _(" Бесшумный режим Eileen ") action
ToggleVoiceMute("eileen")
textbutton _(" Бесшумный режим Lucy ") action
ToggleVoiceMute("lucy")

label start:
show screen voice_toggle

voice "e01.ogg"
e " Можно включить и выключить речь персонажа."

voice "l01.ogg"
l " Да! Теперь я могу наконец заткнуть Вас!"

voice "l02.ogg"
l " Подождите..., это означает, что они могут отключить звук мне также!
Действительно?"
Где это можно применить? простой пример Врата штейна или
Школьные дни, Кланнад – там в настройках есть режим отключить
голос определенному персонажу(или женские и мужские голоса)

Мы настроили персонажей, но вдруг вам потребуется в самом тексте


сделать огромными буквами восклицание персонажа или оформить
текст в отдельном месте? Тогда используют текстовые теги.

ПОДРОБНЫЙ РАЗБОР ТЕКСТОВЫХ ТЕГ


[СПИСОК]
Ниже список всех тегов что есть в ренпае (на момент написания
учебника)

1) ДОБАВИТЬ СПЕЦ СИМВОЛЫ В РЕНПАЙ \"


Например, кавычки
label start:

91
2018 Ren’Py

"Тут идет \"текст в кавычках" текст."

2) СТРОКУ ПЕРЕНЕСТИ НИЖЕ \N


label start:
"Шел текст \n бах упал и дальше пошел."

3) ПОЛУЖИРНОЕ НАЧЕРТАНИЕ {B}


label start:
"Пошел в макдаг текст {b}и стал он жирным{/b} и похудел он"

4) КУРСИВНОЕ НАЧЕРТАНИЕ {I}


label start:
"Получил в глаз текст {i}и стал он косить{/i} но в армию его
забрали"

5)ПОДЧЕРКИВАНИЕ ТЕКСТА {U}


label start:
"Зашел текст в магазин а там {u}РЕВИЗИЯ{/u} и пошел он назад"

6)ДОБАВЛЕНИЕ ЛИНИИ, ПРОХОДЯЩЕЕ


ПОСЕРЕДИНЕ ТЕКСТА {S}
label start:
"Поднял табличку текст {s}Денег нет{/s} Хорошего вам
настроения"

92
2018 Ren’Py

7) УВЕЛИЧИТЬ РАЗМЕР ТЕКСТА


{SIZE=+ЧИСЛО}
label start:
"Зашла девушка в туалет и поняла, что зашла в
{size=+30}Мужской туалет{/size} и сбежала оттуда"

8)УМЕНЬШИТЬ РАЗМЕР ТЕКСТА {SIZE=-


ЧИСЛО}
label start:
"РЕБЯТА ДАВАЙТЕ ЖИТЬ ДРУЖНО!!! {size=-9}я пожить еще
хочу{/size} Хорошо???"

9)СДЕЛАТЬ ПОСЕРЕДИНЕ ТЕКСТА ПАУЗУ


{W} И {P}
Альтернативный вариант(только еще переносит строку) {p}
label start:
"Жить хорошо,{w} А хорошо жить еще лучше"

label start:
"Жить хорошо {p}А хорошо жить еще лучше"

10)СДЕЛАТЬ ПАУЗУ НА КОРОТКОЕ ВРЕМЯ


(1СЕК) {W=1} {P=1}
Альтернативный вариант(только еще переносит строку) {p=1}
label start:
"Смотрю я, а там {w=1} мертвые с косами стоят{p=1}И ТИШИНА.."

93
2018 Ren’Py

11)ВСТАВИТЬ ИЗОБРАЖЕНИЕ ИЛИ СМАЙЛ В


ТЕКСТ {IMAGE=EXCLAMATION.PNG}
label start:
"Чмоки чмоки {image=kiss.png} {image=kiss.png}
{image=chmok.png} до встречи"

12)ПОМЕНЯТЬ ЦВЕТ
ТЕКСТА{COLOR=#008000}
label start:

"Чем меньше мы любим женщин – {color=#0066cc}Тем голубей{/color} наши мечты "

13)СОЗДАТЬ СВЕРХУ ТЕКСТА НАДПИСИ(ИХ


ПРАВИЛЬНОГО ПРОИЗНОШЕНИЯ) {RB}
label start:

"Название проекта{rb}私は今日ここで死にます。{/rb}{rt}Я хочу умереть сегодня{/rt}


дословный перевод"

14)СДЕЛАТЬ ТЕКСТ ВЕРТИКАЛЬНЫМ


{VERT}
label start:

scene black

centered "Название проекта{\n}{vert}私は今日ここで死にます。{/vert}{\n}Я сегодня


хочу умереть"

15)СДЕЛАТЬ ГОРИЗОНТАЛЬНЫЙ
ТЕКСТ{HORIZ}
(вы на нем пишите автоматически)

94
2018 Ren’Py

16)СОЗДАТЬ В ПРОЕКТЕ ССЫЛКУ НА САЙТ


{A=HTTPS://WWW.RENPY.ORG}
label start:

"Скачать самую новую версию ренпая вы можете здесь -


{a=https://www.renpy.org}Офф сайт ренпая{/a} оно бесплатно"

17)ГИПЕРССЫЛКА В ТЕКСТЕ
{a=jump:a_label} прыжок в метку a_label{/a}.
{a=call:a_label} вызываем метку a_label{/a}.
Существуют также {a=show:screen} и {a=showmenu:screen}, которые
показывают экраны в игре и в контексте меню,
соответственно(например, не забудьте сохраниться и ссылка в тексте
на сохранение и т.д.).
Так же в гиперссылках есть жесткая пауза. Пока вы не выберете пункт
экран, диалог не на что не реагирует, прописывают в конце
(advance=False)
Ellen "Хотели бы Вы идти {a=jump:living_room} на запад {/a} или
{a=jump:kitchen} на север {/a}?" (advance=False)

18)СДЕЛАТЬ ТЕКСТ
ПРОЗРАЧНЫМ{ALPHA=0.1}
"{ALPHA=0.1}ЭТОТ ТЕКСТ СТАЛ ПРОЗРАЧНЕЙ НА 10%
{/ALPHA}"

19)ЗАСТАВИТЬ ПОЯВЛЯТЬСЯ ТЕКСТ С


ОПРЕДЕЛЕННОЙ СКОРОСТЬЮ{CPS=25}
label start:

95
2018 Ren’Py

"Утренний зали{cps=1}ппппп{/cps}"

20)ПОМЕНЯТЬ ШРИФТ
ТЕКСТА{FONT=DEJAVUSANS-BOLD.TTF}
label start:

" А она такая: {font=DejaVuSans-Bold.ttf}Я никогда не пила – у меня голова потом


болит{/font}"

21)УМЕНЬШИТЬ ОТСТУПЫ СИМВОЛОВ


МЕЖДУ СОБОЙ
{k=-.5}текст{/k} и наоборот {k=.5}текст{/k}

22)СДЕЛАТЬ ОТСТУП
ГОРИЗОНТАЛЬНЫЙ(ПУСТОЕ
ПРОСТРАНСТВО)
" текст {space=30} текст"

23)СДЕЛАТЬ ОТСТУП
ВЕРТИКАЛЬНЫЙ(МЕЖДУ СТРОКАМИ)
{vspace=30}

24)НЕМЕДЛЕННО ПЕРЕЙТИ К
СЛЕДУЮЩЕМУ ТЕКСТУ И ИСПОЛЬЗОВАТЬ
РАЗНЫЕ ПЕРЕХОДЫ

"диалог{nw}"
with fade
"диалог"

96
2018 Ren’Py

25)ЧТО БЫ ПЕРЕМЕННАЯ ОТОБРАЖАЛАСЬ В


ПЕРЕВОДЕ, В КОНЦЕ НЕЕ СТАВЯТ !T

$ translatable = _(u"переводимый текст"!t)


"текст [translatable] "

26)ВЫВЕСТИ ВЕСЬ ТЕКСТ СРАЗУ НА ЭКРАН.


"текст {fast} весь текст"

КАК ДОБАВИТЬ СЛУЧАЙНУЮ ФРАЗУ В


КОНЦЕ ПРЕДЛОЖЕНИЯ

# как добавить случайную фразу в конце предложения


init python:
v = "" # переменная для текущего варианта
varik = ["того этого", "значица", "эт самое", "как бы"] # варианты
def newsfx(): # сама функция
global v
v = ", " + renpy.random.choice(varik)
NewSfx = renpy.curry(newsfx) # превращаем в action
newsfx() # сразу инициируем
vv = Character(u"Имярек") # просто перс
# в файле screens.rpy в начале экрана screen say добавить строку:
# on "show" action NewSfx()
label start: # тест
vv "Привет[v]."
vv "Как дела[v]?"
vv "Чо делаешь[v]?"
vv "И тишина[v]..."
vv "Ой, всё[v]!"
return

97
2018 Ren’Py

ВЫСТАВЛЯЕМ ПОЗИЦИЮ ДЛЯ ИМЕНИ


ПЕРСОНАЖА
Бывает так, что стандартные позиции имени в ренпае не совсем
подходят для проекта. Сейчас вы подробней изучите как можно задать
координаты для имени персонажа.

1)КОСТЫЛЬ, НО ЧУТЬ ЛИ НЕ
ЕДИНСТВЕННОЕ РЕШЕНИЕ, ЕСЛИ У ВАС
СЛОЖНАЯ РАМКА.

Он же и самый простой для новичка, в фотошоппе создаете


изображение с именем в текстовом боксе

И прописываете его в персонаже (имя не прописываем!!!!)


define leyns = Character(None,
window_background="images/leynsname.png")
где "images/leynsname.png" путь к изображению.
Так же я встречал хардковщиков которые создавали в png чисто имя
персонажа и записывали его в window_foreground
У данного способа плюсы:
1)Простота
2) Можно добавить сразу 2 персонажей, которые сказали 1 и ту же
фразу
Пример:
Персонаж говорит своим подругам

98
2018 Ren’Py

"Алена" "Девочки... Я беременна..."


и вызываем персонажа, у которого текстовый бокс
справа имя Надя и слева имя Катя
nad_kat "Что??????"
3) Можно сделать сложные текстовые поля

Минус:
У вас проект будет весить чуть больше чем, если вы будете
пропечатывать в истинном способе
У вас должны быть базовые знания по фотошоппу или иным
приложениям.

И САМЫЙ ГЛАВНЫЙ МИНУС- при создании


перевода, переводчику потребуется извлечь текст из изображения, и
самому таким же способом создать изображение рамки с именем, а
если рамка сложная и текст там чуть ли не ключевую роль
занимает…. Вы бы знали как я мучался с проектом
私は今日ここで死にます。Ибо там весь текст с главным смыслом был
сделан в виде изображений… У меня словарного запаса не хватит
выразить всю любовь к такому поступку разработчика, он даже в
комментариях не написал что там записано… И перевод ой как
задержался из за того, что программа по извлечению текста корректно
не могла прочитать эти иероглифы!

2)ИСТИННЫЙ НО САМОЕ ТО ДЛЯ КУЧИ


ИМЕН С ОДИНАКОВЫМИ ЗНАЧЕНИЯМИ.

Прописываем персонажа
define e = Character('Эйлин', color="#c8ffc8")

99
2018 Ren’Py

Далее вам понадобится зайти в сценарий gui.rpy и найти такие строки

Все что в диалоге, прописывается здесь, но обратите внимание на эти


строки

100
2018 Ren’Py

define gui.name_xpos = 240


define gui.name_ypos = 0.0
Они отвечают за координаты текста имени.
Далее как вы отрегулировали координату текста, вам нужно прописать
единые изображения текстового поля. Для этого вам нужно зайти в
сценарий screen.rpy

Как тут видно все, что связанно с background это изображения


которые нужно нам поменять
Минусы
1)Долгая настройка

101
2018 Ren’Py

2)Невозможность применить к сложным текст боксам


Плюсы
1)Меньше весит проект
2)Вам не придется 100 раз прописывать 1 и те же координаты для
кучи персонажей
3) При создании перевода переводчик расцелует того кто сделал как
надо код.

КАРТИНКИ В КНОПКАХ ВЫБОРА [MENU]

(http://renpyfordummies.blogspot.com/2018/05/gui.html?m=1)
# стандартные настройки меню
define gui.choice_button_width = 1280
define gui.choice_button_height = 72
define gui.choice_button_borders = Borders(150, 16, 150, 16)

102
2018 Ren’Py

define gui.choice_button_text_xalign = 0.5


define pad = 150 # отступ для картинки слева

init python:
# автоматическое объявление изображений
images_auto()
window_center()

# поиск тегов с настройками кнопки


import re
def get_tags(text, prefix='#'):
# выуживаем все теги ремарок
return re.findall('{' + prefix + '([^}]+)}', text)

# поиск в строке тега (и его значения) по имени


def get_tag(text, tag, default=None):
val = default
tags = get_tags(text)
for i in tags:
parts = i.split('=')
if len(parts) > 0:
if parts[0].strip() == tag.strip():
if len(parts) > 1:
val = parts[1]
return val

# найти в ремарках значение тега 'image'


def get_image(text):
# по-умолчанию картинки нет
return get_tag(text, 'image')

# найти в ремарках значение тега 'align'


def get_align(text):
# по-умолчанию выравнивание текста берем стандартное
return float(get_tag(text, 'align',
str(gui.choice_button_text_xalign)))

# переназначаем экран выбора


screen choice(items):
style_prefix "choice"
vbox:
for i in items:
button:
action i.action
background None
xpadding 0 ypadding 0 xmargin 0 ymargin 0
textbutton i.caption action i.action text_xalign
get_align(i.caption)

103
2018 Ren’Py

add get_image(i.caption) yalign .5 xpos pad

label start:
menu:
"Текст по центру":
pass
"{#image=vk} Текст в центре, картинка слева":
pass
"{image=vk} Текст в центре, картинка рядом с текстом":
pass
"{#image=vk} {image=pref} Текст с картинкой в центре, картинка
слева":
pass
"{#image=vk} Картинка слева, текст справа{#align=1.0}":
pass
"{image=pref} Текст с картинкой слева{#align=.0}":
pass
"{#image=vk}{image=pref} Текст с картинкой слева и картинка
слева{#align=.25}":
pass
return

СПЕЦИАЛЬНЫЕ ПЕРСОНАЖИ В РЕНПАЕ


В ренпае существуют так же свои специально прописанные
персонажи, которые облегчают жизнь разработчикам. Ниже список
персонажей

1)ПЕРСОНАЖ CENTERED
Он позволяет вам писать текст на середине экрана (диалоговое окно
убирается). Очень часто используется в сочетании черного и белого
фона. Не заменимая вщь при создании титров и пролога
scene black
centered "Первое что сказал он, когда зашел в класс"

104
2018 Ren’Py

2)ПЕРСОНАЖ VCENTERED
Все аналогично 1 персонажу только вертикально (очень удобно на нем
иероглифы прописывать)
scene black
vcentered "Первое что сказал он, когда зашел в класс"

105
2018 Ren’Py

3)ПЕРСОНАЖ EXTEND
Он позволяет расширить предыдущую строку диалога
дополнительным текстом, т.е. он позволяет делать различные вещи
во время диалога. Пример
show eileen vhappy ###Спрайт шок
extend "Кошмар,"
show eileen kosmah ###спрайт крик
extend "я деньги забыла!!!"
И получаем: идет сплошной текст: Кошмар, Я деньги забыла!!!
только после слова кошмар спрайт авт меняется, ед. условие текст
должен идти плавно, а не мгновенно. Тогда будет эффект.

4)ПЕРСОНАЖ EXPRESSION

106
2018 Ren’Py

Диалоговое окно не убирается


label start:
show expression Text(_("Это- текст." size=50, yalign=0.5,
xalign=0.5, drop_shadow=(2, 2)) as text
ei "Вы можете…"

ПОДРОБНЫЙ РАЗДЕЛ КООРДИНАТ


ИЗОБРАЖЕНИЙ
Pos – точечная координата xpos и ypos
show logo blue: ###Эйлин
xpos 300 ypos 100

Anchor – точка позиционирования (его часто используют что бы


наложить на другом изображении еще 1 изображение) xanchor и
yanchor
show logo blue: ###Эйлин

107
2018 Ren’Py

xpos 300 ypos 100


show anchor: ###Крестик
xanchor 0.5 yanchor 0.5
xpos 300 ypos 100
Align – объединение Pos и Anchor (самая часто используемая
команда) xalign и yalign
show logo blue: ###Эйлин
xalign 0.3 yalign 0.2

Если при создании анимации у вас не меняется координата, то вместо


него поставьте Anchor например
Center – позиционируют центр изображения xcenter и ycenter. Если вы
поставите значение на 1, то половина изображения исчезнет
show eileen happy:
xcenter 1.0

ПОДРОБНЫЙ РАЗДЕЛ
ТРАНСФОРМАЦИЙ[СПИСОК]

1)СМЕНА ФОНА С ПЕРЕХОДОМ (НАПРИМЕР,


РАСТВОРЕНИЕ)
init:
image pic1 = "risunok_1.png"
image pic2 = "risunok_2.png"
image pic_anim:
"pic1" with dissolve
pause 1.0
108
2018 Ren’Py

"pic2" with dissolve


pause 1.0
repeat

label start:
scene pic_anim
Так же можно и к спрайтам с кнопками применить данную
трансформацию

2)ТЕЛЕПОРТ
init:
image pic1 = "risunok_1.png"
transform teleport:
xalign 1.0 yalign 0.0
pause 1.0
xalign 0.0
repeat
label start:
show pic1 at teleport

И наш спрайт (или фон если вместо show будет scene) будет
телепортироваться (мгновенно менять свои координаты) (с xalign 1.0
(т.е. с левой стороны) на xalign 0.0 (на правую сторону)

3) ИНТЕРПОЛЯЦИЯ ВРЕМЕНИ LINEAR


Интерполяция – плавное смещение значений трансформации, от
старого к новому.

109
2018 Ren’Py

Пример на телепорте, добавим в него интерполяцию времени linear


(таймер по сути своей, но не совсем таймер)
Интерполяции всегда пишутся вначале изменений старого и нового
значения (пример справа налево)
init:
transform move_pra_lev:
xalign 1.0 yalign 0.0
linear 3.0 xalign 0.0
pause 1.0
repeat
label start:
show pic1 at move_pra_lev
И получаем, что объект, будет плавно перемещаться по экрану, за 3
сек. (Вы можете спокойно скорость передвижения изменить, поменяв
значение linear)
А вот пример с правого нижнего угла в верхний левый угол, и обратно,
то пишут в интерполяции х и у, и опять через интерполяцию ее путь
назад.
init:
transform z_z:
xalign .3 yalign .7
linear 1.0 xalign .7 yalign .3
linear 1.0 xalign .3 yalign .7
repeat

label start:
show logo base at z_z

110
2018 Ren’Py

4) ZOOM ZOOM
Zoom позволяет нам увеличивать или уменьшать изображение, делая
его больше или меньше.
Пишется он очень просто. Можно через анимацию алт или
трансформацию.
Анимация
image pic1 = "risunok_1.png" ###спрайт девушки в гневе
image pic2 = "risunok_2.png"###спрайт парень в шоке
label start:
show pic1 ###спрайт девушки в гневе
"Она" "Я беременна!"
show pic1: ### Девушка плавно увеличилась
zoom 1.0
linear 1.0 zoom 1.5
show pic2 at right: ###парень плавно уменьшился
zoom 1.0
linear 1.0 zoom 0.5
"Он" "Оп-па…."

И вот так их прописывают в трансформацию


init:
transform hana:
zoom 1.0
linear 1.0 zoom 1.5
transform hana_emy:
zoom 1.0 xalign 1.0
linear 1.0 zoom 1.5 xalign 1.0

111
2018 Ren’Py

image pic1 = "risunok_1.png" ###спрайт девушки в гневе


image pic2 = "risunok_2.png"###спрайт парень в шоке
label start:
show pic1
"Она" "Я беременна!"
show pic1 at hana ### Девушка плавно увеличилась
show pic2 at hana_emy
"Он" "Оп-па…."
Так же помимо одновременного изменения всего изображения, можно
по отдельности изменять значение х и у.
Пишется все это через xzoom и yzoom. Пример
init:
transform hana:
zoom 1.0
linear 1.0 zoom 1.5
transform hana_emy:
zoom 1.0 xalign 1.0
linear 1.0 zoom 1.5 xalign 1.0
transform toshnotiki:
xzoom .75 yzoom 1.25
linear 1.0 xzoom 1.25 yzoom .75
linear 1.0 xzoom .75 yzoom 1.25
repeat
image pic1 = "risunok_1.png" ###спрайт девушки в гневе
image pic2 = "risunok_2.png"###спрайт парень в шоке
image pic1_1 = "risunok_3.png"### спрайт девушки вся зеленая,
плохо ей

112
2018 Ren’Py

label start:
show pic1_1 at toshnotiki
"Меня тошнит"
"Звук, как кто-то свой завтрак керамическому другу отдает"
scene black
show pic1
"Она" "Я беременна!"
show pic1 at hana
show pic2 at hana_emy
"Он" "Оп-па…."
А приведя значения в отрицательное значение xzoom и yzoom мы
отразим объект (зеркально) по гориз и вертикали
show logo base:
linear 1.0 xzoom -1.0 yzoom 1.0

5) SIZE
Данный оператор позволяет нам задать изображению размер (Сразу
вспоминается момент, когда хотел сделать в проекте несколько
разрешений экрана при помощи данного оператора, говорю сразу
бесполезная затея, поэтому лучше не тратьте время зря)
show logo base:
size (300, 450)
И изображение будет иметь разрешение 300 на 450

113
2018 Ren’Py

6)АЛЬФА
Данный оператор задает прозрачность к применяемому объекту.
init:
transform vszhik:
alpha 1.0
linear 1.0 alpha 0.0
linear 1.0 alpha 1.0
repeat
label start:
show pic_1 at vszhik

7) ROTATE.
Нам требуется, что бы изображение крутилось вокруг себя, в этом нам
поможет Rotate.
Пример на 360 градусов

show logo base:


xpos 0.5 ypos 0.5 xanchor 0.5 yanchor 0.5 ###задаем координату, не
обязательно,но я задал по середине, и еще Так как вращение может
изменить размер я поставил xanchor 0.5 yanchor 0.5
rotate 0
linear 4.0 rotate 360 ###на 360 градусов
repeat

114
2018 Ren’Py

8) СROP. ОБРЕЗКА
Вам требуется что бы персонаж выглядывал из за угла, или с
одеяла(видел пример такой) или половина тела(берегись
поез………………..) то вызывают оператора Сrop.
show logo base:
crop (0, 0, 100, 307)
Где в скобке указанно как оно будет обрезана.
Так же через него можно сфокусироваться(приблизить) на
изображении
show bg washington:
crop (0, 0, 800, 600)
size (1280, 720)
linear 4.0 crop (451, 437, 409, 230)

9) АЛТ ТРАНСФОРМАЦИЯ
Так как стандартные блоки(left, right, center….и т.д) являются
трансформациями, то мы можем их просто записать как они есть.
show eileen happy:
right
pause 1.25
left

115
2018 Ren’Py

pause 1.25
repeat

10) ОПЕРАТОР ВLOCK И TIME. БРАТЬЯ


НЕРАЗЛУЧНЫЕ
Вlock позволяет поставить блок. Так как оператор repeat применим к
блокам, что позволит повторить лишь часть трансформации.
Тime – обычный таймер, по истечению времени он прекратит все что
вы задали, он прервет его даже если другой код уже работает.
Пример: изображение с середины экрана начнет перемещаться
справа-налево 11.5 секунд, и остановится на левой стороне.
show logo base:
xalign 0.0 yalign 0.0
block:
linear 1.0 xalign 1.0
linear 1.0 xalign 0.0
repeat
time 11.5
linear .5 xalign 1.0

11) ОПЕРАТОР PARALLEL


Он позволяет нам использовать одновременно несколько операторов
одновременно. Пример.

1) МАГИЯ СРЕДИ НАС

init:

116
2018 Ren’Py

image magic = "risunok_1.png"


label start:
show magic:
yalign .5 subpixel True

parallel:
xalign .5
linear 3.0 xalign .75
linear 6.0 xalign .25
linear 3.0 xalign .5
repeat

parallel:
alpha 1.0 zoom 1.0
linear .75 alpha .5 zoom .9
linear .75 alpha 1.0 zoom 1.0
repeat

parallel:
rotate 0
linear 5 rotate 360
repeat

117
2018 Ren’Py

Изображение

Рисунок, крутится, меняет свой размер, и исчезает.

2) ИЗОБРАЖЕНИЕ СКАЧЕТ ПО ЭКРАНУ НА ВСЕ 4 СТОРОНЫ.

show logo base:


parallel:
linear 1.0 xalign 0.0
linear 1.0 xalign 1.0
repeat
parallel:
linear 1.3 yalign 1.0
linear 1.3 yalign 0.0
repeat

12) ОПЕРАТОР СHOICE


Оператор Сhoice случайно запускает из вариантов-блоков

118
2018 Ren’Py

show logo base:


choice:
linear 1.0 xalign 0.0
choice:
linear 1.0 xalign 1.0
repeat

13) ВЫХОДИМ ЗА ПРЕДЕЛЫ ЭКРАНА.


До этого мы писали, как картинку поставить на экране. А что если нам
требуется не картинку переставить, а сам экран?
Тут нам потребуется немного поработать в фотошоппе и увеличить
размер картинки в 2 раза(от разрешение проекта), сохраняя ее
пропорции(а то будет квазиморда), после того, как изображение было
подготовлено, вызываем ее

image pic1 = "risunok_1.png"


label start:
show pic1:
xanchor 0 yanchor 0 xpos 0 ypos -222
with dissolve
show pic1:
xanchor 0 yanchor 0 xpos 0 ypos -222
linear 5.0 xpos -435 ypos 0
Картинка то больше чем ваш экран и естественно, что она вся не
помещается на экран,

119
2018 Ren’Py

Что бы выйти за пределы экрана вам потребуется записать значения


координат которые будут больше или меньше чем экран

14) БЛОК ON
Данный блок отвечает за 2 события – событие включено и отключено.
И оно тем самым создает условия и значения при вкл и откл

1)КНОПКИ

init:
transform pulse_button:
on hover:
linear .25 zoom 1.25
linear .25 zoom 1.0
on idle:
linear .25 zoom 1.0
linear .25 zoom 1.25

Потом требуется зайти в скрипт screen.rpy и найдите кнопки, которые


отвечаю за главное меню и допишите выделенные фрагменты.

screen navigation():

vbox:
style_prefix "navigation"

xpos gui.navigation_xpos
yalign 0.5

spacing gui.navigation_spacing

if main_menu:

120
2018 Ren’Py

textbutton _("Начать") at pulse_button action Start()

else:

textbutton _("История") at pulse_button action ShowMenu("history")

textbutton _("Сохранить") at pulse_button action ShowMenu("save")

textbutton _("Загрузить") at pulse_button action ShowMenu("load")

textbutton _("Настройки") at pulse_button action


ShowMenu("preferences")

Теперь посмотрим на то, что происходит: При наведении кнопка


немного увеличивается в размере, и как только мы уберем кнопку, она
уменьшается в размере

2)РАСТВОРЕНИЕ

init:
transform logo_base:
on show:
alpha 0.0
linear .5 alpha 1.0
on hide:
linear .5 alpha 0.0
on replace:
linear 2.0 alpha 1.0
on replaced:
linear 2.0 alpha 0.0

repeat
label start:

121
2018 Ren’Py

show eileen happy at logo_base


pause
hide eileen happy
pause
Теперь рассмотрим что получили. При вызове изображения (show
eileen happy) она у нас появилась растворением, и когда ее
убираем(hide eileen happy) она у нас исчезает так же растворением.
Т.е. не нужно 100 раз прописывать разные переходы, достаточно 1 раз
прописать трансформацию и вызывать в нужные моменты.

3) КАК ЗАДАТЬ СПЕЦ МЕЛОДИЮ ПРИ ПРОПУСКЕ.

В файле screen.rpy находите экран пропуска и добавте следующее:

screen skip_indicator():
on 'show' action Play('music', 'faster.mp3')
on 'hide' action Play('music', 'normal.mp3')

15) CONTAINS
Оператор contains позволяет применять к уже прописанной трансформации
еще операторов.
init:
transform an_animation:
"1.png"
pause 2
"2.png"
pause 2
repeat

image move_an_animation:
contains an_animation

xalign 0.0
linear 1.0 yalign 1.0

122
2018 Ren’Py

16) FUNCTION
init python:
def slide_function(trans, st, at):
if st > 1.0:
trans.xalign = 1.0
return None
else:
trans.xalign = st
return 0

label start:
show logo base:
function slide_function
pause 1.0
repeat

Что оно значит, я не знаю, но в этом примере изображение слева движется направо.

17)РАЗЛИЧНЫЕ ИНТЕРПОЛЯЦИИ WARPERS


Warpers является функцией, которая может изменить количество времени, которое
оператор интерполяции рассматривает для протекания. Следующие Warpers
определены по умолчанию.

Кому интересно вот отрывок из офф документации

A warper is a function that can change the amount of time an interpolation


statement considers to have elapsed. The following warpers are defined by
default. They are defined as functions from t to t', where t and t' are floating
point numbers, with t ranging from 0.0 to 1.0 over the given amount of time.
(If the statement has 0 duration, then t is 1.0 when it runs.) t' should start at
0.0 and end at 1.0, but can be greater or less.
pause

Pause, then jump to the new value. If t == 1.0, t = 1.0. Otherwise, t' = 0.0.

linear

123
2018 Ren’Py

Linear interpolation. t' = t

ease

Start slow, speed up, then slow down. t' = .5 - math.cos(math.pi * t) / 2.0

easein

Start fast, then slow down. t' = math.cos((1.0 - t) * math.pi / 2.0

easeout

Start slow, then speed up. t' = 1.0 - math.cos(t * math.pi / 2.0)

In addition, most of Robert Penner's easing functions are supported. To


make the names match those above, the functions have been renamed
somewhat. Graphs of these standard functions can be found at
http://www.easings.net/.

Ren'Py Name easings.net Name

ease_back easeInOut_back

ease_bounce easeInOut_bounce

ease_circ easeInOut_circ

ease_cubic easeInOut_cubic

ease_elastic easeInOut_elastic

ease_expo easeInOut_expo

ease_quad easeInOut_quad

ease_quart easeInOut_quart

ease_quint easeInOut_quint

easein_back easeOut_back

easein_bounce easeOut_bounce

easein_circ easeOut_circ

easein_cubic easeOut_cubic

124
2018 Ren’Py

Ren'Py Name easings.net Name

easein_elastic easeOut_elastic

easein_expo easeOut_expo

easein_quad easeOut_quad

easein_quart easeOut_quart

easein_quint easeOut_quint

easeout_back easeIn_back

easeout_bounce easeIn_bounce

easeout_circ easeIn_circ

easeout_cubic easeIn_cubic

easeout_elastic easeIn_elastic

easeout_expo easeIn_expo

easeout_quad easeIn_quad

easeout_quart easeIn_quart

easeout_quint easeIn_quint

New warpers can be defined using the renpy.atl_warper decorator, in a python early
block. It should be placed in a file that is parsed before any file that uses the warper.
This looks like:

python early hide:

@renpy.atl_warper
def linear(t):
return t

ПРИМЕР ИСПОЛЬЗОВАНИИ
init:

# взгляд вниз, затем вверх

125
2018 Ren’Py

transform downup:

yanchor 1.0

yalign 0.0

easein 3.0 yalign 1.0

easeout 3.0 yalign 0.0

# взгляд вверх, затем вниз

transform updown:

yanchor 1.0

yalign 1.0

easein 3.0 yalign 0.0

easeout 3.0 yalign 1.0

ПЛАВНЫЙ ПЕРЕХОД ТЕКСТА

Gif анимация https://3.bp.blogspot.com/-


kdEdAcOFNZ4/Wa7g3QyR7SI/AAAAAAAA4SA/I39kQlrggMscTyzHTT0nkma3lRk4iJjfACLcBGA
s/s640/renpy-fade-text-screens.gif

screen info_fade:

text "Look. I'm fading about." at fade_inout_2s

init:
transform fade_inout_2s:
xalign 0.5
yalign 0.5
alpha 0.08
easeout_back 2 alpha 0.9
pause 0
ease 2 alpha 0.0

label start:
scene bg room
"Ok, here we go."
show screen info_fade

126
2018 Ren’Py

pause 6
"That was nice."
pause
return

18) ALIGNAROUND И CLOCKWISE CIRCLES


alignaround -данный оператор заставляет изображение совершать
круговые движения
clockwise circles – число кругов.
Как будто воронкой затянуло
show logo base:
alignaround (.5, .5)
linear 2.0 xalign .5 yalign .5 clockwise circles 3

19)AROUND
Устанавливает центр координатной позиции на абсолютную позицию
show logo small:
anchor (0.5, 0.5)
around (640, 216)

20) ANGLE
Устанавливает значение угла в градусах
show logo small:
linear 1.0 angle 315
linear 1.0 angle 270
repeat

127
2018 Ren’Py

21) RADIUS
Определяет дистанцию от заданной позиции до центра координат
show logo small:
linear 1.0 radius 100
linear 1.0 radius 200
repeat

22)TILE
Клонирование объектов
show logo base:
xtile 3
ytile 2
Получаем 6 одинаковых изображений

23) PAN
Создать панораму

show bg panorama:
xpan 0

128
2018 Ren’Py

linear 10.0 xpan 360


repeat

Где xpan 0 – точка отсчета середина изображения

24) OFFSET
Прописывают в конце всех операторов, смещают изображение
вправо или вниз на то, сколько указали в их значении xoffset и yoffset

25) RANDMOTION
Что бы его вызвать, нужно немного поработать в питоне.
init:

python hide:

def gen_randmotion(count, dist, delay):

import random

args = [ ]

for i in range(0, count):

args.append(anim.State(i, None,

Position(xpos=random.randrange(-dist, dist),

ypos=random.randrange(-dist, dist),

xanchor='left', yanchor='top',

)))

for i in range(0, count):

129
2018 Ren’Py

for j in range(0, count):

if i == j:

continue

args.append(anim.Edge(i, delay, j, MoveTransition(delay)))

return anim.SMAnimation(0, *args)

store.randmotion = gen_randmotion(5, 5, 1.0)

Потом его применяем на спрайте


show eileen happy at randmotion
Как мы видим, спрайт движется, как будто дышит и двигается

130
2018 Ren’Py

АВТОМАТИЧЕСКОЕ ОБЪЯВЛЕНИЕ
АНИМАЦИИ
(http://renpyfordummies.blogspot.ru/2015/06/init-python-def-ani-imgname-
frames.html)

init python:
"""
описание функции Ani:
автоматическое объявление картинки с анимацией,
например есть кадры "images/neko%s.png",
где %s - числа от 1 до 5, тогда объявляем анимацию так:
image neko = Ani("neko", 5, 0.5, reverse = False)
где:
img_name - имя файла без номера (например, "neko")
frames - количество кадров
delay - пауза между кадрами в секундах
loop - зациклить анимацию (по умолчанию включено)
reverse - нужно ли проигрывание анимации в обратную сторону
effect - эффект для смены кадров
start - с какой цифры начинать отсчет кадров
ext - расширение файлов (по умолчанию png)
"""
def Ani(img_name, frames, delay=.1, loop=True, reverse=True, effect=None,
start=1, ext="png", **properties):
args = []
for i in range(start, start + frames):
args.append(renpy.display.im.image(img_name + str(i) + "." + ext))
if reverse or loop or (i < start + frames - 1):
args.append(delay)
args.append(effect)
if reverse: # обратная анимация, если нужна
for i in range(start + frames - 2, start, -1):
args.append(renpy.display.im.image(img_name + str(i) + "." + ext))

131
2018 Ren’Py

if loop or (i > start + 1):


args.append(delay)
args.append(effect)
return anim.TransitionAnimation(*args, **properties)

init:
# эффект dissolve в полсекунды с учетом прозрачности
$ dd = Dissolve(.5, alpha=True)
# 5 кадров, смена раз в полсекунды и эффектом для смены кадров
# по умолчанию зациклена и с обратным ходом
image neko = Ani("neko", 5, .5, effect=dd)

label start:
show expression "bg_room.jpg"
show neko
pause
return

ПОДРОБНЫЙ РАЗБОР ПЕРЕХОДОВ И


СПЕЦЭФФЕКТОВ
Существует несколько типов переходов, одни уже изначально
прописаны в самом ренпае. Другие вам самим придется создавать. В
этой главе мы рассмотрим все прописанные переходы, и покажу как
создавать свои спец эффекты.

1) WITH DISSOLVE
label start:
scene logo with Dissolve(.5)
pause .5

132
2018 Ren’Py

Теперь разберем что тут записано


scene logo –вызываем изображение, текст, и т.д
with – Вызов перехода
Dissolve(.5) – имя перехода
Обратите внимание! В питоне всего несколько стандартных
переходов, которые автоматически прописаны. Но вдруг вы
столкнетесь с интересным для вас переходом в другом проекте, то
там, скорее всего она будет, где то записана в сценарии. Простого
копирования имени этого перехода не достаточно, и что бы у вас она
так же заработала вам, потребуется переписать ее код себе в свой
сценарий
pause .5 – это время за который произойдет данный переход(это пол
секунды)

Пример кода с проекта обучения


show whitehouse ###сценна №1
with dissolve ### переход
with Pause(1) ###пауза

show Washington ###сценна №2

with dissolve ### переход

2) WITH FADE
Вспышка, а потом переходит как dissolve к новой сцене. Им можно
создать эффект лампочки. Для этого вам нужно создать переменную с
указание ее цвета(в моем случае белый свет)
init:

133
2018 Ren’Py

$ flashbulb = Fade(0.2, 0.0, 0.8, color='#fff')###имя перехода


flashbulb, задаем цвет белый color='#fff'

И где то в проекте
label start:
scene komnata with flashbulb
И получаем эффект слеповой гранаты как в КонтрСтрайк.
Так же запомните что любой переход который вы создаете его
нужно прописывать в init

3) WITH PIXELLATE
Создает эффект перехода пикселей (Например, его часто используют
в космических новелках. Где герой получает изображение со спутника
и там изображение плавно появляется на экране)

134
2018 Ren’Py

4) WITH VPUNCH
Эффект встряски экрана (кувалдой по голове, сверху вниз)

5) WITH HPUNCH
Эффект встряски экрана (пощечина, слева на право)

6) WITH PAUSE(1)
Спросите, зачем нужна пауза? Допустим ваш герой провел обычный ничем не
примечательный день(и показываем сцены дом, школа, столовая, домой) если между
каждой сценой не ставить паузу, то программа эти сцены пропустит, так, что вы не
успеете ничего увидеть. Мгновенно практически. А если между каждой сценой поставить
паузу….то только щелчком мышки поменяются сцены. Или как сейчас тут показано через
1 секунду.

Пример кода с обучения

show bg whitehouse ###сценна №1

with dissolve ### переход

with Pause(1) ###пауза

show bg Washington ###сценна №2

with dissolve ### переход

7)ЖЕСТКАЯ ПАУЗА
Так же есть жесткая пауза, например, вы нажали пропуск всех сцен, а вам нужно что
бы нельзя было пропустить нужную сцену, вот для этих целей и нужна жесткая пауза

Как "заморозить" экран или изображение на время, без возможности пропуска?


Добавить "особую" паузу с указанием промежутка, после вызова
изображения/скрина/спрайта, к примеру на 3 секунды:

scene bg1
$ renpy.pause(3.0, hard=True)

ПЕРЕХОДЫ MOVE
Move –это переход который меняет позиции изображения. Они
делятся на 3 типа – простые, moveout, movein
135
2018 Ren’Py

ПРОСТЫЕ ПЕРЕХОДЫ
Используется для перемещений по экрану изображений
Пример
show rish_1 at right
with move
show rish_1 at center
with move
Здесь мы видим, как rish_1 переходит справа в центр.

ПЕРЕХОД MOVEOUT
Используется, что бы скрыть изображение за экраном. Примеры
moveoutright – вправо
moveoutleft – влево
moveouttop - вверх
moveoutbotton – вниз
label start:
show pic
pause
hide pic at moveoutbotton
pause
Данные трансформации часто используют для плавного перехода
спрайта по экрану.

136
2018 Ren’Py

ПЕРЕХОД MOVEIN
Используют, для появлении изображения на экране
moveinright – вправо
moveinleft – влево
moveintop – вверх(ногами)
moveinbotton – вниз
label start:
show pic with moveintop
pause

ZOOMIN И ZOOMOUT
Показать и спрятать изображение масштабированием
hide eileen happy
with zoomout

show eileen happy


with zoomin

CROPMOVE
Переход который похож на Move только старое изображение стоит на
месте, а новое плавно сверху на него наезжает.
with wiperight – на право
with wipeleft – на лево
with wipeup – вверх
with wipedown - вниз

137
2018 Ren’Py

Переход слайд, старое изображение стоит на месте, а новое быстро


сверху на него наезжает.
with slideright - на право
with slideleft – на лево
with slideup – вверх
with slidedown - вниз

with slideawayright - на право

with slideawayleft – на лево

with slideawayup – вверх

with slideawaydown – вниз

ПЕРЕХОД В ВИДЕ ПРЯМОУГОЛЬНИКА


with irisout – приблизить камеру

with irisin – отдалить камеру

ПЕРЕХОДЫ PUSHMOVE
Данный переход меняет сцену вытесняя старую. Как паровоз.

with pushright – вправо

with pushleft – влево

with pushdown - снизу

with pushup – вверх

138
2018 Ren’Py

ПЕРЕХОДЫ КОТОРЫЕ
САМОСТОЯТЕЛЬНО
СОЗДАЮТСЯ(IMAGEDISSOLVE)
Для этих переходов используются другие изображения. В сообществе
ренпая я добавлял архив с кучей изображений для создания
эффектов начиная от телепорта….до перехода виде сердечек для
хэппи-эндов(около 200 картин)
https://vk.com/topic-7553243_31474171?post=8461
подбирайте именно подходящие для вас эффекты (Не забудьте
изображению-переходу дать такое же разрешение, как и ваш проект).
В ренпае уже существует 2 прописанных перехода

ЖАЛЮЗИ
with blinds
Пример:
scene black
with blinds

scene bg washington
show eileen happy
with blinds

КВАДРАТЫ
with squares
Пример:
scene black

139
2018 Ren’Py

with squares

scene bg washington
show eileen happy
with squares
И самостоятельно запишем спецэффект открытия глаз

ОТКРЫВАЕМ И ЗАКРЫВАЕМ ГЛАЗА

Для добавления эффекта вам следует прописать через init: сам


эффект с ссылкой на картину
Ниже пример:
init:
$ pic = ImageDissolve("id_circleiris.png", 1.0, 8) ###открыли.
"id_circleiris.png" – путь к картинке
$ pic2 = ImageDissolve("id_circleiris.png", 1.0, 8, reverse=True) ###
закрыли
И в проекте переход вызываем
label start:
scene picture with dissolve
pause
scene black with pic2
pause
scene picture with pic
pause

140
2018 Ren’Py

Разрешение у изображения такое же, как и экран проекта.


По умолчанию сначала исчезают белые изображения, а потом
черные, но reverse=True делает все наоборот. Сначала темные и
только потом белые
Цифры
1.0, – скорость сек
8 - % закрытия

ТЕЛЕПОРТ(ПОСТРОЧНОЕ ИЗЧЕЗНОВЛЕНИЕ)
Если нужно построчное исчезновение, как в телепорте то пишут

define teleport = ImageDissolve("imagedissolve teleport.png", 1.0, 0)

show eileen happy

with teleport

141
2018 Ren’Py

Разрешение у изображения такое же, как и экран проекта.

ПЕРЕХОД ALPHADISSOLVE
"spotlight.png" частично прозрачное изображение

142
2018 Ren’Py

image alpha_control:

"spotlight.png"

anchor (.5, .5)

parallel:

zoom 0

linear .5 zoom .75

pause 2

linear 1.0 zoom 4.0

parallel:

xpos 0.0 ypos .6

143
2018 Ren’Py

linear 1.5 xpos 1.0

linear 1.0 xpos .5 ypos .2

pause .5

repeat

define alpha_example = AlphaDissolve("alpha_control", delay=3.5)

label start:

scene bg washington

show eileen happy at center

with alpha_example

КАК ЗАДАТЬ ВРЕМЯ ПЕРЕХОДАМ


Можно задавать время для каждого перемещения в блоке
инициализации, а можно и "на лету":
init python:
mtime = 1.5 ### время в пути
moveinleft = MoveTransition(mtime, enter=_moveleft)
moveinright = MoveTransition(mtime, enter=_moveright)
moveoutleft = MoveTransition(mtime, leave=_moveleft)
moveoutright = MoveTransition(mtime, leave=_moveright)
init:
image t = Text("{size=128}@")
label start:
show t with moveinleft
hide t with moveoutright
show t with moveinright
# а можно прямо так, если нужно поменять "время в пути" на
лету:
hide t with MoveTransition(2.0, leave=_moveright)
return

144
2018 Ren’Py

Но проще всего задать время для всех перемещений сразу:


init:
$ define.move_transitions('move', 2.0)

Mеняем стандартное время всех или некоторых эффектов для


появления/исчезновения спрайтов

init python:
def move_time(delay=.5, effects=["move", "ease"]):
effects = make_list(effects)
for i in effects:
define.move_transitions(i, delay)

ЭФФЕКТ DISSOLVE, НО С УЧЕТОМ


ПРОЗРАЧНОСТИ СПРАЙТА.
пример:

# with diss
init:
diss = Dissolve(.1, alpha=True)
diss25 = Dissolve(.25, alpha=True)

ЭФФЕКТ ВСПЫШКИ НУЖНОГО ЦВЕТА ДЛЯ


СМЕНЫ ФОНОВ.
пример:
# with flash("#822")
init python:
def flash(color="#fff"):
return Fade(.25, 0, .75, color=color)

145
2018 Ren’Py

ПРИМЕРЫ ИНТЕРЕСНЫХ
ТРАНСФОРМАЦИЙ(SPRITE).

1)ЭФФЕКТ ПАДАЮЩИХ СВЕРХУ СНЕЖИНОК


ИЛИ ЛИСТЬЕВ(SNOWBLOSSOM)
image sakura filmstrip = anim.Filmstrip("sakura.png", (20, 20), (2, 1), .15)

image snowblossom = SnowBlossom("sakura filmstrip")

label start:

scene black

show snowblossom

pause

146
2018 Ren’Py

Все действия, что можно применить в SnowBlossom

image snowblossom = SnowBlossom("sakura filmstrip", COUNT=10, BORDER=50,


XSPEED=(20 , 50), YSPEED=(100 , 200), START=0 , FAST=FALSE, HORIZONTAL=FALSE)

2 СПОСОБ ВЫЗВАТЬ СНЕГ


init:

transform snowflakes(al=((renpy.random.randint(500, 990)) * .001)):

anchor (.5, .5)

zoom (renpy.random.randint(600, 1000) * .001)

block:

parallel:

pos (renpy.random.random(), (renpy.random.randint(50, 200) * -.001)) # Случайная


позиция по оси x. И позиция сверху, за пределом экрана, по оси y.

alpha al

# Псевдорандомный полёт до низа экрана, с отклонением по сплайну.

147
2018 Ren’Py

linear renpy.random.randint(15, 50) alpha (al * .5) pos (renpy.random.random(),


((renpy.random.randint(50, 200) * .001) + 1.0)) knot (renpy.random.choice((.0, 1.0)),
renpy.random.random()) knot (renpy.random.choice((.0, 1.0)), renpy.random.random())

repeat # За счёт того, что переопределение происходит за пределом экрана,


возникает визуальная иллюзия бесконечного падения снежинок.

parallel:

rotate 0

linear renpy.random.randint(5, 25) rotate renpy.random.choice((360, -360)) #


Вращение в разные стороны, во время полёта.

repeat

init python:

def snowfall(*pic): # Функция, для вывода.

if (len(pic) == 1) and isinstance(pic[0], (list, tuple)):

pic = pic[0]

for i in xrange(renpy.random.randint(60, 120)):

renpy.show(str(renpy.random.random()), what=At(renpy.random.choice(pic),
snowflakes))

label start:

$ snowfall(*tuple(i for i in renpy.list_files() if i.endswith("images/hitry_tits.png"))) # При


вызове, передаём функции одну, или несколько пикч, со снежинкой. Количество
неограничено. Если аргументов несколько, показаны будут случайно выбранные.

pause

2) ЭФФЕКТ ЗВЕЗДНОГО НЕБА(ЗВЕЗДЫ


ДВИГАЮТСЯ СПРАВА НА ЛЕВО)
init python:

class StarField(object):

def __init__(self):

self.sm = SpriteManager(update=self.update)

# A list of (sprite, starting-x, speed).

148
2018 Ren’Py

self.stars = [ ]

# Note: We store the displayable in a variable here.

# That's important - it means that all of the stars at

# a given speed have the same displayable. We render that

# displayable once, and cache the result.

d = Transform(«star.png», zoom=.02)

for i in range(0, 50):

self.add(d, 20)

d = Transform(«star.png», zoom=.025)

for i in range(0, 25):

self.add(d, 80)

d = Transform(«star.png», zoom=.05)

for i in range(0, 25):

self.add(d, 160)

d = Transform(«star.png», zoom=.075)

for i in range(0, 25):

self.add(d, 320)

d = Transform(«star.png», zoom=.1)

for i in range(0, 25):

self.add(d, 640)

d = Transform(«star.png», zoom=.125)

for i in range(0, 25):

self.add(d, 1280)

149
2018 Ren’Py

def add(self, d, speed):

s = self.sm.create(d)

start = renpy.random.randint(0, 840)

s.y = renpy.random.randint(0, 600)

self.stars.append((s, start, speed))

def update(self, st):

for s, start, speed in self.stars:

s.x = (start + speed * st) % 840 - 20

return 0

label start:

scene black

show expression (StarField().sm) as starfield

show eileen happy

with wiperight

pause

3) С ПРАВО НАЛЕВО ВЫЛЕТЕЛО


ИЗОБРАЖЕНИЕ, КОТОРОЕ ПЛАВНО
ВЕРТИТСЯ И ИСЧЕЗАЕТ
init python:

# This spins the logo, while at the same time zooming it and decreasing the

# alpha.

def logo_transform(t, st, at):

# Repeat every 10 seconds.

150
2018 Ren’Py

st = st % 7.0

# The move takes 5 seconds.

done = min(st / 5.0, 1.0)

t.xpos = done

t.xanchor = 1.0 - done

t.ypos = .5

t.yanchor = .5

t.rotate = 360 * done

t.alpha = 1.0 - done

t.zoom = 1.0 + done

return 0

label start:

e "The Transform function allows you to rotate, zoom, move, and adjust the alpha of a
displayable."

e "It does this under the control of a Python function, making it incredibly flexible at the cost of
some complexity."

hide eileen

with dissolve

show logo base at Transform(function=logo_transform)

e "Here's a simple example, showing how we can change an image as it moves around the
screen."

4) ПО ЭКРАНУ СКАЧУТ ШАРИКИ-


ИЗОБРАЖЕНИЯ В СЛУЧАЙНОМ ПОРЯДКЕ
# This is the code for the balls example. It's a bit complicated, but most of

# this is the code for ball movement and so on. Only a very little bit of this

# actually deals with Ren'Py.

init python:

151
2018 Ren’Py

import math

class Ball(object):

def __init__(self, filename, x, y, function=None):

self.transform = Transform(child=filename, xanchor=0.5, yanchor=0.5, rotate=0,


function=function)

self.x = x

self.y = y

MAX_SPEED = 150

self.dx = renpy.random.uniform(-MAX_SPEED, MAX_SPEED)

self.dy = renpy.random.uniform(-MAX_SPEED, MAX_SPEED)

# Rotation speed.

self.drotate = renpy.random.uniform(0, 180)

# This is called

def balls_collide(p1, p2):

"""

Check to see if any of the balls are colliding. If they are,

then handle the collision.

"""

DOUBLE_RADIUS = 75

x21 = p2.x - p1.x

y21 = p2.y - p1.y

d = math.hypot(x21, y21)

# Return if too far.

if d > DOUBLE_RADIUS:

return

vx21 = p2.dx - p1.dx

vy21 = p2.dy - p1.dy

# Return if not approaching.

if (vx21 * x21 + vy21 * y21) > 0:

152
2018 Ren’Py

return

# Fix divide by zero.

if x21 == 0:

x21 = .00001

# Compute the collision.

a = y21 / x21

dvx2 = -(vx21 + a * vy21) / (1 + a * a)

p2.dx += dvx2

p2.dy += a * dvx2

p1.dx -= dvx2

p2.dy -= a * dvx2

# This is called by the first transform. It updates all of the

# transforms.

def balls_update(pilot, st, at):

global last_time

RADIUS = 75 / 2

LEFT = RADIUS

RIGHT = 800 - RADIUS

TOP = RADIUS

BOTTOM = 600 - RADIUS

# The pilot is the first ball in our list, and he's the one

# that gets last_time updated.

if last_time is None:

dt = 0

else:

dt = st - last_time

last_time = st

# Handle current collisions.

for i in xrange(0, len(balls)):

for j in xrange(i + 1, len(balls)):

153
2018 Ren’Py

balls_collide(balls[i], balls[j])

# Basic movement, and bouncing off the walls.

for i in balls:

i.x += i.dx * dt

i.y += i.dy * dt

if i.x < LEFT:

i.x = LEFT

i.dx = abs(i.dx)

if i.x > RIGHT:

i.x = RIGHT

i.dx = -abs(i.dx)

if i.y < TOP:

i.y = TOP

i.dy = abs(i.dy)

if i.y > BOTTOM:

i.y = BOTTOM

i.dy = -abs(i.dy)

# Update the transforms.

for i in balls:

# This is the code that deals with Ren'Py to update the

# various transforms. Note that we use absolute coordinates

# to position ourselves with subpixel accuracy.

i.transform.xpos = absolute(i.x)

i.transform.ypos = absolute(i.y)

i.transform.rotate = (i.drotate * st) % 360.0

i.transform.update()

return 0

label start:

154
2018 Ren’Py

e "If you use it to do a rotation, you can zoom or adjust alpha at no additional cost."

hide logo base

with dissolve

python:

last_time = None

# Define a list of ball objects.

balls = [

Ball("eileen_orb.png", 200, 150, function=balls_update),

Ball("lucy_orb.png", 400, 150),

Ball("eileen_orb.png", 600, 150),

Ball("lucy_orb.png", 200, 300),

Ball("lucy_orb.png", 600, 300),

Ball("eileen_orb.png", 200, 450),

Ball("lucy_orb.png", 400, 450),

Ball("eileen_orb.png", 600, 450),

# Add each ball's transform to the screen.

for i, b in enumerate(balls):

renpy.show("ball%d" % i, what=b.transform)

with dissolve

e "As the python functions get more complicated, more advanced behavior is possible."

e "This can include coordinating more than one Transform."

python:

for i, b in enumerate(balls):

renpy.hide("ball%d" % i)

5)РАНДОМНЫЕ МЕРЦАЮЩИЕ ЗВЕЗДЫ


Чтобы использовать функцию, нужно закинуть файл blinkinstars.rpy в
папку game проекта. В директории images должны быть star.png и

155
2018 Ren’Py

bg_sky.jpg (либо свои файлы - всё настраивается). Можно указать


регион, в котором появятся звезды (левый верхний и правый нижний
углы), также можно указать количество звезд. Полученный файл
можно использовать и в скрипте. Например, так: scene mmbg
# код файла blinkinstars.rpy
init -2:
# мерцание
transform sblink(t=1.0, frm=.0, z=1.0):
alpha frm*.5+.5 zoom z rotate renpy.random.randint(0, 360)
linear t*.5*(1.0-frm) alpha 1.0
linear t*.5 alpha .5
linear t*.5*frm alpha frm*.5+.5
repeat

init -1 python:
# автоматическое объявление
config.automatic_images_minimum_components = 1
config.automatic_images = [' ', '_', '/']
config.automatic_images_strip = ["images"]

# в папке images должна лежать картинка star.png


# функция, приклеивающая к фону несколько мерцающих звездочек
def BlinkinStars(star_count=20, bg = "black", region=None, **properties):
sw, sh = (config.screen_width, config.screen_height)
if region is None:
region = (0, 0, sw, sh)
# регион, в пределах которого будут размещены звезды
# (можно не задавать, тогда на весь экран)
r0x, r0y, r1x, r1y = region
# при необходимости добавляем фон
if bg is None:
data = [(sw, sh)]
else:
data = [(sw, sh), (0, 0), bg]

156
2018 Ren’Py

# мерцающие (несинхронно!) звезды


for i in range(star_count):
frm = renpy.random.random() # начало мерцания
stm = .5+renpy.random.random()*1.5 # время мерцания (0.5..2)
# позиция
y = renpy.random.randint(r0y, r1y)
x = renpy.random.randint(r0x, r1x)
szoom = renpy.random.random() # размер звездочки (0..1)
# добавляем звездочку
iname = "tmpimg" + str(i)
renpy.image(iname, At("star", sblink(stm, frm, szoom)))
data.extend([(x, y), iname])
return LiveComposite(*data)

init:
image mmbg = BlinkinStars(30, "bg sky")
$ style.mm_root.background = "mmbg"
$ style.gm_root.background = "mmbg"

6) ЭФФЕКТ РЕПУЛЬСОН(МЫ МЫШКОЙ


ИЩЕМ ВЕЩИ)
init python:
import math

def repulsor_update(st):

# If we don't know where the mouse is, give up.


if repulsor_pos is None:
return .01

px, py = repulsor_pos

# For each sprite...


for i in repulsor_sprites:

157
2018 Ren’Py

# Compute the vector between it and the mouse.


vx = i.x - px
vy = i.y - py

# Get the vector length, normalize the vector.


vl = math.hypot(vx, vy)
if vl >= 150:
continue

# Compute the distance to move.


distance = 3.0 * (150 - vl) / 150

# Move
i.x += distance * vx / vl
i.y += distance * vy / vl

# Ensure we stay on the screen.


if i.x < 2:
i.x = 2

if i.x > repulsor.width - 2:


i.x = repulsor.width - 2

if i.y < 2:
i.y = 2

if i.y > repulsor.height - 2:


i.y = repulsor.height - 2

return .01

# On an event, record the mouse position.


def repulsor_event(ev, x, y, st):
store.repulsor_pos = (x, y)

label repulsor_demo:

python:
# Create a sprite manager.
repulsor = SpriteManager(update=repulsor_update, event=repulsor_event)
repulsor_sprites = [ ]

158
2018 Ren’Py

repulsor_pos = None

# Ensure we only have one smile displayable.


smile = Image("smile.png")

# Add 400 sprites.


for i in range(400):
repulsor_sprites.append(repulsor.create(smile))

# Position the 400 sprites.


for i in repulsor_sprites:
i.x = renpy.random.randint(2, 798)
i.y = renpy.random.randint(2, 598)

del smile
del i

# Add the repulsor to the screen.


show expression repulsor as repulsor

"..."

hide repulsor

# Clean up.
python:
del repulsor
del repulsor_sprites
del repulsor_pos

label start:
call repulsor_demo

Видел этот код в документации ренпая, и в 1 детективной новелле.


Там главный герой рылся в мусоре и из под этих картин вылезла
улика, номер телефона.

7)СИСЬКОТРЯС

# как создать спрайты с трясущейся грудью, с разными эмоциями, при необходимости


моргающие
init -3:
image pixel = Null(1, 1)

159
2018 Ren’Py

# список героев, если есть грудь, то ее координаты относительно левого верхнего угла
спрайта
$ tits = [("laylastrip", (305, 263)), ("hitry", (280, 600)), ("tasha", (280, 555)), ("ani",(255, 466)),
"hanny", "tarisa", "layla", "eureka", "rian", "bron", "guardian", "kiron", "erion", "bertraed", "tryber",
"oper", "remdark"]
# список эмоций (если нужных спрайтов не будет, то они не будут создаваться)
$ emos = ["angry", "evil", "happy", "ok", "sad", "smile", "wat", "shame"]
# реалистичная анимация сиськотряса
transform boobs(name, boob_t = 2.0):
yanchor 0.0 yzoom 1.0
easeout (boob_t * .075) yzoom 1.05
easein (boob_t * .1) yzoom 0.95
easeout (boob_t * .125) yzoom 1.025
easein (boob_t * .125) yzoom 0.975
easeout (boob_t * .125) yzoom 1.01
easein (boob_t * .15) yzoom 0.990
easeout (boob_t * .15) yzoom 1.005
easein (boob_t * .15) yzoom 1.0
init 1999 python:
# автоматическое объявление персонажей
# с дополнительными «верхними половинками»,
# моргающие, с трясущимися сиськами (если это дамы)
# то есть у нас есть спрайты высотой 1700 (для того чтобы пробежаться взглядом по
всему телу)
# мы прикручиваем к ним моргающие головы с эмоциями и однократно трясущейся
грудью
# а еще обрезаем результат до высоты экрана (1080) - получаются обычные спрайты
for i in tits:
char_name = get_tname(i) # имя перса из списка
xy = get_tpos(i) # координаты сисек
w, h = (800, 1700) # стандартные размеры для всех спрайтов
tits_name = char_name + " tits" # сиськи имяперсонажа_tits.png
if xy[0] < 1 and xy[1] < 1: # если это мужик,
tits_name = "pixel" # то пусть трясет невидимыми сиськами
# перебираем все возможные эмоции
for emo in emos:
nemo = char_name + " " + emo # прикручиваем очередную эмоцию
img_head = nemo + " head" # картинка головы с открытыми глазами (во всю ширину
спрайта!)
img_blink = nemo + " blink" # голова с закрытыми глазами
# если одна из голов пустая, заменяем на другую
if not has_img(img_head):
img_head = "pixel"
if not has_img(img_blink):
img_blink = "pixel"
if img_blink == "pixel":
img_blink = img_head
if img_head == "pixel":
img_head = img_blink
if img_blink == "pixel":
img_blink = img_head
# если есть головы с нужной эмоцией, то создаем спрайты с ними
if img_head != "pixel" or img_blink != "pixel":
img_full = LiveComposite((w, h),

160
2018 Ren’Py

(0, 0), char_name + ' temp',


(0, 0), Animation(img_head, rnd(3, 5) + rnd(0, 10) * .1, img_blink, .1),
xy, At(tits_name, boobs(char_name)),
yanchor=1.0, align=(.5, 1.0)
)
renpy.image(nemo + " full", img_full) # создаем спрайт с анимацией в полный рост
renpy.image(nemo, LiveCrop((0, 0, w, h - 620), img_full)) # обрезаем ноги
# если нет голов с эмоциями, то просто обрезаем спрайт, без анимации
if img_head == "pixel" and img_blink == "pixel" and emo == "ok":
renpy.image(char_name + " ok", LiveCrop((0, 0, w, h - 620), LiveComposite((w, h), (0,
0), char_name + ' temp')))

label start:
scene hitry ok:

anchor (.5, 1.0)

align (.5, 1.0)

zoom 1.15

pause

hitry_tits.png 200x200

161
2018 Ren’Py

hitry_ok_blink.png 800x540

162
2018 Ren’Py

hitry_ok_head.png 800x540

hitry_temp.png 800x1700

163
2018 Ren’Py

164
2018 Ren’Py

8) МАСКИРОВКА СНАЙПЕР
init python:

import math

class Appearing(renpy.Displayable):

def __init__(self, child, opaque_distance, transparent_distance, **kwargs):

# Pass additional properties on to the renpy.Displayable

# constructor.

super(Appearing, self).__init__(**kwargs)

# The child.

self.child = renpy.displayable(child)

# The distance at which the child will become fully opaque, and

# where it will become fully transparent. The former must be less

# than the latter.

self.opaque_distance = opaque_distance

self.transparent_distance = transparent_distance

# The alpha channel of the child.

self.alpha = 0.0

# The width and height of us, and our child.

self.width = 0

self.height = 0

165
2018 Ren’Py

def render(self, width, height, st, at):

# Create a transform, that can adjust the alpha channel of the

# child.

t = Transform(child=self.child, alpha=self.alpha)

# Create a render from the child.

child_render = renpy.render(t, width, height, st, at)

# Get the size of the child.

self.width, self.height = child_render.get_size()

# Create the render we will return.

render = renpy.Render(self.width, self.height)

# Blit (draw) the child's render to our render.

render.blit(child_render, (0, 0))

# Return the render.

return render

def event(self, ev, x, y, st):

# Compute the distance between the center of this displayable and

# the mouse pointer. The mouse pointer is supplied in x and y,

# relative to the upper-left corner of the displayable.

distance = math.hypot(x - (self.width / 2), y - (self.height / 2))

# Base on the distance, figure out an alpha.

if distance <= self.opaque_distance:

166
2018 Ren’Py

alpha = 1.0

elif distance >= self.transparent_distance:

alpha = 0.0

else:

alpha = 1.0 - 1.0 * (distance - self.opaque_distance) / (self.transparent_distance -


self.opaque_distance)

# If the alpha has changed, trigger a redraw event.

if alpha != self.alpha:

self.alpha = alpha

renpy.redraw(self, 0)

# Pass the event to our child.

return self.child.event(ev, x, y, st)

def visit(self):

return [ self.child ]

screen alpha_magic:

add Appearing("logo.png", 100, 200):

xalign 0.5

yalign 0.5

label start:

show screen alpha_magic

"Где тут спрятался снайпер?"

9) ФОНАРИК

167
2018 Ren’Py

init python:

class Flashlight(renpy.Displayable):
def __init__(self):
super(Flashlight, self).__init__()

# This image should be twice the width and twice the height
# of the screen.
self.child = Image("flashlight.png")

# (-1, -1) is the way the event system represents


# "outside the game window".
self.pos = (-1, -1)

def render(self, width, height, st, at):


render = renpy.Render(config.screen_width, config.screen_height)

if self.pos == (-1, -1):


# If we don't know where the cursor is, render pure black.
render.canvas().rect("#000", (0, 0, config.screen_width,
config.screen_height))
return render

# Render the flashlight image.


child_render = renpy.render(self.child, width, height, st, at)

# Draw the image centered on the cursor.


flashlight_width, flashlight_height = child_render.get_size()
x, y = self.pos
x -= flashlight_width / 2
y -= flashlight_height / 2
render.blit(child_render, (x, y))
return render

def event(self, ev, x, y, st):


# Re-render if the position changed.
if self.pos != (x, y):
renpy.redraw(self, 0)

# Update stored position


self.pos = (x, y)

def visit(self):
return [ self.child ]

screen flashlight_demo:
textbutton "continue" xpos 300 ypos 300 action Return()
add Flashlight()

label start:
$ mouse_visible = False
call screen flashlight_demo

Этот код ожидает, чтобы иметь возможность найти «flashlight.png»; это


изображение должно иметь ширину и высоту вдвое больше, чем на
экране, и он должен быть черным с прозрачным отверстием в центре.
(Что делает его в два раза размер экрана немного неэффективно, но
это делает код намного проще.)

168
2018 Ren’Py

Изображение
https://lemmasoft.renai.us/forums/download/file.php?
id=19774&mode=view

10) КОМПАС

Ссылка https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=23179

11) МЕТЕЛЬ

Посмотреть видео примера https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=24762


transform withAdd:
additive 1.0

image particle newDownBright = SnowBlossom(At("images/blue-particle-


circle.png", withAdd), border=150, count=6000,start=0.00000000001,
fast=False, yspeed=(-100, -80), xspeed=(-3000,3000), horizontal=True)

12) ЗВЕЗДНОЕ НЕБО ПРЯМО В ЛИЦО

file star.rpy

init python:

"""

Projection Starfield v2 for Ren'Py

2014 Joshua Fehler <jsfehler@gmail.com>

Based on:

3D Starfield Simulation

Developed by Leonel Machava <leonelmachava@gmail.com>

http://codeNtronix.com

http://twitter.com/codentronix

http://opensource.org/licenses/mit-license.php

"""

169
2018 Ren’Py

from random import randrange

class ProjectionStarfield(renpy.Displayable):

"""

Fires out a displayable from the centre of the screen and outwards.

star_amount controls the number of displayables created.

depth and perspective controls the starting position and how the displayables move.

"""

def __init__(self, star_amount=512, depth=16, perspective=128.0, speed=0.19,


image=None):

super(renpy.Displayable, self).__init__()

self.star_amount = star_amount

self.depth = depth

self.perspective = perspective

self.speed = speed

self.origin_x = config.screen_width * 0.5

self.origin_y = config.screen_height * 0.5

#If no image is provided, create a generic star

star_colour = Solid((255, 255, 255, 255))

if image == None:

self.image = Fixed(star_colour,xysize=(3, 3))

else:

self.image = Image(image)

self.stars = []

self.transforms = []

170
2018 Ren’Py

def start(self):

#Creates a list of starting positions for the starts, represented as: [x,y,z]

self.stars = [[randrange(-25, 25), randrange(-25, 25), randrange(1, self.depth),0] for x in


range(self.star_amount)]

self.transforms = self._build_star_transforms(self.image)

def _build_star_transforms(self, image):

"""Pre-calculate all the size/alpha transforms that are possible so they don't have to be
recreated

in render() every single frame."""

#All possible depths, based on speed

current_depth = float(self.depth)

all_depths = []

while current_depth > 0:

all_depths.append(current_depth)

current_depth -= self.speed

#All possible transform factors

#Using Linear Interpolation, distant stars are smaller and darker than closer stars.

t_factors = [(1 - float(d) / self.depth) for d in all_depths]

#All possible size and alpha transforms

tr = [(Transform(child=image, zoom=item, alpha=item)) for item in t_factors]

tr.reverse()

return tr

def add_stars(self, amount):

171
2018 Ren’Py

for x in range(amount):

self.stars.append([randrange(-25, 25), randrange(-25, 25), randrange(1,


self.depth),0])

def subtract_stars(self, amount):

for x in range(amount):

del self.stars[-1]

def render(self, width, height, st, at):

render = renpy.Render(0, 0)

for star in self.stars:

#Z coordinate decreases each redraw.

star[2] -= self.speed

star[3] -= 1

#If the star exits the screen, move it to the back of the projection with random X and Y
coordinates.

if star[2] <= 0:

star[0] = randrange(-25,25)

star[1] = randrange(-25,25)

star[2] = self.depth

star[3] = len(self.transforms)-1

#Convert the 3D coordinates to 2D using perspective projection.

k = self.perspective / star[2]

x = int(star[0] * k + self.origin_x)

y = int(star[1] * k + self.origin_y)

#Draw the star (if it's visible on screen).

172
2018 Ren’Py

if 0 <= x < config.screen_width and 0 <= y < config.screen_height:

child_render = renpy.render(self.transforms[star[3]], 1, 1, st, at)

render.blit(child_render,(x, y))

renpy.redraw(self, 0)

return render

file script.rpy

init:

#Simple black background to show under the stars

define space = Solid((0, 0, 0, 255))

#Create the starfield displayables. Optional keyword arguments can tweak the default
display.

#One with a generic square for the star.

$ n_starfield = ProjectionStarfield()

#and one with an image used, plus optional keyword arguments.

$ i_starfield = ProjectionStarfield(star_amount=512, depth=16, perspective=128.0,


speed=0.19, image="star_image.png")

#Screens where the displayables are shown

screen starfield:

add space

add n_starfield

screen starfield_with_image:

add space

add i_starfield

# The game starts here.

label start:

173
2018 Ren’Py

show screen starfield

$n_starfield.start()

"Space."

$ n_starfield.add_stars(512)

"The final frontier."

$ n_starfield.subtract_stars(512)

"These are the voyages of the starship Enterprise."

hide screen starfield

show screen starfield_with_image

$ i_starfield.start()

"It's continuing mission, to explore strange new worlds."

return

13) ЭФФЕКТ ДВОЕНИЯ В ГЛАЗАХ(ПЬЯНЫЙ)

init:

transform transpa:

alpha 0.5

python hide:

def gen_randmotion(count, dist, delay):

174
2018 Ren’Py

import random

args = [ ]

for i in range(0, count):

args.append(anim.State(i, None,

Position(xpos=random.randrange(-dist, dist),

ypos=random.randrange(-dist, dist),

xanchor='left',

yanchor='top',

)))

for i in range(0, count):

for j in range(0, count):

if i == j:

continue

args.append(anim.Edge(i, delay, j, MoveTransition(delay)))

return anim.SMAnimation(0, *args)

store.randmotion = gen_randmotion(5, 5, 1.0)

init python:

def double_vision_on(picture):

renpy.scene()

175
2018 Ren’Py

renpy.show(picture)

renpy.show(picture, at_list=[transpa,randmotion], tag="blur_image")

renpy.with_statement(dissolve)

def double_vision_off():

renpy.hide("blur_image")

renpy.with_statement(dissolve)

label start:

$ double_vision_on("mark_h")#в кавычках изобраэжение

pause

14) ВЗРЫВ ЧАСТИЦ

http://ru.renpypedia.shoutwiki.com/wiki/%D0%92%D0%B7%D1%80%D1%8B%D0%B2_
%D1%87%D0%B0%D1%81%D1%82%D0%B8%D1%86_(Particle_Burst)

ОПЕРАЦИИ НАД ИЗОБРАЖЕНИЕМ


Здесь те команды, которые позволяют нам манипулировать над изображениями.

1) CROP

176
2018 Ren’Py

init:

image imy_ssilka crop = im.Crop("logo.png", 0, 0, 100, 307)

label start:

show imy_ssilka

2) IM.COMPOSITE

177
2018 Ren’Py

init:

image logo composite = im.Composite((200, 407),

(0, 0),"logo.png",

(0, 50),"logo.png",

(0, 100),"logo.png")

3)LIVECOMPOSITE
Как и предыдущий оператор, только может использовать еще анимации

init:

image logo livecomposite = LiveComposite((200, 407),

(0, 0), anim.Blink(Image("logo.png")),

(0, 50), "logo.png",

(0, 100), "logo.png")

178
2018 Ren’Py

4) IM.SCALE

init:

image logo scale = im.Scale("logo.png", 100, 150)

5) IM.FACTORSCALE
init:

image logo factorscale = im.FactorScale("logo.png", 1.5, 1.5)

179
2018 Ren’Py

6) IM.MAP
init:

image logo green = im.Map("logo.png", rmap=im.ramp(0, 0))

180
2018 Ren’Py

В данном случае убрали все красное

7) IM.RECOLOR
Тоже самое что и im.Map но более эффективна при линейной обработке.

init:

image logo green2 = im.Recolor("logo.png", 0, 255, 255, 255)

8) MATRIXCOLOR
Позволяет изменять цвета и насыщеность

ТУСКЛЫЙ ОТТЕНОК

init:

181
2018 Ren’Py

image logo halfsat = im.MatrixColor("logo.png",im.matrix.saturation(.5))

ИНВЕРТИРОВАТЬ ОТТЕНОК

init:

image logo invert = im.MatrixColor("logo.png",

[ -1, 0, 0, 0, 1,

0, -1, 0, 0, 1,

0, 0, -1, 0, 1,

0, 0, 0, 1, 0, ])

Тем кто хорошо знаком с питоном вот записи из офф руковод

An image operator that uses matrix to linearly transform the image


manipulator im.

182
2018 Ren’Py

Matrix should be a list, tuple, or im.matrix() that is 20 or 25 elements long. If


the object has 25 elements, then elements past the 20th are ignored.

When the four components of the source color are R, G, B, and A, which
range from 0.0 to 1.0; the four components of the transformed color are R',
G', B', and A', with the same range; and the elements of the matrix are
named:

[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]

the transformed colors can be computed with the formula:

R' = (a * R) + (b * G) + (c * B) + (d * A) + e
G' = (f * R) + (g * G) + (h * B) + (i * A) + j
B' = (k * R) + (l * G) + (m * B) + (n * A) + o
A' = (p * R) + (q * G) + (r * B) + (s * A) + t

The components of the transformed color are clamped to the range [0.0,
1.0].
im.matrix()

Constructs an im.matrix object from matrix. im.matrix objects support The operations supported
are matrix multiplication, scalar multiplication, element-wise addition, and element-wise
subtraction. These operations are invoked using the standard mathematical operators (*, *, +,
and -, respectively). If two im.matrix objects are multiplied, matrix multiplication is performed,
otherwise scalar multiplication is used.

matrix is a 20 or 25 element list or tuple. If it is 20 elements long, it is padded with (0, 0, 0, 0, 1)


to make a 5x5 matrix, suitable for multiplication.

im.matrix.brightness(b)

Returns an im.matrix that alters the brightness of an image.

b
The amount of change in image brightness. This should be a number between -1 and 1, with -1
the darkest possible image and 1 the brightest.
im.matrix.colorize(black_color, white_color)

Returns an im.matrix that colorizes a black and white image. black_color and white_color are
Ren'Py style colors, so they may be specified as strings or tuples of (0-255) color values.

# This makes black colors red, and white colors blue.


image logo colored = im.MatrixColor(

183
2018 Ren’Py

"bwlogo.png",
im.matrix.colorize("#f00", "#00f"))

im.matrix.contrast(c)

Returns an im.matrix that alters the contrast of an image. c should be greater than 0.0, with
values between 0.0 and 1.0 decreasing contrast, and values greater than 1.0 increasing
contrast.

im.matrix.desaturate()

Returns an im.matrix that desaturates the image (makes it grayscale). This is equivalent to
calling im.matrix.saturation(0).

im.matrix.hue(h)

Returns an im.matrix that rotates the hue by h degrees, while preserving luminosity.

im.matrix.identity()

Returns an identity matrix, one that does not change color or alpha.

im.matrix.invert()

Returns an im.matrix that inverts the red, green, and blue channels of the image without
changing the alpha channel.

im.matrix.opacity(o)

Returns an im.matrix that alters the opacity of an image. An o of 0.0 is fully transparent, while
1.0 is fully opaque.

im.matrix.saturation(level, desat=(0.2126, 0.7152, 0.0722))

Returns an im.matrix that alters the saturation of an image. The alpha channel is untouched.

level
The amount of saturation in the resulting image. 1.0 is the unaltered image, while 0.0 is
grayscale.
desat
This is a 3-element tuple that controls how much of the red, green, and blue channels will be
placed into all three channels of a fully desaturated image. The default is based on the
constants used for the luminance channel of an NTSC television signal. Since the human eye is
mostly sensitive to green, more of the green channel is kept then the other two channels.
im.matrix.tint(r, g, b)

Returns an im.matrix that tints an image, without changing the alpha channel. r, g, and b should
be numbers between 0 and 1, and control what fraction of the given channel is placed into the
final image. (For example, if r is .5, and the value of the red channel is 100, the transformed
color will have a red value of 50.)

184
2018 Ren’Py

9) IM.GRAYSCALE

init:

image logo grayscale = im.Grayscale("logo.png")

185
2018 Ren’Py

10) IM.SEPIA

Старые воспоминания и фотографии

init:

image logo sepia = im.Sepia("logo.png")

186
2018 Ren’Py

11) IM.ALPHA

init:

image logo alpha = im.Alpha("logo.png", 0.5)

Эффект призрака

АНАЛОГ ТОЛЬКО С РАЗМЫТИЕМ(КАК БУДТО В ЗЕРКАЛЕ):

init:

# сам эффект

transform blur(img_name, trans=.2, stp=3):

187
2018 Ren’Py

contains:

img_name

alpha 1.0

contains:

img_name

alpha trans xoffset stp

contains:

img_name

alpha trans yoffset stp

contains:

img_name

alpha trans xoffset -stp

contains:

img_name

alpha trans yoffset -stp

label start:

scene bg

# пример применения

show Null at blur("bg hall hitry")

pause

return

188
2018 Ren’Py

12) IM.FLIP

init:

image eileen flip = im.Flip("images/eileen happy.png", vertical=True)

13) TEXT

189
2018 Ren’Py

Использовать текст как изображение


image logo text = Text(_("Это текстовый обьект."), size=30)
или еще

14) ЭФФЕКТ РАЗМЫТИЯ ИЗОБРАЖЕНИЯ


# довольно дурацкий способ размытия
init python:
# узнаем размер картинки
def get_size(d):
w, h = renpy.render(renpy.easy.displayable(d), 0, 0, 0, 0).get_size()
return int(round(w)), int(round(h))
# покажем на экране размытую
def show_blur(img, degree = 5):
w, h = get_size(img)
factor = im.Scale(renpy.easy_displayable(img), w / degree, h / degree)
factor = Transform(factor, size = (w, h))
renpy.show(img, what=factor)
label start:
# проверка
show bg1
pause
$ show_blur("bg1")
pause

190
2018 Ren’Py

return

ВИЗУАЛЬНЫЙ ЗАПОЛНИТЕЛЬ

Что это за зверь такой. Он используется для временного отображения


фонов, персонажей(половое разделение). Используется в основном
теми, у кого нет художников, но есть текст сценария.
Сейчас опишу, как пользоваться данным оператором.
Вам требуется прописать изображение персонажа, пускай это будет
мужчина.
image nikita_dshigurda = Placeholder("boy")
Далее в тексте вызываем спрайт c нужной эмоцией
show nikita_dshigurda ulibaetsya

191
2018 Ren’Py

Вот весь список кодов

Placeholder(base=None, full=False, flip=None, **properties)

base:

'bg' – фоновый рисунок, заполняет экран светло-серым, и выводит на экран


название картинки наверху экрана.

'boy' - мужчина спрайт.

'girl' – женщина спрайт

image nikita_dshigurda = Placeholder("boy", full=True)

full – заполнить рисунок на весь экран

192
2018 Ren’Py

flip – вертикал

ДИНАМИЧЕСКИЙ ФОН
(Руслан Небыков)
Работая над новеллой «Сателлит», я столкнулся с такой проблемой. У
меня был динамический фон – плывущие по небу облака и
движущийся немного с другой скоростью пейзаж. Всё было
замечательно, пока по экрану не начали двигаться спрайты. По
завершении движения или при уничтожении спрайта Renpy
перерисовывает фон. А значит, анимация запускается заново.
Происходит рывок. Допустим тучки прошли только треть пути, и тут их
возвращают на исходную. Выглядит это очень некрасиво. Но чтобы
фон не перерисовывался, его можно засунуть в экран, который будет
выводиться прямо поверх фона, но под спрайтами. Как это сделать,
видно из кода ниже.
(http://renpyfordummies.blogspot.ru/2016/02/blog-post_24.html)

init -3 python:
# окно игры в центре экрана
import os
os.environ['SDL_VIDEO_CENTERED'] = '1'
# автоматическое объявление изображений
config.automatic_images_minimum_components = 1
config.automatic_images = [' ', '_', '/']
config.automatic_images_strip = ['images']
init:
# трансформация для перемещения фона
transform _moveleft(delay=7.5):
xalign 1.0
linear delay xalign 0.0
repeat

# экран с фоном
screen scr_bg:

193
2018 Ren’Py

add "sky" at _moveleft(15)


add "solt" at _moveleft

label start:
scene black
# показать фон
show screen scr_bg(_layer="master")
with dissolve
# движение спрайта
show mtt at Truecenter with easeinright
pause .25
hide mtt with easeoutleft
# спрятать фон
$ renpy.hide_screen("scr_bg", layer="master")
with dissolve
return

НЕУБИРАЮЩИЙСЯ ПО HIDEINTERFACE()
ЭКРАН
Допустим, мы захотели как-то оформить интерфейс игры. Добавить экран с какими-то
элементами. Но при нажатии на кнопку 'h' все экраны прячутся, в том числе и тот, что
прятаться не должен. Чтобы этого избежать, можно размещать неубирающийся экран на
отдельном слое.

(http://renpyfordummies.blogspot.ru/2016/02/hideinterface.html)

init -1:
# список слоев. если наш tvframe поставить в другое место,
# то не сработает распознавание экрана настроек.
# а так наш экран не будет исчезать при нажатии 'h'
$ config.layers = ["master", "transient", "tvframe", "screens", "overlay"]

# экран с кинескопом и помехами

194
2018 Ren’Py

screen frm:
# выводится, если это игра, но не экран настроек
if not ("preferences" in renpy.current_screen().screen_name):
add "bg frame"

# Игра начинается здесь.


label start:
show screen frm(_layer="tvframe")

СКРОЛЛ ЛЮБОГО, ДАЖЕ НЕ БЕСШОВНОГО


ФОНА

(http://renpyfordummies.blogspot.ru/2016/02/blog-post.html)

# как заскроллить с произвольной скоростью любой фон


# и при этом сделать его бесшовным?
# очень просто: отзеркалить и состыковать одинаковыми сторонами
# пример для движения влево
init:
image sky = "images/sky.jpg"
# трансформации для перемещения и отзеркаливания
transform scroll_in(delay = 10.0):
xpos config.screen_width xzoom -1.0
linear delay xpos 0
pause delay
repeat
transform scroll_in2(delay = 10.0):
xpos config.screen_width
pause delay

195
2018 Ren’Py

linear delay xpos 0


repeat
transform scroll_out(delay = 10.0):
xpos 0
linear delay xpos -config.screen_width
pause delay
repeat
transform scroll_out2(delay = 10.0):
xpos config.screen_width
pause delay
xpos 0 xzoom -1.0
linear delay xpos -config.screen_width
repeat
init python:
# функция объединаяет трансформации
# выводит на экран
def _scroll(img, effect = None, delay = 10.0):
renpy.show(img + "1", what = ImageReference(img), at_list =
[scroll_in(delay)])
renpy.show(img + "2", what = ImageReference(img), at_list =
[scroll_out(delay)])
renpy.show(img + "3", what = ImageReference(img), at_list =
[scroll_in2(delay)])
renpy.show(img + "4", what = ImageReference(img), at_list =
[scroll_out2(delay)])
renpy.with_statement(effect)
def _hide(img, effect = None):
renpy.hide(img + "1")
renpy.hide(img + "2")
renpy.hide(img + "3")
renpy.hide(img + "4")
renpy.with_statement(effect)
# всё, теперь можно в любом месте скрипта
# одной строкой отображать движущийся бесшовный фон

196
2018 Ren’Py

label start:
scene black
# отображаем (параметры можно не указывать)
$ _scroll("sky", Dissolve(2.0), 15)
pause # наслаждаемся облаками
# а теперь прячем наши бегущие картинки
$ _hide("sky", Dissolve(2.0))
pause .5
return

РЕЖИМ NVL
Данный режим выставляет на весь экран текст, а не выставляет его в
нижней части экрана на специальную рамку(речь идет о режиме ADV)
Самый простой способ выставить его – прописать в персонаже
define nvle = Character(_("Eileen"), color="#c8ffc8", kind=nvl)
define misli = Character(None, color="#c8ffc8", kind=nvl)

ОЧИСТИТЬ ЭКРАН NVL


В отличии от экрана ADV - Nvl периодически необходимо чистить от
диалогов. Делается это все командой

label start:
misli "Мысли"
mvle "Диалог"
nvl clear

197
2018 Ren’Py

УБРАТЬ И ПОКАЗАТЬ ПЕРЕХОД В NVL


nvl hide dissolve

nvl show dissolve

МЕНЮ В NVL
Так же в этом режиме можно использовать меню выбора, для этого
вам потребуется прописать
init -1 python hide:
define menu = nvl_menu
label start:
menu:
nvle "NVL-mode"
"Yes.":
nvl clear
nvle "Good!"
"No.":
nvl clear
nvle "Well"

КАК ЗАПРЕТИТЬ ОТКАТ НАЗАД НА NVL

init python:
config.nvl_paged_rollback = True

198
2018 Ren’Py

КАК ПРОПИСАТЬ АВТОМАТИЧЕСКИЙ


ПЕРЕХОД НА NVL
init python:
config.empty_window = nvl_show_core
config.window_hide_transition = dissolve
config.window_show_transition = dissolve

УБРАТЬ ПРЕДЫДУЩУЮ СТРОКУ В NVL

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


командy
label start:
"text"
nvl_erase
"new text"

И все занятые имена связанные с nvl


 nvl_clear
 nvl_clear_next
 nvl_erase
 nvl_hide
 nvl_list
 nvl_menu
 nvl_narrator
 nvl_show
 nvl_show_core
 nvl_variant
 nvl_window

НАСТРАИВАЕМ ЭКРАН NVL


Настроить Nvl можно несколькими способами.

199
2018 Ren’Py

1) ИСТИННЫЙ
Открываете сценарий gui.rpy и находите такую строку

Потом заходите в папку game/gui/nvl.png и меняете на ваше изображение задний фон.

2) КОСТЫЛЬНЫЙ

200
2018 Ren’Py

Прописываем в имени персонажа координаты и фон и координаты

Пример и что получилось

define sh = Character('Shino',
color="9966cc",
window_background = Frame("textbox3.png", 0, 0), #Your custom textbox.
window_left_margin = 320,
window_right_margin = 10,
window_top_margin = 70,
window_bottom_margin = 500,
window_left_padding = 60,
window_right_padding = 10,
window_top_padding = 70,
window_bottom_padding = 75,
ctc="ctc_blink")

ОГРАНИЧИТЬ МАКСИМАЛЬНОЕ ЧИСЛО


СТРОК В NVL

201
2018 Ren’Py

define config.nvl_list_length = 6

РЕЖИМ ADV
Данный режим выставляет текст диалога внизу экрана, где видно имя персонажа,
диалоговое окно и само изображение персонажа в диалоговом окне.

Ранее мы рассматривали как задать изображение и имя персонажа, а


так же диалоговое окно каждому персонажу, по этому их не будем
прописывать.
Настроить расстояние имени от края, максимальную длину текста в
диалоге можно перейдя в сценарий gui.rpy. И найдите такую строку

## Диалог
############################################################
######
## Эти переменные контролируют, как диалог появляется на
отдельной строчке.

202
2018 Ren’Py

Все что связанно с диалогом находится здесь. Предыдущие настройки


мы рассматривали ранее(как задать всем 1 общую текстовый бокс и
т.д. в сценарии screen.rpy экран screen say)

## Экран разговора
############################################################
#
##
## Экран разговора используется для показа диалога игроку. Он
использует два
## параметра — who и what — что, соответственно, имя говорящего
персонажа и
## показываемый текст. (Параметр who может быть None, если имя не
задано.)
##
## Этот экран должен создать текст с id "what", чтобы Ren'Py могла
показать
## текст. Здесь также можно создать наложения с id "who" и id
"window", чтобы
## применить к ним настройки стиля.
##
## https://www.renpy.org/doc/html/screen_special.html#say

screen say(who, what):

КАК ЗАПРЕТИТЬ ОТКАТ НАЗАД В ADV


Вам потребуется прописать в ините следующее

203
2018 Ren’Py

init:
config.hard_rollback_limit = 0
label start:
….
Что бы на 10 откатов назад, то цифру 0 меняют на 10

КАК СДЕЛАТЬ, ЧТОБЫ ПРИ ПЕРЕМОТКЕ


НАЗАД У ИГРОКА НЕ БЫЛО ВОЗМОЖНОСТИ
СМЕНИТЬ СВОЙ ВЫБОР
label start:
menu:
"Выбор 1":
jump v1 ### Прыжок на v1
"Выбор 2":
jump jump v2 ### Прыжок на v2

label v1:
$ renpy.fix_rollback() ###Откат работает, но вариант выбора нельзя
поменять
"Текст"

label v2:
$ renpy.fix_rollback() ###Откат работает, но вариант выбора нельзя
поменять
"Текст"

ПОДРОБНЫЙ РАЗБОР ЗВУКОВ


204
2018 Ren’Py

КАК ДОБАВИТЬ ЗВУКИ И МУЗЫКУ В


ПРОЕКТ
Что бы добавить фоновую музыку используют команду play music
label start:
scene black
play music "illurock.ogg"
uchi "Приветствую Вас"
Музыка из за канала music будет постоянно повторяться.
Так же можно при помощи питона вставлять музыку
$ renpy.music.play('theme.ogg')
Что бы звук 1 раз проиграл, используют канал sound
label start:
scene black
play sound "illurock.ogg"
uchi "Приветствую Вас"
Что бы музыка перед заменой другой песней затухала, используют
оператор fadeout. После которого записываю время затухания.
label start:
scene black
play sound "illurock.ogg" fadeout 1.0
uchi "Приветствую Вас"
Что бы добавить несколько звуков используют оператора queue и
канал на котором будут воспроизводиться
queue music "sunflower-slow-drag.ogg"
queue sound "sunflower-slow-drag.ogg"
queue sound "sunflower-slow-drag.ogg"

205
2018 Ren’Py

или сокращенно
queue music [ "a.ogg", "b.ogg" ]

Что бы остановить музыку используют оператора stop


stop music fadeout 1.0
Или при помощи питона
$ renpy.music.stop(fadeout=1.0)
Что бы была 1 секунда паузы, перед воспроизведением, используют
fadein
queue sound "sunflower-slow-drag.ogg" fadeout 1.0, fadein 1.0
queue sound "sunflower-slow-drag.ogg" fadeout 1.0, fadein 1.0

КАК ИЗМЕНИТЬ ГРОМКОСТЬ ЗВУКОВ И


МУЗЫКИ

$ renpy.music.set_volume(0.2)
Я все ближе к комнате.
$ renpy.music.set_volume(0.5)
Практически открываю дверь.
$ renpy.music.set_volume(1.0)
Я в комнате.

КАК ОБЬЯВИТЬ В ИМЯ - МУЗЫКАЛЬНЫЙ


ФАЙЛ
init:
define audio.sunflower = "music/sun-flower-slow-jam.ogg"

206
2018 Ren’Py

а потом вызывают только имя

play music sunflower

КАК ДОБАВИТЬ ГОЛОС В ДИАЛОГ


label start:

voice "e01.ogg"
imya_silka "текст."

Где voice "e01.ogg" голос диалога и путь к файлу

КАК СДЕЛАТЬ СЛУЧАЙНОЕ


ВОСПРОИЗВЕДЕНИЕ МУЗЫКИ

init:
$ playlist = ["song1.mp3", "song2.mp3", "song3.mp3", "song4.mp3",
"song5.mp3"]
$ renpy.random.shuffle(playlist)
label start:
play music playlist fadeout 1.0 fadein 1.0

КАК ВСТАВИТЬ ПЕСНЮ В ГЛАВНОЕ МЕНЮ


В сценарии options.rpy найдите строку
#define config.main_menu_music = "main-menu-theme.ogg"
Уберите решетку и пропишите путь к фоновой песне

207
2018 Ren’Py

Собственно, всё.
Если хочется, чтобы в меню играло несколько мелодий по порядку, то
пишем:
define config.main_menu_music = ["music1.mp3", "music2.mp3",
"music3.mp3", "music4.mp3"]
или что бы они все перемешались
define config.main_menu_music = renpy.random.shuffle(["music1.mp3",
"music2.mp3", "music3.mp3", "music4.mp3"] )
Однако, в этом случае мелодия будет играть и после нажатия кнопки
старт.
Чтобы отключить музыку, после начала игры (нажатием кнопки start)
находим в сценарии script.rpy строку label start: и под ней
дописываем, не забывая про четыре пробела:

stop music fadeout 1.0

где fadeout создает эффект затухания длительностью в секундах


(если не нужен, то просто stop music).

КАК ПРИВЯЗАТЬ К КНОПКАМ ЗВУК


В файле screens.rpy в самом конце напишите
init python:
renpy.music.register_channel("test_one", "sfx", False)
renpy.music.register_channel("test_two", "sfx", False)
renpy.music.register_channel("test_three", "sfx", False)
renpy.music.register_channel("test_four", "sfx", False)
renpy.music.register_channel("test_five", "sfx", False)

208
2018 Ren’Py

renpy.music.register_channel("test_six", "sfx", False)


Далее, когда вы пишите кнопку, вы в нее добавляете канал
textbutton "X" xpos 100 ypos 200 action [Play("test_six",
"Click3.wav"),action Jump("gruppa_tatu")] hovered Play("test_one",
"menu_click_01.ogg")

Теперь разберем что тут записано


textbutton "X" xpos 100 ypos 200 action – начало большинства
кнопок
[Play("test_six", "Click3.wav"), - музыка при нажатии на канале
test_six(для нажатия достаточно 1 канала)
action Jump("gruppa_tatu")] – прыжок к метке
hovered Play("test_one", "menu_click_01.ogg") –музыка при
наведения (если несколько кнопок, то несколько муз каналов надо
использовать)
для горячих точек вот наглядный пример

209
2018 Ren’Py

ЧАСТИЧНОЕ ВОСПРОИЗВЕДЕНИЕ МУЗЫКИ


Ренпай поддерживает частичное воспроизведение музыки. Это
сделано, поместив специальное воспроизведение, приложенную в
угловых скобках, в начале файла.
Вот 3 его основных свойства.
from(с англ значит от)
Определяет положение в файле, в котором первый звук начинает
играть
to(с англ значит к)
Определяет положение в файле в котором будет конец
воспроизведения
loop(с англ значит петля)
Определяет положение в файле, в котором вторая и более позднее
воспроизведение начнет играть.

И примеры в сценарии
play music "<from 5 to 15.5>waves.opus"

Муз файл(waves.opus) будет воспроизводиться с 5 секунды и будет


играть 10,5 сек т.е. до 15,5 сек в файле

АЛЬТЕРНАТИВА
screen my_music_scr(t, melody):

timer t action [Play("music", melody), Hide("my_music_scr")]

label start:

show screen my_music_scr(t=3.0, melody="menu.mp3")

"?"

Другое действие

210
2018 Ren’Py

PLAY MUSIC "<LOOP 6.333>SONG.OPUS"

Будет играть song.opus полностью, затем петля(loop)вернется назад к 6.333 сек.

АВТОМАТИЧЕСКОЕ ОБЬЯВЛЕНИЕ МЕЛОДИЙ


И ЗВУКОВ
Дабы не прописывать пути и расширения для каждой мелодии и звуков, вот
пару функций, дублирующих стандартную работу со звуками. Только на
входе теперь имя мелодии без пути и расширения. Сделано для папок "music"
и "sound" и расширения "mp3".

init python:
def mplay(mname, fin=0, fout=0):
renpy.play("music/" + mname + ".mp3", channel="music", loop=True, fadein=fin,
fadeout=fout)
def splay(mname, fin=0, fout=0):
renpy.play("sound/" + mname + ".mp3", channel="sound", loop=False, fadein=fin,
fadeout=fout)

label start:
$ mplay("music1")###музыка с именем music1.mp3
$ splay("ku_ku")###звук с именем ku_ku.mp3

ПОСТАВИТЬ МУЗЫКУ НА ПАУЗУ


(http://renpyfordummies.blogspot.ru/2015/07/blog-post_18.html)

init python:

211
2018 Ren’Py

### запустить мелодию на канале


def mplay(fn, chan = "music", fin = 1.0, fout = 1.0):
renpy.play(fn + ".mp3", channel = chan, loop = True, fadein = fin, fadeout =
fout)
### канал на паузу
def mpause(channel = "music"):
c = renpy.audio.audio.get_channel(channel)
c.pause()
### снять с паузы
def munpause(channel = "music"):
c = renpy.audio.audio.get_channel(channel)
c.unpause()
### остановить мелодию
def mstop(chan = "music", fout=1.0):
renpy.music.stop(channel = chan, fadeout = fout)
### тест
label start:
$ mplay("mus")
pause (2.0)
$ mpause()
pause (2.0)
$ munpause()
pause (2.0)
$ mstop()
pause (2.0)
return

МУЗЫКА В МЕНЮ ОТ ВРЕМЕНИ СУТОК


(http://renpyfordummies.blogspot.ru/2017/01/blog-post.html)

init python:

212
2018 Ren’Py

### окно игры – в центр экрана


import os
os.environ['SDL_VIDEO_CENTERED'] = '1'

### функция переводит текущее время в название времени суток


import datetime
def get_t():
h = int(datetime.datetime.now().strftime("%H"))
res = "night" ### по умолчанию ночь
### границы любого времени суток можно поменять
if (h > 6) and (h < 11):
res = "morning"
if (h >= 11) and (h <= 18):
res = "day"
if (h > 18) and (h < 23):
res = "evening"
return res
last_t = None
### функция меняет музыку и освещение в меню
### в зависимости от времени суток
def change_mus():
global last_t
if last_t != get_t():
last_t = get_t()
### перезапускаем отрисовку меню
renpy.restart_interaction()
### меняем мелодию в главном меню
config.main_menu_music = last_t + ".ogg"
if renpy.music.get_playing() != last_t + ".ogg":
renpy.music.play(last_t + ".ogg")
### функцию - в action
ChangeMus = renpy.curry(change_mus)
### картинка для фона главного меню
style.mm_root.background = "mm.jpg"

213
2018 Ren’Py

### в main_menu после style "mm_root":


# timer .05 repeat True action ChangeMus()
# if last_t:
# add last_t

init:
### фильтры для освещения
image morning = "#8404"
image day = "#0000"
image evening = "#0484"
image night = "#000b"

### Игра начинается здесь.


label start:
"Вы создали новую игру Ren'Py."
return

КАК ПОКАЗАТЬ ГРОМКОСТЬ МУЗЫКИ В


ПРОЦЕНТАХ
Зайдите в сценарий screen.rpy и запишите следующий код:

init python:
# узнать громкость и перевести ее в целочисленные проценты
def getV(mixer):
return (int)(_preferences.get_volume(mixer)*100)

# действие - добавить или убавить громкость


class AddVolume(Action):
def __init__(self, mixer, value):
self.mixer = mixer
self.value = value

def __call__(self):
v = _preferences.get_volume(self.mixer) + self.value
if v > 1.0:
v = 1.0
214
2018 Ren’Py

if v < 0.0:
v = 0.0
_preferences.set_volume(self.mixer, v)

def get_selected(self):
return _preferences.get_volume(self.mixer) == self.value

Далее ищите там же экран настроек screen preferences():


и меняете эту строку
label _("Громкость музыки")
bar value Preference("music volume")
на
label _("Громкость музыки: %s" % (getV("music"))) # показываем
громкость в процентах
textbutton _("+") action AddVolume("music", .1)###Не обязательно,
достаточно бара
textbutton _("-") action AddVolume("music", -.1)###тоже самое
bar value Preference("music volume")

САУНДЧЕК, ПРИ СМЕНЕ ГРОМКОСТИ


# В любом файле.
init python:
persistent.last_check = _preferences.get_volume("sfx")
def play_sound_check():
if persistent.last_check != _preferences.get_volume("sfx"):
persistent.last_check = _preferences.get_volume("sfx")
renpy.sound.play("sound_check.mp3", "sound")
# В screens.rpy найти строчку:
# bar value Preference("sound volume")
# И дописать:
bar value Preference("sound volume") changed play_sound_check()

215
2018 Ren’Py

ПОЛЬЗОВАТЕЛЬ НЕ МОЖЕТ ПРОПУСТИТЬ СЦЕНУ ПОКА


ИГРАЕТ МУЗЫКА

init python:

class __MusicInteract(renpy.Displayable):

__author__ = "Vladya"

def __init__(self, filenames, channel="music", *music_ar, **music_kw):

super(__MusicInteract, self).__init__()
self.channel = channel
self.music_data = {
"args": [filenames, channel] + list(music_ar),
"kwargs": music_kw
}
self.__start_interact = False

def start_play(self):
renpy.music.play(
*self.music_data["args"],
**self.music_data["kwargs"]
)
self.__start_interact = True
return ui.interact()

def render(self, width, height, st, at):


if self.__start_interact:
if not renpy.music.is_playing(self.channel):
renpy.end_interaction(st)

renpy.redraw(self, 0)
return renpy.Render(1, 1)

def play_interact(*args, **kwargs):


u"""
Передавать аргументы, как обычному 'renpy.music.play'.
Управление вернётся игроку, как только закончится аудиофайл.
"""
_music_object = __MusicInteract(*args, **kwargs)
renpy.show("musicInteractObject", what=_music_object)
play_time = _music_object.start_play()
renpy.hide("musicInteractObject")
return play_time

label start:
$ play_interact("sound/file123.ogg", loop=False)

216
2018 Ren’Py

"Конец песни."
return

SPLASHSCREEN
Что это такое? Это экран, что появляется во время запуска
приложения.
Существуют 2 типа splashscreen

МЕТКА SPLASHSCREEN

Это метка, что появляется у вас до появления главного меню. В него


вы можете указать ограничение по возрасту, предупреждение по
возрасту, прописать рекламу вашего изображения, страницы
разработчиков или художников, пред историю того мира где
происходят события вашего проекта. А так же вставить видеоролик
Что бы создать данную метку вам потребуется прописать его в
сценарии. Простой пример из моего старого учебника:
label splashscreen:
….scene black
….centered "Внимание\n
Данная игра может содержать нецензурные выражения\n
и сцены насилия.Содержимое может вызвать у вас протест.\n
Данная игра является безобидной шуткой и ни в коем\n
случае не ставит перед собой цели оскорбить кого-либо\n
Все сходства с реальными персонажами и событиями\n
случайны. Эта игра содержит контент, принадлежащий\n
третьим лицам. По закону об авторском праве РФ я имею\n
право использовать его для создании пародии, которой\n

217
2018 Ren’Py

данная игра и является. Я не присваиваю себе\n


авторство над видео- и аудиозаписями, изображениями\n
и эффектами, я всего лишь являюсь автором всей картины\n
в целом. Все исходники указанны в конце игры(и/или описании)\n
Возрастная маркировка данной игры - 18+. "

….centered "{size=+10}САМИЗДАТ{/size}\n\n\n\n\nЛитературно-
публицистический журнал\n\n\n\n {size=-5}
{a=http://samlib.ru}http://samlib.ru{/a}{/size}"
….centered "Посетите нашу группу {a=http://vk.com/renpy}Ren'Py на
vk.com{/a}"

….return
laber start:
….
Обязательно в конце ставьте return иначе игра начнется без
главного меню. Сохраните и запустите ваш проект.

ТАК ЖЕ ЕГО МОЖНО МОДЕРНИЗИРОВАТЬ,


ПРОПИСАТЬ КНОПКУ ПРОПУСК СЦЕНЫ
если пользователь уже видел этот экран. То на 10 заход игры уже начинает бесить
невозможность пропустить данный текст.

label splashscreen:

if persistent.one:

scene black

menu:

"Пропустить историю, прелюдию и т.д. ?"

"Да":

218
2018 Ren’Py

jump afterintro

"Нет":

pass

scene black

centered "Внимание\n

Данная игра может содержать нецензурные выражения\n

и сцены насилия.Содержимое может вызвать у вас протест.\n

Данная игра является безобидной шуткой и ни в коем\n

случае не ставит перед собой цели оскорбить кого-либо\n

Все сходства с реальными персонажами и событиями\n

случайны. Эта игра содержит контент, принадлежащий\n

третьим лицам. По закону об авторском праве РФ я имею\n

право использовать его для создании пародии, которой\n

данная игра и является. Я не присваиваю себе\n

авторство над видео- и аудиозаписями, изображениями\n

и эффектами, я всего лишь являюсь автором всей картины\n

в целом. Все исходники указанны в конце игры(и/или описании)\n

Возрастная маркировка данной игры - 18+. "

centered "{size=+10}САМИЗДАТ{/size}\n\n\n\n\nЛитературно-публицистический
журнал\n\n\n\n {size=-5}{a=http://samlib.ru}http://samlib.ru{/a}{/size}"

centered "Посетите нашу группу {a=http://vk.com/renpy}Ren'Py на vk.com{/a}"

$ persistent.one = True

label afterintro:

pass

return

laber start:

……..

219
2018 Ren’Py

ИЛИ ЗАДАТЬ ОДНОРАЗОВЫЙ ВОПРОС


ПОЛЬЗОВАТЕЛЮ, А ТЕБЕ ТОЧНО ЕСТЬ 18?

label splashscreen:

if not persistent.one:

scene black

"Тебе точно 18?"

menu:

"Да":

$ persistent.one = True

pass

"Нет":

$ renpy.quit()

pass

return

label start:

ИЗОБРАЖЕНИЕ SPLASHSCREEN

Изображение, которое появляется при запуске приложения. Вставьте в ваш проект


изображение "presplash.png" и положите ее в папку game проекта, то она появится на
экране ещё перед появлением окна игры (на время загрузки проекта)

220
2018 Ren’Py

ЭКРАНЫ

Экраны прописываются отдельно, как метки, и их потом вызывают


в проект как обьект.

ПРАВИЛЬНЫЙ ПРИМЕР КАК ПРОПИСЫВАТЬ


ЭКРАН:
screen simple_screen():
frame:
xalign 0.5 ypos 50
vbox:
text _("Это экран.")
textbutton _("Хорошо"):
action Return(True)

label start:
call screen simple_screen
pause

Оператор screen говорит ренпаю, что это экран, и у него имя


simple_screen
Объект frame: используется что бы показать на каких координатах
будет находиться данный экран и нужна ли ему рамка
Объект vbox: расставляет вертикально все что в нем пропишут
text _("Это экран.") – текст
textbutton – текстовая кнопка

221
2018 Ren’Py

action Return(True) – действие при нажатии

КАК ОТОБРАЗИТЬ ЭКРАН В ПРОЕКТЕ


1) show screen
show screen imya_ekrana
Данный экран будет показываться, пока его не скроют.
Скрывают экраны командой hide screen imya_ekrana
2)call screen
call screen imya_ekrana останавливает ренпай, пока экран либо не
вернется на какое либо действие, либо не прыгнет в другое место
Например
screen simple_screen():
frame:
xalign 0.5 ypos 50
vbox:
text _("Это экран.")
textbutton _("Хорошо"):
action Return(True)
laber start:
call screen simple_screen
pause

У вас пропадет текстовый диалог, и пока вы не нажмете на


«Хорошо»и вы ничего не сможете сделать.

222
2018 Ren’Py

Когда заканчивается оператор call screen, экран автоматически


закрывается
В основном show screen применяется, что бы отобразить постоянные
элементы.
А call screen что бы отобразить короткие интерактивные экраны

ЭКРАН С 3 ПАРАМЕТРАМИ
Вот еще 1 пример экрана, который берет сразу 3 параметра
init:
$ message = "Привет мир"
screen parameter_screen(message, okay=Return(True),
cancel=Return(False)):
frame:
xalign 0.5 ypos 50
vbox:
text "[message!t]"
textbutton _("Okay"):
action okay
textbutton _("Cancel"):
action cancel
label start:
show screen parameter_screen(_("Привет."), cancel=Notify(_("Ты не
можешь отменить")))
pause

Теперь рассмотрим параметры

223
2018 Ren’Py

[message!t] – показываемое сообщение


okay и cancel – действия при нажатии, Это базовые значения,
используемые когда не задано других аргументов.
Каждый параметр имеет приоритет над всеми остальными
переменными
Параметры позволяют нам изменять внешний вид экрана, попросту
показав его с другими аргументами
show screen parameter_screen(_("Shiro был тут."))

НЕСКОЛЬКО ПАРАМЕТРОВ ЭКРАНОВ


1) MODAL TRUE

Когда у modal стоит значение True, вы не можете ни с чем


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

screen modal_example():

modal True

frame:

xalign 0.5 ypos 50

textbutton _("Закрыть этот экран"):

action Hide("modal_example")

label start:

show screen modal_example

pause

224
2018 Ren’Py

2)ZORDER

Контролирует порядок наложения. Чем больше значение – тем ближе


к игроку.
screen zorder_100_screen():
zorder 100
frame:
xalign 0.5 xoffset 50 ypos 70
text _("Zorder 100")

label start:
show screen zorder_100_screen
pause
Стандартный экран имеет значение 0

3)STYLE_PREFIX

Определяет стиль экрана


screen style_prefix_screen():
style_prefix "red"
frame:
xalign 0.5 ypos 50
text _("Этот текст красный.")
style red_frame:
background "#440000d9"
style red_text:

225
2018 Ren’Py

color "#ffc0c0"

label start:
show screen style_prefix_screen
pause

Когда используется префикс red, рамка берет стиль из style


red_frame
А текст из style red_text

4) TAG MENU

Аналогичен modal True но скрывает все экраны


screen tag_example():
tag menu
frame:
xalign 0.5 ypos 50
textbutton _("Закрыть этот экран"):
action Hide("tag_example")
label start:
show screen tag_example
pause

PYTHON В ЭКРАНАХ
Операторы питона в экранах работают точно так же как и в обычном
скрипте.

226
2018 Ren’Py

Строки с питоном в ренпае начинаются со знаком $ или python.


Пример
screen single_python_screen():
$ message = _("Привет мир")
frame:
xalign 0.5 ypos 50
vbox:
text "[message!t]"
или
screen block_python_screen():
python:
message1 = _("Привет мир")
message2 = _("Приятно с тобой познакомиться")
frame:
xalign 0.5 ypos 50
vbox:
text "[message1!t]"
text "[message2!t]"

label start:
show screen single_python_screen
show screen block_python_screen
pause

Есть 1 различие между питоном в экранах и в сценарии.

227
2018 Ren’Py

В питоне экранах нельзя иметь сторонние функции, т.е. в экране вы не


поменяете значение переменной.

ОПЕРАТОРЕ DEFAULT
В операторе default можно установить первоначальное значение
переменной экрана при его запуске. Это значение может быть
изменено через SetScreenVariable и ToggleScreenVariable
Пример
screen default_screen():
default n = 0
frame:
xalign 0.5 ypos 50
vbox:
text "n = [n]"
textbutton _("Увеличить значение") action SetScreenVariable("n",
n + 1)

label start:
show screen default_screen

ОПЕРАТОРЫ IF, ELIF, ELSE


Обычные операторы if, elif, else работают, так же как и в скрипте.
screen if_screen():
default n = 0
frame:
xalign 0.5 ypos 50

228
2018 Ren’Py

vbox:
if n > 2:
text "n = [n]" color "#cfc"
else:
text "n = [n]" color "#fcc"
textbutton _("Увеличить") action SetScreenVariable("n", n + 1)

label start:
show screen if_screen
pause

Где если данные переменной n меньше 2, будет значение else


Если n больше 2, будет if

ОПЕРАТОР FOR
Есть в переменных еще оператор for. Он берет список, каждое
значение в списке запускает в блоке action.
screen for_screen():
$ landings = [ _("Earth"), _("Moon"), _("Mars") ]
frame:
xalign 0.5 ypos 50
vbox:
for i in landings:
textbutton "[i!t]" action Return(i)
229
2018 Ren’Py

label start:
show screen for_screen
pause

ОПЕРАТОР FRAME(РАМКА ДЛЯ ЭКРАНА)

Создает рамку, и в нем указывают положение экрана.


Пример без Frame

С Frame

230
2018 Ren’Py

КАК УБРАТЬ СТАНДАРТНУЮ РАМКУ В


ЭКРАНЕ
Пишут background None
screen single_python_screen():
$ message = _("Привет мир")
frame:
xalign 0.5 ypos 50
background None ###убирает рамку
vbox:
text "[message!t]"

ОПЕРАТОР ADD И КАК ДОБАВИТЬ


ИЗОБРАЖЕНИЕ В ГЛАВ МЕНЮ

Данный оператор позволяет добавлять в экран изображения.

231
2018 Ren’Py

Например, если изображение прописано


image logo base ="images/logotip.jpg"

screen add_image_example():
add "logo base"
Так же можно в нем прописать и анимации, со всеми объектами и
трансформациями.

Или указав путь к изображению


screen add_filename_example():
add "images/logo base.png"

Так же в нем можно прописывать различные трансформации


init:
transform unrotate:
zoom 0.7 rotate 43.21
linear 1.0 rotate 0

screen add_at_transform_example():
add "logo base" at unrotate

label start:
show screen add_at_transform_example

232
2018 Ren’Py

КАК ПРОПИСАТЬ ИЗОБРАЖЕНИЯ В


ГЛАВНОЕ МЕНЮ?
Для этого вам потребуется открыть screen.rpy. найти строку screen
main_menu: и там у вас будет записан экран главного меню, там вы
пишете изображение
screen main_menu():
### This ensures that any other menu screen is replaced.
tag menu
### The background of the main menu.
add "images/logotip_fona.jpg"
textbutton _("Новая игра") action Start()
textbutton _("Загрузить") action ShowMenu("load")
textbutton _("Настройки") action ShowMenu("preferences")
textbutton _("Помощь") action Help()
textbutton _("Выйти") action Quit(confirm=False)

Тоже самое относится и к другим разделам главного меню(загрузки,


настройки и т.д)
Это если вы создаете проект на старой версии.
На новой вам потребуется зайти в сценарий screen.rpy
и найти метку:

screen main_menu():

## Этот тег гарантирует, что любой другой экран с тем же


тегом будет
## заменять этот.
tag menu

style_prefix "main_menu"

add gui.main_menu_background

233
2018 Ren’Py

## Эта пустая рамка затеняет главное меню.


frame:
pass

Что бы убрать рамку, которая вокруг текста находится, вам


потребуется убрать из текста следующие строки
## Эта пустая рамка затеняет главное меню.
#frame:
#pass

Что бы поменять изображение фона вам потребуется зайти в файл


gui.rpy и найти строку
gui.main_menu_background – и в ней прописываете изображение
меню.

Что бы поменять координаты кнопок вам нужно найти в screen.rpy


метку
screen navigation():

vbox:
style_prefix "navigation"

xpos gui.navigation_xpos
yalign 0.5

spacing gui.navigation_spacing

if main_menu:

И все координаты вы можете изменить просто vbox и его значения на


ваше усмотрение

ОПЕРАТОР TEXT
Данный оператор прописывает текст на экране.
screen text_example():
frame:

234
2018 Ren’Py

xalign 0.5 ypos 50


text _("Текст на экране"):
size 30
label start:
show screen add_at_transform_example

Если после текста мы поставим : то мы можем прописать различные


параметры.

Так же в нем можно прописать значения переменной.


screen text_interpolation_example():
$ answer = 42

frame:
xalign 0.5 ypos 50
text _("Ответ: [answer].")
label start:
show screen text_interpolation_example
pause

КАК ПРОПИСАТЬ МУЗЫКУ В ЭКРАНЕ


screen main_menu():
### Сразу прописываем музыку что будет звучать в экране.
python:
renpy.music.play("menu.mp3", fadeout=10.0, fadein=15.0)

235
2018 Ren’Py

frame:
…………….

КАК ПРОПИСЫВАТЬ КООРДИНАТЫ


ОБЪЕКТАМ?
screen implicit_fixed_example():
frame:
xalign 0.5 ypos 50
xsize 440 ysize 316

text "1" xpos 41 ypos 184


text "2" xpos 135 ypos 177
text "3" xpos 92 ypos 3
text "4" xpos 359 ypos 184
text "5" xpos 151 ypos 25
label start:
show screen implicit_fixed_example

ОПЕРАТОР ON
Данный оператор запускает автоматически событие при его вызове. В
нижнем примере будет 2 события: событие show (экран впервые
показывается) и событие hide(экран убирается)
screen on_screen():
on "show" action Notify(_("Появился экран"))
on "hide" action Notify(_("Экран убрали"))

236
2018 Ren’Py

label start:
schow screen on_screen
"Привет"
hide screen on_screen
"Пока"
Как видим, данный экран с текстом уведомления Notify и через
несколько секунд текст исчезает.

КАК ЗАДАТЬ КООРДИНАТУ – КУДА БУДЕТ


ДВИГАТЬСЯ МЫШКЕ
screen force_mouse_move():
on "show":
action MouseMove(x=650, y=350, duration=.3)
timer .5 repeat True action MouseMove(x=650, y=350, duration=.3)
textbutton "Click Me" xalign .5 yalign .5 action Return()
label start:
scene black
call screen force_mouse_move
"..."

ОПЕРАТОР KEY
Данный оператор позволяет вызывать события нажатием клавиши на
клавиатуре.
screen on_key_screen():
frame:
xalign 0.5 ypos 50
text _("Нажмите на англ букву'a'.")

237
2018 Ren’Py

key "a" action Notify(_("Вы нажали на анг А"))

label start:
show screen on_key_screen
Питон очень чувствителен к тому, какой раскладкой клавиатуры вы
нажали и не активирована ли Caps Lock . Например, в выше
написанном примере буква а, будет активна, только на английской
раскладке при отключенном Caps Lock. Что бы она правильно
работала на русской (или китайской и т.д.) клавише нам потребуется
прописать все варианты значений (Заглавную, маленькую, и на другом
языке).
screen on_key_screen():
frame:
xalign 0.5 ypos 50
text _("Нажмите на англ букву'a'.")
key "a" action Notify(_("Вы нажали на А"))
key "A" action Notify(_("Вы нажали на А"))
key "Ф" action Notify(_("Вы нажали на А"))
key "ф" action Notify(_("Вы нажали на А"))

label start:
show screen on_key_screen

Так же обратите внимание, что данный оператор работает только на


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

238
2018 Ren’Py

http://www.pygame.org/docs/ref/key.html (учитывайте что там только анг


раскладка прописана)
Так же прописываются к оператору данному функции при действии
ссылка

УПРАВЛЯЕМ ШТРУДЕЛЕМ
init:
$ ax, ay = (.5, .5)
$ aplus = .01
transform axy(x, y):
align(x, y)
image pers = Text("{size=256}@")
screen test:
key "focus_left" action SetVariable("ax", ax - aplus)
key "focus_right" action SetVariable("ax", ax + aplus)
key "focus_up" action SetVariable("ay", ay - aplus)
key "focus_down" action SetVariable("ay", ay + aplus)
add "pers" at axy(ax, ay)

label start:
centered "Жми кнопки стрелок для управления штруделем.{w=2.0}
{nw}"
show screen test
pause
return

КОЛЕСИКО МЫШКИ
screen my_keys:
key "rollback" action Show("название_экрана") # заменит действие
"перемотка назад" на показ экрана (затронет колесико мыши, кнопку
PgUp и кнопку джойстика)
key "mousedown_5" action Hide("название_экрана") # установит
действие для прокрутки колесика вперед

label start:

239
2018 Ren’Py

show screen my_keys


"а вот теперь покрути-ка колесико..."
"?"
hide screen my_keys
"..."
"...а теперь?"

ЧТО ТО ВРОДЕ ПРЕДВАРИТЕЛЬНОГО


СООБЩЕНИЯ, ЧТО ПОЯВИТСЯ НА ВВОД
default message = ""
default rest_of_message = "I am message"
init python:
def next_letter():
global message
global rest_of_message
message += rest_of_message[0]
rest_of_message = rest_of_message[1:]

screen my_message():
text message
key "p" action Function(next_letter)
# rest of keys

label start:
call screen my_message
"Вы создали новую игру Ren'Py."

240
2018 Ren’Py

ОБЬЕКТЫ BOX И GRID


Объект box берет объекты и располагает их так, как мы укажем box.
Очень часто применяется при написании кнопок или нескольких
значений которые мы должны отобразить на экране(настройки и т.д)
Примеры с hbox где объекты горизонтально ставятся.
screen hbox_example():
frame:
xalign 0.5 ypos 50
hbox:
spacing 10
text "1"
text "2"
text "3"
text "4"
text "5"
label start:
show screen hbox_example

Где spacing расстояние между объектами

241
2018 Ren’Py

А объект vbox действует вертикально

Объект Grid создает таблицы.

242
2018 Ren’Py

screen grid_example():
frame:
xalign 0.5 ypos 50
grid 3 2:
spacing 10
text "1"
text "2"
text "3"
text "4"
text "5"
null
label start:
show screen grid_example

243
2018 Ren’Py

Разберем подробней, что тут прописано


screen grid_example():-имя экрана
frame: - прописываем положение и создаем рамку
xalign 0.5 ypos 50 – координаты
grid 3 2: - создаем таблицу, в которой будет 3 столба в 2 строки, где
нам потребуется прописать 6 объектов (т.к. 3*2=6) иначе возникнет
ошибка. И в нем прописываем объекты (двоеточие)
spacing 10 – параметр, которое делает расстояние между объектами
text "5" – 1 из объектов
null – пустая ячейка, применяется, когда объекта еще нет, но он
должен будет появиться и что бы не было ошибки, пишут данный
объект.
Так же если вам требуется сделать другое расположение
заполнения(т.е. таблица заполняется горизонтально, а если нужно
вертикально например) то используют параметр transpose
screen grid_transpose_example():
frame:
xalign 0.5 ypos 50
grid 3 2:
spacing 10
transpose True
text "1"
text "2"
text "3"
text "4"
text "5"
null

244
2018 Ren’Py

label start:
show screen grid_transpose_example

Обратите внимание! В гриде, все объекты делят расстояние на свои


размеры, т.е. если 1 объект назвать, например не 4, а словом бабуля,
то расстояние будет вычисляться по самому длинному названию, т.е.
от бабули будут рассчитываться положения на экране. Учитывайте
это когда будете создавать свои таблицы.
Ну и пример еще один .

245
2018 Ren’Py

246
2018 Ren’Py

ТЕКСТОВЫЕ КНОПКИ И ЭКРАН


УВЕДОМЛЕНИЯ NOTIFY
Кнопки – это такие объекты, которые при нажатии активируют
действие.
Прописываются в экранах.(screen)
Разберем пример самой простейшей тестовой кнопки.
screen button_hover_example():
frame:
xalign 0.5 ypos 50
button:
action Notify(_("Ты нажал на кнопку"))
hovered Notify(_("Ты навел на кнопку"))
unhovered Notify(_("Ты отвел кнопку"))
text _("Кликни на меня")
label start:
show screen button_hover_example

screen button_hover_example():-экран с кнопкой

frame: -рамка

xalign 0.5 ypos 50 –координаты экрана

button: - кнопка, в которой прописываем ее действия и внешний вид

action Notify(_("Ты нажал на кнопку")) –при нажатии(action)


произойдет событие(Notify(_("Ты нажал на кнопку"))) – в данном
случае высветится надпись уведомления(Notify)

247
2018 Ren’Py

hovered – при наведении произойдет событие(обычно используется


что бы пояснять комментариями что произойдет при нажатии)

unhovered – как уберете кнопку, произойдет событие(используется


довольно часто, когда пользователю предстоит выбор)

text - тут мы программе указываем что у нас будет текст в виде


кнопки

Или еще пример


screen vibor():
frame:
xalign 0.5 ypos 50
has vbox
text _("Кого вы спасете?")
textbutton _("Женщина."):
action Jump("Dev")
hovered Notify(_("Ты хочешь спасти девушку?"))
unhovered Notify(_("А как ты потом матери в глаза смотреть
будешь?"))
textbutton _("Ребенок"):
action Jump("Kind")
hovered Notify(_("Ты хочешь спасти ребенка?"))
unhovered Notify(_("А как ты потом ему объяснишь Где
мама?"))
label start:
call screen vibor

248
2018 Ren’Py

где Jump("Kind")прыжок в метку label Kind

А КАК ИЗМЕНИТЬ NOTIFY?

Изображение, которое отвечает за него, находится по адресу


gui/notify.png
Что бы прописать координаты зайдите в screen.rpy и найдите такую
строку и изменяете на свое усмотрение
screen notify(message):
zorder 100
style_prefix "notify"
frame at notify_appear:
text message
timer 3.25 action Hide('notify')
transform notify_appear:
on show:
alpha 0

249
2018 Ren’Py

linear .25 alpha 1.0


on hide:
linear .5 alpha 0.0

style notify_frame is empty


style notify_text is gui_text
style notify_frame:
ypos gui.notify_ypos
background Frame("gui/notify.png", gui.notify_frame_borders,
tile=gui.frame_tile)
padding gui.notify_frame_borders.padding
style notify_text:
properties gui.text_properties("notify")

СВОЙ ЭКРАН NOTYFY2


screen note(message):

zorder 100
style_prefix "note"

frame at note_appear:
text "[message!tq]"

timer 2 action Hide('note')

transform note_appear:
on show:
alpha 0
linear .25 alpha 1.0
on hide:
linear .5 alpha 0.0

250
2018 Ren’Py

style note_frame is empty


style note_text is gui_text

style notify_frame:
xalign 0.5 ypos 0.82 xpos 0.97
background None #Frame("gui/notify.png", gui.notify_frame_borders,
tile=gui.frame_tile)

style note_text:
properties gui.text_properties("note")
color "#fff"
size 40
font "fonts/myfont.ttf"
И где то
init:
def show_note(text):
renpy.show_screen("note", message=text)

# . .hovered Function(show_note, "test")


или
#….hovered Show(note, message="test")

КАК ПРОПИСАТЬ В ЭКРАНЕ ВОПРОС ПРИ


НАЖАТИИ
label restart:
call screen confirm(message=u _("Ты точно хочешь ударить ее? Ваше
отношения могут измениться"), yes_action=Jump("da"),
no_action=Jump("net"))

screen button2:
frame:
align 0.5

251
2018 Ren’Py

textbutton _("Ударить ее") action Jump("restart")

ВЫЗОВ SCREEN С ПРЕОБРАЗОВАНИЕМ


init:
transform atlShowTrans(t=.5):
align (.5, .5)
alpha .0
on appear:
alpha 1.
on show:
linear .01 alpha .0
linear t alpha 1.
on hide:
linear t alpha .0

screen myScreen(*variants):
default defPic = Null()
default isShow = False
showif isShow:
add At(defPic, atlShowTrans)
hbox:
align (.5, .75)
spacing 300
for txt, pic, lab in variants:
textbutton txt:

252
2018 Ren’Py

text_size 100
action Jump(lab)
hovered (
SetScreenVariable("defPic", pic),
SetScreenVariable("isShow", True)
)
unhovered SetScreenVariable("isShow", False)

init python:

def _call_screen(name, trans=None, **kw):


u"""
Вызов скрина, с преобразованием.
"""
_exceptions = (renpy.game.JumpException,
renpy.game.CallException)
renpy.mode("screen")

renpy.show_screen(name, **kw)
renpy.transition(trans)

try:
result = ui.interact(
mouse="screen",
type="screen",
roll_forward=renpy.roll_forward_info()

253
2018 Ren’Py

)
except _exceptions as exc:
result = exc

renpy.hide_screen(name)
renpy.transition(trans)

renpy.exports.checkpoint(result)

if isinstance(result, _exceptions):
raise result

return result

screen testScreen:
textbutton u"Тестовый элемент" action Jump("testLabel")

label start:
scene black with None
$ _call_screen("testScreen", dissolve)
return

label testLabel:
"Следующий лейбл."
return

254
2018 Ren’Py

СПИСОК ДЕЙСТВИЙ КНОПОК ДЛЯ


TEXTBUTTON
Ранее мы рассмотрели 3 действия, которые прописывают в кнопках,
сейчас рассмотрим более подробнее.
hovered
Действие при наведении на кнопку
action
Действие при нажатии.
alternate
Действия при удержании(на планшетах), или нажатие правой
кнопки(на ПК)

unhovered
Действие когда с кнопки убрали мышь
selected
Выражение, которое определяет, нажата ли кнопка или нет.

sensitive
Выражение, которое определяет, чувствительна ли кнопка или нет.

keysym
Строка, дающая keysym описание клавиши на клавиатуре, которая,
когда нажато, вызывает действие этой кнопки.

alternate_keysym
Строка, дающая keysym описание клавиши на клавиатуре, которая,
когда нажато, вызывает альтернативное действие этой кнопки.

255
2018 Ren’Py

ФУНКЦИИ ПРИ НАЖАТИИ.

Прежде чем мы рассмотрим варианты функций, обратите внимание,


как прописывать правильно сразу несколько функций.
textbutton "Marsopolis":
action [ Jump("mars"), Hide("mars_flag") ]

Т.е. мы все действия заключаем в такие [] скобки(для удобства) и между


действиями ставят запятую, иначе будет ошибка.

ACTION ****

Список действий
Jump(LABEL) - прыжок к метке
Call(LABEL, FROM_CURRENT=FALSE) - вызов метки
Show(SCREEN, TRANSITION=NONE, *ARGS, **KWARGS) -вызвать
Hide(SCREEN, TRANSITION=NONE) – убрать
NullAction(*ARGS, **KWARGS) – ничего не делать
Return(VALUE=NONE)- возвратиться назад, True и False
ShowTransient(SCREEN, *ARGS, **KWARGS) - Показывает
переходный экран. Переходный экран будет скрыт, когда текущее
взаимодействие завершит.

ДЕЙСТВИЯ ДАННЫХ

Они устанавливают или переключают данные.


AddToSet(SET, VALUE)- увеличить и установить значение

RemoveFromSet(SET, VALUE)-удалить значение

SetDict(DICT, KEY, VALUE) Заставляет установить значение,ключ.

256
2018 Ren’Py

SetField(OBJECT, FIELD, VALUE)- заставляет объект и поле быть


установленным в данное значение. Объект является объектом, поле
является строкой, дающей название поля, чтобы установить, и
оценить, значение для установления его

SetScreenVariable(NAME, VALUE) - Заставляет имя переменной,


связанное с текущим экраном собираться оценить.

SetVariable(variable, value) Заставляет переменную изменить


значение

ToggleDict(dict, key, True_value=None, False_value=None)


Переключается значение ключа. Переключение средств
инвертировать значение, когда действие выполняется.

True_value
Если не Ни один, то это - истинное значение, которое мы
используем.
False_value
Если не Ни один, то это - ложное значение, которое мы
используем.

ToggleField(object, field, True_value=None, False_value=None)- Поле


переключателей на объекте. Переключение средств инвертировать
булево значение того поля, когда действие выполняется.

ToggleScreenVariable(name, True_value=None, False_value=None)-


Переключается значение имени переменной на текущем экране.

ToggleSetMembership(set, value)- Переключается членство имеющее


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

ToggleVariable(variable, True_value=None, False_value=None)


Переменная переключателей.
True_value
Если не Ни один, то это - истинное значение, которое мы
используем.
False_value

257
2018 Ren’Py

Если не Ни один, то это - ложное значение, которое мы


используем.

MENU ACTIONS

Эти действия вызывают меню или прежде всего полезны как в основном или игровом
меню.

MainMenu(confirm=True)- выйти в главное меню. confirm=True –спрашивать пользователя


о выходе в главное меню

Quit(confirm=None)- выйти из игры. confirm=True –спрашивать пользователя о выходе из


игры.

ShowMenu(SCREEN=NONE, *ARGS, **KWARGS)- вызвать меню

Start("FOO")- запустить, "FOO" –название метки, если будет пусто, то автоматически


берется метка start

FILE ACTIONS
Эти действия применяются в сохранениях, загрузках и удалении файлов.

FileAction(NAME, PAGE=NONE, **KWARGS)- делать что то с файлом(обычно загрузить и


сохранить)

FileDelete(NAME, CONFIRM=TRUE, PAGE=NONE) – удалить файл


FileLoad(NAME, CONFIRM=TRUE, PAGE=NONE, NEWEST=TRUE) –загрузить файл
FilePage(PAGE)- Устанавливает страницу файла в страницу, которая должна быть
одним из "автоматических", "быстрых", или целое число.

FilePageNext (max=None, wrap=False)- пройти на страницу

FilePagePrevious(max=None, wrap=False)- пройти на предыдущую страницу если


возможно.

FileSave(name, confirm=True, newest=True, page=None, cycle=False)- сохранить файл

FileTakeScreenshot (*args, ** kwargs) - Возьмите скриншот, который будет


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

258
2018 Ren’Py

QuickLoad (confirm=True) - выполняет быструю загрузку.

QuickSave(message=u'Quick save complete.', newest=False)- выполняет быстрое


сохранение.

message -Сообщение для отображения пользователю, когда быстрое сохранение


заканчивается.
newest -Набор к истинному для маркировки quicksave как новейшее сохранение.

AUDIO ACTIONS
PauseAudio(channel, value=True)- Устанавливает паузу для канала.

Play(channel, file, selected=None, **kwargs)- Заставляет аудиофайл играться на данном


канале.

Queue(channel, file, **kwargs)- Заставляет аудиофайл быть поставленным в очередь на


данном канале

SetMixer(MIXER, VOLUME) - регулирует громкость микшера для оценки


SetMute(mixer, mute)- Устанавливает бесшумное состояние одного или более микшеров.
Когда микшер будет отключен звук, звуковые каналы, связанные с тем микшером,
прекратят играть аудио.

Stop(CHANNEL, **KWARGS)-остановить аудио канал


ToggleMute(mixer)- Переключается бесшумное состояние одного или более микшеров

VOICE ACTIONS
PlayCharacterVoice(VOICE_TAG, SAMPLE, SELECTED=FALSE)- Это играет образец на
голосовом канале, как будто сказанный характером с voice_tag.
SAMPLE -Полный путь к звуковому файлу. Никакая связанная с голосом обработка этого
файла не сделана.

SetCharacterVolume (voice_tag, volume=None)- изменить громкось голоса. Задается


volume в диапазоне от 0.0 до 1.0

SetVoiceMute(VOICE_TAG, MUTE)- Если немой(MUTE) верен(true), голоса немых,


которые играются с данным voice_tag. Если немой(MUTE) ложный(False), голоса
ненемых, которые играются с voice_tag.

ToggleVoiceMute (voice_tag, invert=False)- пуговица, заглушка voice_tag. Это отобрано,


если высказавший признак приглушен, если обратный свод не верен, в этом случае это
отобрано, если голос неслаб.

259
2018 Ren’Py

VoiceReplay (*args, ** kwargs) - повторить последний играемый голос

OTHER ACTIONS
Confirm(prompt, yes, no=None, confirm_selected=False)- Предлагает пользователю
подтверждение действия. Если пользователь щелкает да, действие выполняется. Иначе
никакое действие не выполняется.

HideInterface(*args, **kwargs)- Заставляет интерфейс быть скрытым до пользовательских


щелчков.

If(expression, True=None, False=None)- Это возвращает True, если выражение является


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

MouseMove (x, y, duration=0)-переносит мышь на координату х и у


duration –продолжительность по времени

Notify(message)- вывести уведомление

OpenURL(URL)- открыть в браузере ссылку


QueueEvent(event, up=False)- Ставит данные события в очередь

Rollback(*args, **kwargs)- откатить назад событие

RollbackToIdentifier(identifier)- Это заставляет откат к идентификатору происходить.


Идентификаторы отката возвращены как часть объектов HistoryEntry.

Screenshot(*args, **kwargs)- сделать скриншот

SelectedIf(EXPRESSION)- Это позволяет выражению управлять, если кнопка должна


быть отмечена, как выбрано. Это должно использоваться в качестве части списка с одним
или более действиями. Например:
### кнопка нажата, если mars_flag=True
textbutton "Marsopolis":
action [ Jump("mars"), SelectedIf(mars_flag) ]
SensitiveIf(EXPRESSION)- Это позволяет выражению управлять, если
кнопка должна быть отмечена как чувствительная. Это должно
использоваться в качестве части списка с одним или более действиями.
Skip(fast=False, confirm=False)- пропустить

With(TRANSITION)- переход

260
2018 Ren’Py

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

Так же существуют кнопки в которых используют изображение.

IMAGEBUTTON
Имеет много общего с текстовой кнопкой, но и имеются и различия.

САМАЯ ПРОСТАЯ ГРАФИЧЕСКАЯ КНОПКА


screen gui_game_menu():
vbox xalign 1.0 yalign 1.0:
imagebutton auto "images/button_%s.png" action Jump('ddde')

label start:
call screen gui_game_menu

imagebutton auto –изображение которое автоматически(auto) берет


изображение с названием button_insensitive.png, button_idle.png,
button_hover.png и т.д.и автоматически будут действовать по заложенным
командам в их названии. используется для удобства(или теми кто не парится
насчет размера проекта, ибо нельзя будет применить различные
трансформации к изображениям). И не забудьте про _%s

"images/button_%s.png" – путь к изображению, где находится графическая


кнопка.

_%s – показывает программе что тут применяется авто подбор изображения

action Jum('ddde') – прыжок к метке ddde

МОЙ ЛЮБИМЫЙ СПОСОБ

screen imagebutton_example():
frame:
xalign 0.5 ypos 50
imagebutton:
idle "logo bw"
hover "logo base"
261
2018 Ren’Py

action Jump('ddde')
label start:
call screen imagebutton_example

Где logo bw изображение с трансформацией.

Теперь разберем, что значат idle и какие вообще бывают значения

insensitive -Изображение используется, когда кнопку нельзя использовать

idle - Изображение используется, когда кнопка не активна.

hover - Изображение используется, когда кнопка активна.

selected_idle - Изображение используется, когда кнопка нажата и


неактивна.
selected_hover -Изображение используется, когда кнопка нажата и
неактивна

selected_insensitive - Изображение используется, когда кнопка


нажата и нечувствительна

Вот и вся разница между textbutton и imagebutton.


Так же можно объединить оба варианта кнопок для получения вот
такого результата.

ТЕКСТОВАЯ КНОПКА С ГРАФИЧЕСКИМИ


ЭЛЕМЕНТАМИ

262
2018 Ren’Py

screen button_inline_style_example():
frame:
xalign 0.5 ypos 50
textbutton _("Кликните на меня."):
idle_background Frame("button glossy idle", 12, 12)
hover_background Frame("button glossy hover", 12, 12)
xpadding 20
ypadding 10
xmargin 5
ymargin 5
hover_sound "pong_beep.opus"
text_idle_color "#c0c0c0"
text_hover_color "#ffffff"
action Notify(_("Вы нажали на кнопку."))

label start:
call screen button_inline_style_example

Что мы здесь сделали, мы прописали текстовую кнопку(textbutton


_("Кликните на меня.")), и в нее мы прописали(:) значения
графической кнопки,( idle_ и т.д.)

263
2018 Ren’Py

Как вы заметили к стандартной idle_ добавилась background что это


такое и его антагонист сейчас попробую объяснить.

background – визуальный объект, который используется в качестве


фона. Зачастую его используют как фон рисунок, который
масштабирует фон и рамку кнопки в единое целое(пример выше с
кнопкой).
foreground – визуальный объект, который используется в качестве переднего
фона.

Их можно использовать со всеми значениями графической кнопки.


idle_ idle, selected_idle
hover_ hover, selected_hover
selected_ selected_idle, selected_hover
insensitive_ insensitive
selected_idle_ selected_idle
selected_hover_ selected_hover
selected_insensitive_ selected_insensitive
Более подробней разберем их в разделе стиль

style button:
background "#006"
insensitive_background "#444"
hover_background "#00a"

КАК ПРОПИСАТЬ КНОПКЕ, НЕ


АКТИВИРОВАТЬ ПРОЗРАЧНЫЕ ПОЛЯ.
В графических кнопках, когда вы наводите на кнопку курсор, она
выделяется, а что если вам нужно что бы ее невидимая часть, не
могла позволить ее выделить? Для этого в кнопке, после координат,
но перед действиями(action), мы прописываем focus_mask.
screen main_menu():
### This ensures that any other menu screen is replaced.
tag menu

264
2018 Ren’Py

### The background of the main menu.


add Animation("images/anim/koster/1.gif", 0.1,
"images/anim/koster/2.gif", 0.1, "images/anim/koster/3.gif", 0.1,
"images/anim/koster/4.gif", 0.1, "images/anim/koster/5.gif", 0.1,
"images/anim/koster/6.gif", 0.1, "images/anim/koster/7.gif", 0.1,
"images/anim/koster/8.gif", 0.1, "images/anim/koster/9.gif", 0.1,
"images/anim/koster/10.gif", 0.1, "images/anim/koster/11.gif", 0.1,
"images/anim/koster/12.gif", 0.1, "images/anim/koster/13.gif", 0.1,
"images/anim/koster/14.gif", 0.1, "images/anim/koster/15.gif", 0.1,
"images/anim/koster/16.gif", 0.1)###анимация укуреная на главное меню

imagebutton auto "images/elements/new_game_%s.png" xpos 556 ypos


250 focus_mask True action Start()
imagebutton auto "images/elements/load_%s.png" xpos 556 ypos 300
focus_mask True action ShowMenu("load")
imagebutton auto "images/elements/options_%s.png" xpos 556 ypos
350 focus_mask True action ShowMenu("preferences")
imagebutton auto "images/elements/help_%s.png" xpos 556 ypos 400
focus_mask True action Help()
imagebutton auto "images/elements/exit_%s.png" xpos 556 ypos 450
focus_mask True action Quit(confirm=True)

КАК ПРИ НАВЕДЕНИИ НА КНОПКУ


СДЕЛАТЬ, ЧТО БЫ ЭКРАН МЕНЯЛ ЦВЕТ
init:
transform atlShowTrans(t=.5):
align (.5, .5)
alpha .0

265
2018 Ren’Py

on appear:
alpha 1.
on show:
linear .01 alpha .0
linear t alpha 1.
on hide:
linear t alpha .0

screen myScreen(*variants):
default defPic = Null()
default isShow = False
showif isShow:
add At(defPic, atlShowTrans)
hbox:
align (.5, .75)
spacing 300
for txt, pic, lab in variants:
textbutton txt:
text_size 100
action Jump(lab)
hovered (
SetScreenVariable("defPic", pic),
SetScreenVariable("isShow", True)
)
unhovered SetScreenVariable("isShow", False)

266
2018 Ren’Py

label start:
call screen myScreen((_("Затемнить"), Solid("#000"), "metka1"),
("Осветлить", Solid("#fff"), "metka2"))
label metka1:
pass
label metka2:
pass
return

ПЛЮСЫ И МИНУСЫ КНОПОК


Кнопки можно использовать как карту на экране, прописав каждой кнопке
действия, но их не сильно любят использовать в проектах, и вот почему:

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

2)Занимает память.
Когда вы прописываете 1 кнопку, в ренпае создается сколько то там кб
(вроде 300кб точно не помню) системой, что не является плюсом на мобил
устройства.

Но у кнопок так же есть ряд плюсов, если сравнивать с другими видами граф
карт.

1)Простота
Что бы написать 10 кнопок разбросанных по всему экрану(не столбцами) у
многих займет ну максимум час(где пол часа – спор с командой как лучше
расположить кнопки для лучшего дизайна).
В imagemap(hotspot) что бы рассчитать угол координаты, размер кнопки для
1 кнопки, может занять ну минут 15, а представьте если их 10 шт… плюс
редактирования командой координат(опять дизайн наше все). и опять
переставлять и вычислять все это сколько времени уйдет.
И таким образом на imagemap(hotspot) у вас может уйти спокойно пол
дня(образно)

267
2018 Ren’Py

2)Любая форма
Вы можете сделать круглую кнопку, зигзагообразная и т.д. а в
imagemap(hotspot) вы можете сделать активной зоной только квадратный
участок.

ГРАФИЧЕСКАЯ КАРТА
IMAGEMAP(HOTSPOT)
Графическая карта отличается от кнопки тем, что само изображение
является одновременно фоном и кнопкой. Благодаря этому у
imagemap кнопки полностью сливаются с фоном. Не смотря на
минусы(время на расчет координат, квадратная зона выделения…)
это все компенсируется тем что кнопки сливаются с фоном(ибо
красиво, когда все гармонично и не чужеродно смотрится).
Как вообще выглядит граф карта? Имеет много общего с imagebutton,
в плане выделения. idle_ и hover_. Но имеются и расхождения.
imagemap:
hotspot (970, 140, 270, 85)
Разберем что это значит.
imagemap: - объявляем графическую карту в которой прописываем
координаты горячих кнопок
hotspot (970, 140, 270, 85) - горячая кнопка, которая при наведении на
эту область будет активировано действие/наведение.
Теперь разберем подробней как определять числа в скобках
Первые 2 числа это верхний левый угол горячей кнопки.(х и у)
Последние 2 числа это координаты области действия кнопки(х и у)
Пример как выглядит все это в фотошоппе

268
2018 Ren’Py

1 и 2 цифра

3 цифра. Стрелками показано, на сколько она уйдет в горизонт


плоскость(вправо)

269
2018 Ren’Py

4 цифра на сколько вертикально вниз она уйдет

И получим кнопку старт с такими координатами


screen main_menu:
tag menu
imagemap:
ground 'gui/imagemap_main_menu_unlocked_idle.png'
hover 'gui/imagemap_main_menu_unlocked_hover.png'
hotspot (970, 141, 270, 85) action Start()
Далее я распишу подробней как главное меню прописать

ПРИМЕР ПРОСТЕЙШЕЙ ГРАФ КАРТЫ НА ГЛАВНОЕ МЕНЮ.

Для работы вам потребуется вставить в папку gui 2 изображения


Имя файла imagemap_main_menu_unlocked_hover.png разрешение
1280 на 720 (в принципе, все кроме кнопок, можно сделать
прозрачным, т.к. при наведении поменяется только выделенная
область, но мне лень обрезать изображение, и поэтому поменял

270
2018 Ren’Py

только контрастность кнопкам и обводку в фотошоппе добавил)

И 2 - Имя файла imagemap_main_menu_unlocked_idle.png


разрешение 1280 на 720

Далее нам для данного главного меню, придется почти все уже
прописанные значения экранов удалить с 243 строки(после значения
screen choice(items):) по 1135(до значения screen confirm(message,
yes_action, no_action):)

271
2018 Ren’Py

Да, в нем нет истории, не прописаны варианты для телефона, и кучу


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

 Простое лучше, чем сложное.


 Если реализацию легко объяснить — идея, возможно,
хороша.

И пропишем полностью свое главное меню.


screen main_menu:
tag menu
imagemap:
ground 'gui/imagemap_main_menu_unlocked_idle.png'
hover 'gui/imagemap_main_menu_unlocked_hover.png'
hotspot (970, 141, 270, 85) action Start()
hotspot (970, 230, 270, 85) action ShowMenu('load')
hotspot (970, 320, 270, 85) action ShowMenu('preferences')
hotspot (970, 412, 270, 85) action Start('extras')
hotspot (970, 500, 270, 85) action Quit(confirm=False)

272
2018 Ren’Py

273
2018 Ren’Py

Разберем, что мы тут записали


screen main_menu: - прописанная системой метка главного меню
tag menu - Этот тег гарантирует, что любой другой экран с тем же
тегом будет заменять этот.(можно использовать еще и modal True но
опытные пользователи для меню всегда используют tag menu)
ground 'gui/imagemap_main_menu_unlocked_idle.png' – изображение
карты в покое, изображение полное
hover 'gui/imagemap_main_menu_unlocked_hover.png' –изображение
карты при наведении, можно использовать только изображение кнопок
при выделении, т.к. в картах вы еще 1 слой добавляете, как в
фотошоппе.
hotspot (970, 141, 270, 85) action Start() –горячая кнопка, все значения
действий аналогично кнопкам( action Jump, action Call….)

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


главное меню при наведении.
Все смотрится довольно скучно, почему бы не записать что бы
высвечивались комментарии при наведении? Да и прописать в нее
свои координаты.

ДОБАВЛЯЕМ КОММЕНТАРИИ НА КАРТЕ


Добавьте изображения в папку gui.
Имя файла tooltip_main_menu_start.png разрешение 532 на 58

Имя файла tooltip_main_menu_quit. Png разрешение 532 на 58

274
2018 Ren’Py

Имя файла tooltip_main_menu_load.png разрешение 532 на 58

Имя файла tooltip_main_menu_extra.png разрешение 532 на 58

Имя файла tooltip_main_menu_config.png разрешение 532 на 58

И теперь нам нужно в самом конце файла screen.rpy записать


следующее значение
screen gui_tooltip:
add my_picture xpos my_tt_xpos ypos my_tt_ypos

275
2018 Ren’Py

И теперь пропишем значения появления и снятия комментарий в


горячих кнопках.
screen main_menu:
tag menu
imagemap:
ground 'gui/imagemap_main_menu_unlocked_idle.jpg'
hover 'gui/imagemap_main_menu_unlocked_hover.jpg'
hotspot (970, 140, 270, 85) action Start() hovered [Show("gui_tooltip",
my_picture="gui/tooltip_main_menu_start.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (970, 230, 270, 85) action ShowMenu('load') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_main_menu_load.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

276
2018 Ren’Py

hotspot (970, 320, 270, 85) action ShowMenu('preferences') hovered


[Show("gui_tooltip", my_picture="gui/tooltip_main_menu_config.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (970, 412, 270, 85) action Start('extras') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_main_menu_extra.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (970, 500, 270, 85) action Quit(confirm=False) hovered
[Show("gui_tooltip", my_picture="gui/tooltip_main_menu_quit.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

Разберем что записали


hovered [Show("gui_tooltip",
my_picture="gui/tooltip_main_menu_start.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
Что значит, при наведении(hovered) вызывается экран
([Show("gui_tooltip",) в котором прописано
изображение(my_picture="gui/tooltip_main_menu_start.png",) и его
координаты появления(my_tt_xpos=46, my_tt_ypos=518) ])
И как только мы убираем курсор с горячей кнопкой(unhovered) мы
убираем вызванный экран ([Hide("gui_tooltip")])
Ранее была запись как добавить звук на горячую кнопку.

Действующие кнопки у нас являются только старт(action Start() ) и


выход(action Quit(confirm=False) ) и если мы нажмем на настройки или
загрузки, то высветится ошибка. Мы прописали действия к вызову
меню, но их не прописали, давайте запишем остальные разделы
главного меню.

277
2018 Ren’Py

ГРАФИЧЕСКАЯ КАРТА МЕНЮ НАСТРОЙКИ


Добавьте изображение в папку gui. Все картинки формата .png и
разрешение имеют 1280 на 720
imagemap_config_ground

278
2018 Ren’Py

imagemap_config_hover

imagemap_config_idle

279
2018 Ren’Py

imagemap_config_selected_hover

imagemap_config_selected_idle

280
2018 Ren’Py

Так же добавим комментарии при наведении. Все комментарии


формата .png и имеют разрешение 532 на 58

tooltip_config_all

tooltip_config_disable_transition

tooltip_config_enable_transition

tooltip_config_fullscreen

tooltip_config_go_skip

tooltip_config_seen

tooltip_config_skipping

281
2018 Ren’Py

tooltip_config_stop_skip

tooltip_config_windowed

Теперь нам потребуется создать экран настроек


screen preferences():
tag menu
imagemap:
ground 'gui/imagemap_config_ground.jpg'
idle 'gui/imagemap_config_idle.png'
hover 'gui/imagemap_config_hover.png'
selected_idle 'gui/imagemap_config_selected_idle.png'
selected_hover 'gui/imagemap_config_selected_hover.png'

hotspot (395, 252, 96, 96) action Preference('display', 'window')


hovered [Show("gui_tooltip",
my_picture="gui/tooltip_config_windowed.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (503, 252, 96, 96) action Preference('display', 'fullscreen')
hovered [Show("gui_tooltip",

282
2018 Ren’Py

my_picture="gui/tooltip_config_fullscreen.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (645, 252, 96, 96) action Preference('transitions', 'none')
hovered [Show("gui_tooltip",
my_picture="gui/tooltip_config_disable_transition.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (758, 252, 96, 96) action Preference('transitions', 'all') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_config_enable_transition.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

hotspot (-1, -1, -1, -1) action Preference('joystick')

hotspot (395, 452, 96, 96) action Preference('after choices', 'stop')


hovered [Show("gui_tooltip",
my_picture="gui/tooltip_config_stop_skip.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (503, 452, 96, 96) action Preference('after choices', 'skip')
hovered [Show("gui_tooltip", my_picture="gui/tooltip_config_go_skip.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (645, 452, 96, 96) action Preference('skip', 'seen') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_config_seen.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (758, 452, 96, 96) action Preference('skip', 'all') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_config_all.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

hotspot (522, 145, 200, 40) action Preference('begin skipping')


hovered [Show("gui_tooltip", my_picture="gui/tooltip_config_skipping.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

hotbar (73, 170, 243, 40) value Preference('music volume')


hotbar (73, 255, 243, 40) value Preference('sound volume')

283
2018 Ren’Py

hotbar (73, 339, 243, 40) value Preference('voice volume')


hotbar (73, 444, 243, 40) value Preference('text speed')
hotbar (73, 525, 243, 40) value Preference('auto-forward time')

hotspot (989, 125, 296, 68) action ShowMenu('save') hovered


[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_save.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (989, 206, 297, 68) action ShowMenu('load') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_load.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (989, 286, 295, 68) action ShowMenu('preferences') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_config.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (989, 364, 296, 68) action MainMenu() hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_main.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (989, 446, 295, 68) action Return() hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_return.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (989, 526, 297, 68) action Quit() hovered [Show("gui_tooltip",
my_picture="gui/tooltip_geme_menu_quit.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

284
2018 Ren’Py

ГРАФИЧЕСКАЯ КАРТА ЗАГРУЗКИ И


СОХРАНЕНИЯ
В папку gui добавьте следующие изображения, все рисунки формата png и
имеют разрешение 1280 на 720

285
2018 Ren’Py

imagemap_load_ground

imagemap_load_hover

286
2018 Ren’Py

imagemap_load_idle

imagemap_load_selected_hover

287
2018 Ren’Py

imagemap_load_selected_idle

imagemap_save_ground

288
2018 Ren’Py

imagemap_save_hover

imagemap_save_idle

289
2018 Ren’Py

imagemap_save_selected_hover

290
2018 Ren’Py

imagemap_save_selected_idle

Все комментарии формата .png и имеют разрешение 532 на 58


tooltip_geme_menu_config

tooltip_geme_menu_load

291
2018 Ren’Py

tooltip_geme_menu_main

tooltip_geme_menu_quit

tooltip_geme_menu_return

tooltip_geme_menu_save

screen save:
tag menu
imagemap:
ground 'gui/imagemap_save_ground.jpg'
idle 'gui/imagemap_save_idle.png'
hover 'gui/imagemap_save_hover.png'
selected_idle 'gui/imagemap_save_selected_idle.png'
selected_hover 'gui/imagemap_save_selected_hover.png'

hotspot (-1, -1, -1, -1) action FilePage('auto')


hotspot (58, 134, 157, 142) action FilePage(1)
hotspot (58, 289, 157, 142) action FilePage(2)
hotspot (58, 440, 157, 142) action FilePage(3)

hotspot (244, 134, 621, 142) action FileAction(0):


use load_save_slot(number=0)

292
2018 Ren’Py

hotspot (244, 289, 621, 142) action FileAction(1):


use load_save_slot(number=1)
hotspot (244, 440, 621, 142) action FileAction(2):
use load_save_slot(number=2)

hotspot (987, 122, 292, 70) action ShowMenu('save') hovered


[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_save.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 202, 292, 70) action ShowMenu('load') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_load.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 283, 292, 70) action ShowMenu('preferences') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_config.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 370, 292, 70) action MainMenu() hovered [Show("gui_tooltip",
my_picture="gui/tooltip_geme_menu_main.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 442, 292, 70) action Return() hovered [Show("gui_tooltip",
my_picture="gui/tooltip_geme_menu_return.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 525, 292, 70) action Quit() hovered [Show("gui_tooltip",
my_picture="gui/tooltip_geme_menu_quit.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

293
2018 Ren’Py

И экран загрузки
screen load:

tag menu

imagemap:
ground 'gui/imagemap_load_ground.jpg'
idle 'gui/imagemap_load_idle.png'
hover 'gui/imagemap_load_hover.png'
selected_idle 'gui/imagemap_load_selected_idle.png'
selected_hover 'gui/imagemap_load_selected_hover.png'

hotspot (-1, -1, -1, -1) action FilePage('auto')


hotspot (58, 134, 157, 142) action FilePage(1)
hotspot (58, 289, 157, 142) action FilePage(2)
hotspot (58, 440, 157, 142) action FilePage(3)

hotspot (244, 134, 621, 142) action FileAction(0):


use load_save_slot(number=0)
hotspot (244, 289, 621, 142) action FileAction(1):
use load_save_slot(number=1)
hotspot (244, 440, 621, 142) action FileAction(2):
use load_save_slot(number=2)

hotspot (987, 122, 292, 70) action ShowMenu('save') hovered


[ Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_save.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 202, 292, 70) action ShowMenu('load') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_load.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 283, 292, 70) action ShowMenu('preferences') hovered
[Show("gui_tooltip", my_picture="gui/tooltip_geme_menu_config.png",
my_tt_xpos=46, my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 370, 292, 70) action MainMenu() hovered [Show("gui_tooltip",
my_picture="gui/tooltip_geme_menu_main.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]
hotspot (987, 442, 292, 70) action Return() hovered [Show("gui_tooltip",
my_picture="gui/tooltip_geme_menu_return.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

294
2018 Ren’Py

hotspot (987, 525, 292, 70) action Quit() hovered [Show("gui_tooltip",


my_picture="gui/tooltip_geme_menu_quit.png", my_tt_xpos=46,
my_tt_ypos=518) ] unhovered [Hide("gui_tooltip")]

Самые главные и основные разделы главного меню записали. Остался экран


экстра. Но мы его рассмотрим позже.

ОБЬЕКТЫ-ПОЛОСКИ (BAR )
Обьекты bar – гибкие полоски , которые отображают любое значение в
виде полосок.

БАР С ТОЧНЫМ ЗНАЧЕНИЕМ


Например, вам известно какое будет точное значение (66 например) и
что бы его отобразить нужно, прописать следующее
screen bar_example():
frame:
xalign 0.5 ypos 50
xsize 500
bar:

295
2018 Ren’Py

value StaticValue(66, 100)


label start:
call screen bar_example

Значение xsize - длина бара(экрана) если он, или xminimum и


xmaximum не будут записаны, то бар будет во весь экран.
Обьект bar - горизонтальная полоска
Обьект vbar - вертикальная полоска
value – значение

296
2018 Ren’Py

СУЩЕСТВУЮТ 3 ВИДА СТАНДАРТНЫХ В


GUI ПРОПИСАННЫХ ГОРИЗОНТАЛЬНЫХ
СТИЛЕЙ БАРОВ.
screen bars_example():
default n = 66

frame:
xalign 0.5 ypos 50
xsize 500

vbox:
spacing 10

bar value AnimatedValue(n, 100, 0.5) style "bar" # 1 стиль


bar value ScreenVariableValue("n", 100) style "slider" # 2 стиль
bar value ScreenVariableValue("n", 100) style "scrollbar" # 3 стиль

label start:
call screen bars_example

1 стиль - style "bar"


Его используют для отображения значений, которые пользователь
самостоятельно не может изменить.
2 стиль - style "slider"

297
2018 Ren’Py

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


может самостоятельно изменить
3 стиль - style "scrollbar"
Его используют для перемещения по экрану и прокрутки

ТАК ЖЕ ЕСТЬ 3 СТАНДАРТНЫХ


ВЕРТИКАЛЬНЫХ СТИЛЕЙ БАРОВ
screen vbars_example():
default n = 66

frame:
xalign 0.5 ypos 50
ysize 300

hbox:
spacing 10

vbar value AnimatedValue(n, 100, 0.5)


vbar value ScreenVariableValue("n", 100) style "vslider"
vbar value ScreenVariableValue("n", 100) style "vscrollbar"
label start:
call screen vbars_example

1 стиль - style "vbar"

298
2018 Ren’Py

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


самостоятельно не может изменить.
2 стиль - style "vslider"
Его используют для отображения значений, которые пользователь
может самостоятельно изменить
3 стиль - style "vscrollbar"
Его используют для перемещения по экрану и прокрутки

А ТАК ЖЕ СУЩЕСТВУЕТ БАР ДЛЯ ГОРЯЧИХ


ТОЧЕК,
hotbar (73, 170, 243, 40) value Preference('music volume')

НАСТРОЙКИ БАРОВ ПРОПИСАНЫХ


Настройки данных экранов находятся тут в gui.rpy

299
2018 Ren’Py

а изображения так же в screen.rpy

300
2018 Ren’Py

КАК ДОБАВИТЬ СВОЙ БАР В ПРОЕКТ?


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

screen simple_stats_screen: ###бары жизни

301
2018 Ren’Py

frame: ###шкала жизни красной шапки


xalign 0.01 yalign 0.05 ###координаты ее
xminimum 220 xmaximum 220 ### ограничиваем ее размеры
vbox:
style_group "imya_bara"###прописываем стиль
text "Красная шапочка" size 22 xalign 0.5
null height 5
hbox:
bar:
xmaximum 130
value red_hood_hp
range red_hood_max_hp
null width 5
label start:
call screen simple_stats_screen

style_group "imya_bara" – вызвали нужный стиль, а так же вместо него


можно использовать style_prefix "imya_bara"

КАК ПРОПИСАТЬ СТАРУЮ ВЕРСИЮ БАРА В


НОВОМ GUI
Вы можете самостоятельно создать свой стиль бара без использования изображений, как
на старых версиях, для этого нам нужно записать в нем код с нужными значениями.
Вам необходимо очистить в screen.rpy те строки, что отвечают за значение
изображение бара (предыдущая картинка, где выделены стили бара)

302
2018 Ren’Py

И потом в стиле прописать свой бар и в коде вызывать только его


стилем
Взял старую тему.

Прописал где то в любом файле rpy(иначе новое гуи не сможет


понять, что от него хотят, и вместо шкалы будет пустота)
init -1 python hide:

theme.tv(
## Theme: TV
## Color scheme: First Valentines

## The color of an idle widget face.


widget = "#F09898",

## The color of a focused widget face.


widget_hover = "#D6C5BB",

## The color of the text in a widget.


widget_text = "#593131",

## The color of the text in a selected widget. (For


## example, the current value of a preference.)
widget_selected = "#B31E1E",

## The color of a disabled widget face.

303
2018 Ren’Py

disabled = "#F8F2D0",

## The color of disabled widget text.


disabled_text = "#BFA1A1",

## The color of informational labels.


label = "#5D1010",

## The color of a frame containing widgets.


frame = "#F8F2D0",

## The background of the main menu. This can be a color


## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
mm_root = "#D98989",

## The background of the game menu. This can be a color


## beginning with '#', or an image filename. The latter
## should take up the full height and width of the screen.
gm_root = "#D98989",

## If this is True, the in-game window is rounded. If False,


## the in-game window is square.
rounded_window = False,

## And we're done with the theme. The theme will customize
304
2018 Ren’Py

## various styles, so if we want to change them, we should


## do so below.
)

И прописываю сам стиль настроек(стиль назвал pref , тут вы можете


любое название задать)
init -2 python:
style.pref_frame.xfill = True
style.pref_frame.xmargin = 5
style.pref_frame.top_margin = 5

style.pref_vbox.xfill = True

style.pref_button.size_group = "pref"
style.pref_button.xalign = 1.0

style.pref_slider.xmaximum = 192
style.pref_slider.xalign = 1.0

style.soundtest_button.xalign = 1.0

Что бы выбрать определенный бар в нужный момент игры, вы


задаете в экране стиль проекта(выделенная область)
screen simple_stats_screen: ###бары жизни
frame: ###шкала жизни красной шапки
xalign 0.01 yalign 0.05 ###координаты ее

305
2018 Ren’Py

xminimum 220 xmaximum 220 ### ограничиваем ее размеры


vbox:
style_group "pref"###прописываем стиль
text "Красная шапочка" size 22 xalign 0.5
null height 5
hbox:
bar:
xmaximum 130
value red_hood_hp
range red_hood_max_hp
null width 5

style_group "pref" – вызвали нужный стиль, а так же вместо него можно


использовать style_prefix "pref"

ГДЕ ВЗЯТЬ КОДЫ СТАРЫХ БАРОВ?


В лаунчере нажимаете создать новый проект, выбираете старую
версию и выбираете понравившуюся версию стиля. И копируете
настройки стиля(где подобного плана записи style.pref_frame.xfill =
True и т.д.)

ДЕЙСТВИЯ БАРА
пример про что я имею в виду
bar:
at transform_ese_left
xmaximum 130
value red_hood_hp

306
2018 Ren’Py

range red_hood_max_hp

1) value - Текущее значение бара. Это может быть либо объект


значения бара, либо число.
2) range - Максимальное значение бара. Это необходимо, если
значение является числом.
3) adjustment - Пользовательский интерфейс.регулировка (объекта)
ui.adjustment , что это настраивается.
4) changed - Если учесть, это должна быть функция в Python. Функция
вызывается со значением корректировки при изменении
корректировки.
5) hovered –действия при наведении
6) unhovered – действие при снятии

ПОДРОБНЫЙ РАЗБОР ЗНАЧЕНИЙ БАРОВ.

AnimatedValue(value=0.0, range=1.0, delay=1.0, old_value=None) Это анимирует значение,


принимая задержки секунд, чтобы изменить значение от old_value к значению.
value - Само значение числа.
range - Диапазон значений, число.
delay - Время анимации в секундах. По умолчанию 1.0.
old_value - Старое значение. Если этого нет, то значение берется из AnimatedValue мы
заменили, если таковые имеются. В противном случае инициализируется значение.

AudioPositionValue(channel=u'music', update_interval=0.1) Значение, показывающее


положение воспроизведения аудиофайла, воспроизводимого в канале.
update_interval - Как часто значение обновляется, в секундах.

DictValue(dict, key, range, max_is_zero=False, style=u'bar', offset=0, step=None) Значение,


которое позволяет пользователю изменить значение ключа в словаре.

FieldValue(object, field, range, max_is_zero=False, style=u'bar', offset=0, step=None)


Значение бара, позволяющее пользователю настраивать значение поля для объекта.

MixerValue(mixer) Значение аудиомикшера.

ScreenVariableValue(variable, range, max_is_zero=False, style=u'bar', offset=0, step=None)


Значение бара, которое регулирует значение переменной на экране
variable - Строка, задающая имя переменной для настройки.

307
2018 Ren’Py

range - Диапазон регулировки


max_is_zero -Если True, то, когда поле равно нулю, значение бара будет range, и все
остальные значения будут смещены вниз на 1. Это работает обеими способами - когда
полоса установлена на максимум, поле установлено на 0.
step - Сумма, на которую нужно изменить планку. Если нет, по умолчанию 1/10th из бара.

StaticValue(value=0.0, range=1.0) - Это позволяет задавать значение статически.

VariableValue(variable, range, max_is_zero=False, style=u'bar', offset=0, step=None)


Значение бара, позволяющее пользователю изменять значение переменной в хранилище
по умолчанию.
variable - Строка, задающая имя переменной для настройки.

XScrollValue(viewport) Значение регулировки, которая горизонтально (x значение)


прокручивает область просмотрана текущем экране. Без обьявления в viewport не
заработает

YScrollValue(viewport) Значение регулировки, которая вертикально (у значение)


прокручивает область просмотрана текущем экране. Без обьявления в viewport не
заработает

НАСТРОЙКИ СТИЛЯ БАРА


Бары рисуются с желоба слева и справа(горизонтальное) и сверху
вниз(вертикальное), при нажатии на которую пользователь может
перейти. Оставшееся пространство-это часть бара, которая может
измениться, при этом сумма с каждой стороны пропорциональна
значению бара в виде доли диапазона.
Пример как будет выглядеть в стиле настройка бара(с именем
timebar)с теми настройками стиля
init -5 python:
style.timebar = Style(style.default)
style.timebar.left_bar = Frame("ui/interface/timerfull.png", 0, 0)
style.timebar.right_bar = Frame("ui/interface/timerempty.png", 0, 0)
style.timebar.xmaximum = 695
style.timebar.ymaximum = 27
И подробный разбор всего, что можно в нем приделать. Оно будет
иметь такой вид
style.imya_bara.imena_punktov =...

308
2018 Ren’Py

СПИСОК ИМЕН ПУНКТОВ СТИЛЕЙ(И


ДРУГИЕ ЗНАЧЕНИЕ СТИЛЕЙ ПОДОЙДУТ, НО
ЭТИ ЧИСТО БАРОВ НАСТРОЙКИ)

1) style.imya.bar_vertical = True

Если значение True, то панель имеет вертикальную ориентацию. Если False, он имеет
горизонтальную ориентацию.

2) style.imya.bar_invert = True

Если True, значение бар представлена в правой/верхней стороне панели, а не


слева/снизу.

3) ) style.imya.bar_resizing = True

Если True, то размеры сторон бруска. Если False, мы представляем стороны бара в
полном размере, а затем обрезать их.

4) style.imya.left_gutter = число

Размер желоба на левой стороне бара, в пикселях.

5) style.imya.right_gutter = число

Размер желоба на правой стороне бара, в пикселях.

6) style.imya.top_gutter = число

Размер желоба на верхней стороне бара, в пикселях

7) style.imya.bottom_gutter = число

Размер желоба на нижней стороне бара, в пикселях.

8) style.imya.left_bar = Frame("путь к изображению", 0, 0)

Изображение, используемая для левой стороны бара.

9) style.imya.right_bar= Frame("путь к изображению", 0, 0)

Изображение, используемая для правой стороны бара.

10) style.imya.top_bar = Frame("путь к изображению", 0, 0)

Изображение, используемая для верхней стороны бара.

309
2018 Ren’Py

11) style.imya.bottom_bar = Frame("путь к изображению", 0, 0)

Изображение, используемая для нижней стороны бара.

12) style.imya.base_bar = Frame("путь к изображению", 0, 0)

Один дисплей, используемый для left_bar/right_bar или top_bar/bottom_bar, в зависимости


от ситуации. (Это можно использовать с большим пальцем для создания ползунка или
полосы прокрутки.)

13) style.imya.thumb = Frame("путь к изображению", 0, 0)

thumb - это бегунок в центре панели, нажав, на которую пользователь может перетащить.

Если нет ни у кого, это визуализуемым, поверх разрыва между сторонами в баре

14) style.imya.thumb_shadow = Frame("путь к изображению", 0, 0)

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

15) style.imya.thumb_offset= число

Количество, на которое большой палец(thumb) перекрывает бары, в пикселях. Для того,


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

16) style.imya.mouse = строка(примеров не находил, если кто знает вышлите пример


пож)

Стиль мыши, используемый при фокусировке кнопки. Это должен быть один из стилей из
config.mouse

17) style.imya.unscrollable = None

style.imya.unscrollable = "insensitive"

style.imya.unscrollable = "hide"

None - Нормально отображает бар.

"insensitive" - Отображает панель в нечувствительном состоянии. Это позволяет панели


изменить свой стиль, чтобы отразить его отсутствие полезности.

"hide" - Предотвращает отображение панели вообще. Пространство будет выделено для


бара, но ничего не будет нарисовано в этом пространстве.

18) style.imya.keyboard_focus = True

Если True, то по умолчанию, эта кнопка может быть сфокусирована с помощью


механизма фокуса клавиатуры, если она может быть сфокусирована вообще. Если
значение равно False, механизм фокусировки клавиатуры пропустит эту кнопку.
(Механизм фокусировки клавиатуры используется клавиатурами и устройствами,
похожими на клавиатуру, такими как джойпады.)

310
2018 Ren’Py

КАК ПРОПИСАТЬ ЗНАЧЕНИЕ БАРА ЧЕРЕЗ


ПЕРЕМЕННУЮ
Прописываем бар в экране

screen simple_stats_screen: ###экран бара


frame: ###рамка
xalign 0.01 yalign 0.05 ###координаты ее
xminimum 220 xmaximum 220 ### ограничиваем ее размер
vbox:
text "Красная шапочка" size 22 xalign 0.5
null height 5
hbox:
bar: ###бар в котором прописыв значение
xmaximum 130 ###длина бара
value red_hood_hp ###значени переменной
red_hood_hp
range red_hood_max_hp ###диапазон переменной
red_hood_max_hp
null width 5 ###ширина строки

text "[red_hood_hp] / [red_hood_max_hp]" size 16


###отображаем ее жизнь при ранении и полную

После того как мы прописали экран бара нам необходимо прописать


переменные и вызвать экран бара
label start:

311
2018 Ren’Py

$ red_hood_max_hp = 50 ###Значение чему равно


$ red_hood_hp = red_hood_max_hp ### значение 1 переменной
= другой
show screen simple_stats_screen###вызываем экран бара
"полная шкала"
$ red_hood_hp -=5###отнимаем от переменной -5
"шкала упала"
И получили вот

В экранах мы не можем изменять значения переменной, поэтому


нам необходимо прописать саму переменную в метку (label) и в метках
записать изменение значения переменной $ red_hood_hp -=5

ДЕЛАЕМ КРУГЛЫЙ БАР

https://lemmasoft.renai.us/forums/viewtopic.php?f=8&t=27159&p=328819#p328841

DEFAULT
312
2018 Ren’Py

Задает значение переменной по умолчанию.


screen scheduler():
default club = None
vbox:
text "Куда ты пойдешь?"
textbutton "Художка" action SetScreenVariable("club", "art")
textbutton "Спорт зал" action SetScreenVariable("club", "writing")

if club:
textbutton "Выбрать" action Return(club)

VIEWPORT
Порт просмотра – применяют, когда нам нужно показать что то, что
больше экрана.
Вот простой пример такого порта

screen viewport_screen():
313
2018 Ren’Py

viewport:
xalign 0.5 ypos 50 xysize (700, 300)
draggable True
mousewheel True
arrowkeys True
add "bg band"
Рассмотрим что тут записано
screen viewport_screen(): -имя экрана в котором мы пишем
xalign 0.5 ypos 50 – место положение на экране
xysize (700, 300) – ограничиваем размер отбражаемого окна, иначе на
весь экран получим картинку
draggable True – нажав на экран порта просмотра, мы переносимся по
экрану
mousewheel True – вертикальная прокрутка мыши
arrowkeys True - прокручивать порт просмотра с помощью клавиш со
стрелками и контроллера d-pad.
add "bg band" – изображение которое будем просматривать

Рассмотрим еще значения порта


screen edgescroll_viewport_screen():

viewport:
xalign 0.5 ypos 50 xysize (700, 300)

edgescroll (150, 500)


mousewheel True
arrowkeys True

314
2018 Ren’Py

add "bg band"

edgescroll (150, 500) – Экран автоматически начинает двигать


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

315
2018 Ren’Py

1)ВЕРТИКАЛЬНЫЕ И ГОРИЗОНТАЛЬНЫЕ ПОЛОСЫ


(SCROLLBARS "BOTH")

screen scrollbar_viewport_screen():
viewport:
xalign 0.5 ypos 50 xysize (700, 300)
scrollbars "both"
spacing 5 ###расстояние от порта до края изображен
draggable True
mousewheel True
arrowkeys True

add "bg band"

2) ГОРИЗОНТАЛЬНЫЕ ПОЛОСЫ
(SCROLLBARS "HORIZONTAL")

316
2018 Ren’Py

screen child_size_viewport_screen():
viewport:
xalign 0.5 ypos 50 xysize (700, 300)
child_size (1000, None)
scrollbars "horizontal"
spacing 5
draggable True
mousewheel True
arrowkeys True
add "#000c"
text _("Этот текст больше размера экрана") size 40

Если не дописать child_size (1000, None) то текст будет


распологаться на экране порта, а так мы даем ему расстояние до куда
можно крутить. None – параметр берет размер порта

317
2018 Ren’Py

3) ВЕРТИКАЛЬНАЯ ПОЛОСА( SCROLLBARS "VERTICAL")

screen scrollbar_viewport_screen():
viewport:
xalign 0.5 ypos 50 xysize (700, 300)
scrollbars "vertical"
spacing 5 ###расстояние от порта до края изображен

draggable True
mousewheel True
arrowkeys True

add "bg band"

КАК УСТАНОВИТЬ НАЧАЛЬНУЮ ЗОНУ ПРОСМОТРА.


(XINITIAL И YINITIAL)

screen foritial_viewport_screen():
viewport:
xalign 0.5 ypos 50 xysize (700, 300)
xinitial 0.5
yinitial 1.0
scrollbars "both"
spacing 5
draggable True

318
2018 Ren’Py

mousewheel True
arrowkeys True
add "bg band"

КАК КЛОНИРОВАТЬ ОБЬЕКТЫ В ПОРТЕ

screen vpgrid_screen():
vpgrid:
cols 6
rows 4
xalign 0.5 ypos 50 xysize (700, 300)
child_size (1000, None)
scrollbars "both"
side_spacing 5
draggable True
mousewheel True
arrowkeys True

319
2018 Ren’Py

for i in range(6 * 4):


add "logo base"

Краткий разбор
vpgrid: - обьединить таблицу и порт просмотра
cols 6 – колонок (горизон)
rows 4 – строки (вертикал)
side_spacing 5 – отступ между изображениями
for i in range(6 * 4): - таблица будет из 24 изображений

ПРИМЕР СКРОЛА С ОГРОМНЫМ ЧИСЛОМ


ТЕКСТА
init python:
txt_string = "Много текста.\nВторой абзац Второй абзац Второй абзац Второй абзац
Второй абзац Второй абзац Второй абзац Второй абзац Второй абзац Второй абзац
Второй абзац Второй абзац Второй абзац Второй абзац Второй абзац Второй абзац\
nКрутите колесо мышки; перетаскивайте, цепляясь прямо за текст; пользуйтесь бегунком
справа.\n4-й абзац\n5-й\n6...\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\
n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\
n43\n44\n45\n46\n47\n48\n49\n50"
txt = txt_string.split("\n") # рубим на абзацы
screen scr_txt:
modal True
frame:
background "#2008"
xfill True
yfill True
left_margin 16
right_margin 16
top_margin 16
bottom_margin 16
vbox:
xfill True
yfill True
frame:
background "#0028"
xfill True
hbox:
xfill True
text "INFO" yalign .5
textbutton _("x") xalign 1.0 action Return()

320
2018 Ren’Py

hbox:
xfill True
viewport id "box":
xmaximum 0.95
mousewheel True
draggable True
vbox:
spacing 8 # отступы между абзацами
for i in txt:
text " " + i # пробелы для красной строки
vbar yfill True value YScrollValue("box") xalign 1.0

label start:
"Сейчас появится окно с текстом."
call screen scr_txt
return

DRAG AND DROP


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

ЭКРАН ЗАГРУЗКИ

321
2018 Ren’Py

load_base.png 935х922

load_hover.png 935х922

322
2018 Ren’Py

savebutton_base.png 253х152

323
2018 Ren’Py

savebutton_hover.png 253х152

savedelete_base.png

savedelete_hover.png

savedelete_inactive.png

screen load():
zorder 200
drag:

324
2018 Ren’Py

drag_name "drag_load"
drag_raise True
drag_handle (0,0,1.0,1.0)
xalign 0.5 yalign 0.5
drag_offscreen True
has imagemap:
ground "UI/load_base.png"
hover "UI/load_hover.png"
hotspot (32, 100, 170, 63):
action FilePage(1)
hover_sound "Sounds/hover1.ogg"
activate_sound "Sounds/button1.ogg"
hotspot (202, 100, 170, 63):
action FilePage("auto")
hover_sound "Sounds/hover1.ogg"
activate_sound "Sounds/button1.ogg"
hotspot (373, 100, 170, 63):
action FilePage("quick")
hover_sound "Sounds/hover1.ogg"
activate_sound "Sounds/button1.ogg"
hotspot (553, 100, 330, 64):
action (Hide("load"),SetVariable("show_load",False))
hover_sound "Sounds/hover1.ogg"
activate_sound "Sounds/button1.ogg"
style "file_picker_frame"
$ columns = 3
325
2018 Ren’Py

$ rows = 50
hbox:
area (40, 190, 855, 675)
viewport:
draggable True
mousewheel True
scrollbars "vertical"
child_size (863,5000)
has grid columns rows:
transpose False
xfill True
style_group "file_picker"
xpos 40
ypos 190
for i in range(1, rows * columns + 1):
frame:
xmaximum 265
ymaximum 165
background None
button:
background None
focus_mask None
has vbox
$ description = "% 2s. %s\n%s" % (
FileSlotName(i, rows*columns),
FileTime(i, empty=_("Empty Slot.")),
326
2018 Ren’Py

FileSaveName(i))
text description ysize 10 color "#000000" font
"Fonts/SourceCodePro-Regular.ttf" size 13
add FileScreenshot(i) size (227,127) ypos -15
imagebutton:
idle "UI/savebutton_base.png"
hover "UI/savebutton_hover.png"
hover_sound "Sounds/hover1.ogg"
activate_sound "Sounds/button1.ogg"
focus_mask None
action FileAction(i)

imagebutton:
idle "UI/savedelete_base.png"
hover "UI/savedelete_hover.png"
insensitive "UI/savedelete_inactive.png"
activate_sound "Sounds/cancel.ogg"
xpos 184
action FileDelete(i)

init -2:
style file_picker_frame is menu_frame
style file_picker_nav_button is small_button
style file_picker_nav_button_text is small_button_text
style file_picker_button is large_button
style file_picker_text is large_button_text

327
2018 Ren’Py

И получим такого плана экран загрузки, мы его можем передвигать


по экрану, расположить там, где нам будет удобно. И удобное
расположение кнопок удаления, НО у данной функции есть огромный
минус – может быть у меня так, или у кого то еще, но когда вызывешь
несколько такого плана экранов-drag и оставить включенный проект
минут на 10 то включается ошибка, мол, ресурсов ему не хватает.
Может быть со временем данный недостаток и исправили, но я не
часто стал применять данную функцию, или в больших количествах,
дабы избежать критик насчет глючной работы приложения, можно
просто обговорить с бета-тестерами варианты удобного расположения
на экране того или иного экрана.

ПОДРОБНЫЙ РАЗБОР ЗНАЧЕНИЙ DRAG


drag_name – Имя перемещаемого обьекта, если есть такой же
обьект с таким же именем, то все они будут перемещены.
draggable – если True, будет перемещаться за мышкой
droppable - если True, другие Перетаскивания могут быть пропущены
на это Перетаскивание.
drag_raise - если True, во время перетаскивания будет поверх
других drag
dragged – обьект, на событие ссылается

328
2018 Ren’Py

dropped - Обратный вызов (или список обратных вызовов), который


называют, когда это Перетаскивание пропущено на. Это называют с
двумя параметрами. Первым является Перетаскивание, пропускаемое
на. Вторым является список Перетаскиваний, которые
перетаскиваются. Если обратный вызов возвращает значение ни
кроме Одного, то значение возвращено как результат взаимодействия.
clicked – включать перенес по щелчку

drag_handle -(x, y, ширина, высота) кортеж, давая позицию


перетаскивания обрабатывают в ребенке. В этом кортеже целые
числа считаются литеральным числом пикселей, в то время как
изменения относительно размера ребенка.

drag_joined - Это называют с текущим Перетаскиванием как


параметр. Это, как ожидают, возвратится, список [(перетащите, x, y)]
кортежи, давая draggables для перетаскивания как модуль. x и y
является смещениями перетаскиваний друг относительно друга, они
не относительно угла этого перетаскивания.

drag_offscreen - Если это правда, это перемещаемое может быть


перемещено вне экрана.

snap(x, y, delay=0)- Меняет положение перетаскивания. Если


перетаскивание не показывает, то изменение позиции мгновенно.
Иначе изменение позиции занимает секунды задержки и анимировано
как линейное перемещение.

КАК ПЕРЕНЕСТИ ИЗОБРАЖЕНИЕ В ОБЛАСТЬ


ГДЕ ДОЛЖНО ПРОИЗОЙТИ СОБЫТИЕ

Вот простой пример из офф документации


init python:

def detective_dragged(drags, drop):

329
2018 Ren’Py

if not drop:
return

store.detective = drags[0].drag_name
store.city = drop.drag_name

return True

screen send_detective_screen:
# A map as background.
add "europe.jpg"
# A drag group ensures that the detectives and the cities can be
# dragged to each other.
draggroup:

# Our detectives.
drag:
drag_name "Иван"
child "ivy.png"
droppable False
dragged detective_dragged
xpos 100 ypos 100
drag:
drag_name "Вася"
child "zack.png"
droppable False
330
2018 Ren’Py

dragged detective_dragged
xpos 150 ypos 100

# The cities they can go to.


drag:
drag_name "Краснодар"
child "london.png"
draggable False
xpos 450 ypos 140
drag:
drag_name "Волгоград"
draggable False
child "paris.png"
xpos 500 ypos 280

# Определение персонажей игры.


define e = Character('Эйлин', color="#c8ffc8")
label start:
"Выберите кто куда поедет"

call screen send_detective_screen

"Хорошо, [detective] едет в [city]."

ПРОСТОЙ СПОСОБ СМЕНЫ СУТОК

331
2018 Ren’Py

(http://renpyfordummies.blogspot.ru/2015/02/blog-post.html)
init:
image man = "man.png"
image bg = "bg.jpg"
$ dt = "утро"
screen daytime:
if dt == "утро":
add "#8404"
if dt == "вечер":
add "#0484"
if dt == "ночь":
add "#000b"
label start:
show screen daytime
scene bg
show man
"Сейчас – [dt]."
$ dt = "день"

332
2018 Ren’Py

"Сейчас – [dt]."
$ dt = "вечер"
"Сейчас – [dt]."
$ dt = "ночь"
"Сейчас – [dt]."
return

ПРОСТЕЙШИЙ КАЛЕНДАРЬ
Давайте создадим самый простой календарь.
Для этого давайте создадим сценарий knopki.rpy где пропишем
следующее
(не забывайте про отступы)
screen kalendar: ###наш календарь и в нем прописываем все, без
отступов
add "service/calendar.png": ###картинка календаря с путем к ней
zoom 1.5
align (.26,.025) ### Ее координата
text "[day]": ### текст переменной day которая будет меняться в
течении все игры
color "#000000" ### цвет кнопки
if day < 10: ###условие при меньше 10 day
align (.27,.07)### Ее координата
else:###не прошла проверку, там больше 10 day
align (.265,.07) ### Ее координата

Картинка вот

333
2018 Ren’Py

Если вы сделали все правильно, то у вас в игре появился


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

ПРОПИСЫВАЕМ ОТОБРАЖЕНИЕ ДЕНЕГ

Так же можно и деньги прописать (отступы не забывайте)

screen cash:
add "service/money.png":

334
2018 Ren’Py

align (.08,.05)
text ": [money]":
align (.17,.07)

картинка монет а в игре дописываем

label start:
$ day = 1
$ money = 1
show screen kalendar
show screen cash

$ udacha = 0 и т.д.
А что бы их убрать (Например, вы создали мини карту и инвентарь, и
заходите В главную карту локации, естественно вам уже не нужно что
бы отображалась ссылка на мини карту) пишем:
hide screen calendar (Все так же как и вызывать, только вместо show
пишем hide )

ЧАСЫ ЭЛЕКТРОННЫЕ И ЦИФРОВЫЕ

https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=21978

ВЫЗОВ CALL ИЗ ЭКРАНА SCREEN

Чтобы не порушить всю адресацию и прочие неважные нам детальки, в


Renpy нельзя из экрана делать call (переход на метку с последующим
возвратом). Можно перейти на метку в новом контексте, но тогда Renpy
спрячет все экраны screen. Это пример того, как можно организовать call по
кнопке и отобразить спрятанные экраны, словно их и не прятали. Но кнопку,

335
2018 Ren’Py

по которой мы прыгнули на метку, лучше спрятать. Или заменить кнопкой


возвращения назад
(http://renpyfordummies.blogspot.ru/2016/03/call-screen.html)
# чтобы вызвать локацию кнопкой на экране screen,
# нужно вызывать в ее в новом контексте.
# то есть открывается как бы другая игра.
# и прячутся все прежние экраны.

# вот только при сохранении игры, запоминается только место,


# откуда был вызван первый call, словно все return уже сработали
# поэтому возможность сохранения лучше отключить
# итого: способ работает только для всяких менюшек,
# но не для ветвления сюжета
init python:
# стек для хранения состояния экранов до вызова call
screens = []
# действие по кнопке ESC
gamemenu = config.game_menu_action
# добавить очередной список экранов
def s_push(item):
global screens
screens.append(item)
# извлечь последний список экранов
def s_pop():
global screens
if len(screens) > 0:
return screens.pop()
return []
# стартовое количество денег для тестирования
money = 10
# флаг вызова локации в новом контексте
is_call = False
# из экрана нельзя выполнить обычный call label
# создадим его аналог
class MyCall(Action):
def __init__(self, label, *args, **kwargs):
self.label = label
self.args = args
self.kwargs = kwargs
def __call__(self):
global screens, is_call
# отключаем ESC
config.game_menu_action = NullAction()
# запоминаем экраны
s_push(renpy.current_screen().screen_name)
# включаем флаг вызова нового контекста (чтобы спрятать кнопку)

336
2018 Ren’Py

is_call = True
# вызываем локацию в новом контексте
renpy.call_in_new_context(self.label, *self.args, **self.kwargs)
# функция для восстановления экранов в новом контексте
def show_screens():
for i in screens[-1:]:
renpy.show_screen(i)
# функция для возвращениея из локации в новом контексте
def myreturn():
global is_call
# спрятать экраны
for i in s_pop():
renpy.hide_screen(i)
# снять флаг новой локации, чтобы кнопка ее вызова снова появилась
is_call = len(screens) > 0
if not is_call:
config.game_menu_action = gamemenu
# сохранение данных игры
renpy.retain_after_load()
Return()()
# чтобы можно было привязать к копке, например
MyReturn = renpy.curry(myreturn)

# экран из которого можно выполнить call


screen test:
text _(str(money) + " денег") align(.05, .05)
# кнопку показываем лишь, если не выполнен call по ее нажатию
if not is_call:
# кнопка, которая выполняет аналог call label
textbutton _("Чит") align(.95, .05) action MyCall("menu1")
else:
# вызов call из метки, которая уже вызвана с помощью call
textbutton _("Хинт") align(.95, .05) action MyCall("hnt")

label start:
show expression "images/bg.jpg"
show screen test
"Вы создали новую игру Ren'Py."
"Добавьте сюжет, изображения и музыку и отправьте её в мир!"
return

# другая локация, из которой можно вернуться в то же место игры


# при желании можно передавать параметры при вызове
# тогда, вызывать например так можно: ... action MyCall("menu1", plus=100)
label menu1(plus=10):
# отобразить все экраны, спрятанные при вызове локации в новом контексте
$ show_screens()

337
2018 Ren’Py

# собственно какие-то действия


$ loop1 = True
# зацикливаем до нажатия 3-й кнопки
while loop1:
menu:
"+[plus]":
$ money += plus
"-[plus]":
$ money -= plus
"Вернуться":
$ loop1 = False
# возвращаемся туда, откуда пришли, восстанавливая прежнее положение дел
# вместо return
$ MyReturn()()
return

label hnt:
scene black
centered "Подсказка: это вложенный вызов call из другого call."
$ MyReturn()()
return

ИНФОРМАЦИОННЫЙ ЭКРАН, ПОПОЛНЯЕМЫЙ


init python:
# при первом запуске игры создается пустой список "открытий"
if persistent.pages is None:
persistent.pages = []
# номер текущей страницы
page = 0
# экран для отображения открытых страничек
screen scrPages:
# рамка для страницы
frame:
align (.5, .2) # расположение
# размеры
xminimum 500 xmaximum 500
yminimum 400 ymaximum 400
background "#0028" # фон
vbox:
spacing 16
# контейнер с кнопками управления страницами
hbox:
xfill True
# кнопка, которая листает страницы назад (с проверкой на
границы)
# SensitiveIf делает кнопку активной при выполнении условия

338
2018 Ren’Py

textbutton _("«") align(.0, .0) action [SensitiveIf(page >


0), SetVariable("page", page - 1)]
text str(page + 1) + " из " + str(len(persistent.pages))
align(.5, .0)
# кнопка, которая листает страницы вперед (с проверкой на
границы)
textbutton _("»") align(1.0, .0) action [SensitiveIf(page <
len(persistent.pages) - 1), SetVariable("page", page + 1)]
# если текущая страница доступна, то выводим ее
if page >= 0 and page < len(persistent.pages):
$ title, txt, img = persistent.pages[page]
# горизонтальный контейнер, чтобы картинка была слева
hbox:
vbox:
# картинка
xminimum 200 xmaximum 200
# если она есть, то выводим
if img:
add img align(.5, .2)
# вертикальный контейнер для текста
vbox:
xfill True yalign .1
# расстояние между объектами в контейнере
spacing 16
# заголовок страницы
text title xalign .5
# текст страницы
text txt xfill True

label start:
"Для начала покажем экран со страницами. При первом запуске пустой."
show screen scrPages
"Добавим одну страницу."
$ persistent.pages.append(("Страница 1", "Текст страницы. Просто любой
текст для того, чтобы показать пример.", "image1"))
"А теперь добавим еще пару страниц."
$ persistent.pages.append(("Страница 2", "Текст второй страницы. И снова
просто любой текст для того, чтобы показать пример.", "image2"))
$ persistent.pages.append(("Страница 3", "Текст второй страницы. И снова
просто любой текст для того, чтобы показать пример. Только в этот раз без
картинки.", ""))
"Теперь их можно полистать."
hide screen scrPages
"Сеанс окончен. Всем спасибо."
menu:
"Очистить список страниц?"
"Да":
# эта строка очищает данные в списке страниц

339
2018 Ren’Py

$ persistent.pages = []
# скорее всего для этого будет использоваться кнопка
# textbutton _("Очистить") action SetField(persistent, "pages",
[])
"Нет":
pass
return

ИНФОРМАЦИОННЫЙ ЭКРАН 2. ЛИСТ ПЕРСОНАЖА

Подробней читайте здесь:

https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=16273

init python:
xmax = config.screen_width
ymax = config.screen_height

init python:
# declares a class called 'char'
default_var = '???'
class char:
#--------------------------VV--------if you want to change how much
affection they start with
def __init__(self, affection=0, friendship=default_var,
name=default_var, bloodType=default_var, mood=default_var, age=default_var,
birthday=default_var, sign=default_var, likes=default_var,
dislikes=default_var, description=default_var, currentThoughts=default_var,
dateable=True, mainChar=default_var, pic='none', health=default_var,
mana=default_var, charisma=default_var, intelligence = default_var, stregnth
= default_var, agility = default_var, stress = default_var ): #<-- this line
sets all the defaults; the only one you'll probably use

self.affection= affection
self.friendship = friendship
self.name = name
self.bloodType = bloodType
self.mood = mood
self.age = age
self.birthday = birthday
self.sign = sign
self.likes = likes
self.dislikes = dislikes
self.description = description
self.currentThoughts = currentThoughts
self.dateable=dateable
self.mainChar = False
self.pic=pic

self.mana = mana
self.health = health

self.charisma = charisma
self.intelligence = intelligence

340
2018 Ren’Py

self.stregnth = stregnth
self.agility = agility
self.stress = stress
#You can add more areas if you want, just put self. and whatever
it is you need

def add_affection(self, amount):


self.affection += amount
if self.affection > affectionMax:
self.affection = affectionMax

def add_friendship(self, amount):


self.friendship += amount
if self.friendship > friendshipMax:
self.friendship = friendshipMax

def add_health(self, amount):


self.health += amount
if self.health > healthMax:
self.health = healthMax

def add_mana(self, amount):


self.mana += amount
if self.mana > manaMax:
self.mana = manaMax

def add_charisma(self, amount):


self.charisma += amount
if self.charisma > charismaMax:
self.charisma = charismaMax

def add_intelligence(self, amount):


self.intelligence += amount
if self.intelligence > intelligenceMax:
self.intelligence = intelligenceMax

def add_stregnth(self, amount):


self.stregnth += amount
if self.stregnth> stregnthMax:
self.stregnth = stregnthMax

def add_agility(self, amount):


self.agility += amount
if self.agility > agilityMax:
self.agility = agilityMax

#mother of normalizations
def normalizeAffection(self):
if self.affection > affectionMax:
self.affection = affectionMax
if self.affection < 0:
self.affection = 0

def normalizeFriendship(self):
if self.friendship > friendshipMax:
self.friendship = friendshipMax
if self.friendship < 0:
self.friendship = 0

def normalizeHealth(self):

341
2018 Ren’Py

if self.health > healthMax:


self.health = healthMax
if self.health < 0:
self.health = 0

def normalizeMana(self):
if self.mana > manaMax:
self.mana = manaMax
if self.mana < 0:
self.health = 0

def normalizeCharisma(self):
if self.charisma > charismaMax:
self.charisma = charismaMax
if self.charisma < 0:
self.charisma = 0

def normalizeIntelligence(self):
if self.intelligence > intelligenceMax:
self.intelligece = intelligenceMax
if self.intelligence< 0:
self.intelligence = 0

def normalizeStregnth(self):
if self.stregnth > stregnthMax:
self.stregnth = stregnthMax
if self.stregnth < 0:
self.stregnth = 0

def normalizeAgility(self):
if self.agility > agilityMax:
self.agility = agilityMax
if self.mana < 0:
self.agility = 0

def normalizeStress(self):
if self.stress > stressMax:
self.stress = stressMax
if self.stress < 0:
self.stress = 0
init:
#declare all the characters here, use the following format. Add as many
as you want or need.
$ Elisa = char(
name="Elisa ",
bloodType="A",
mood="Social Studies",
age="18",
birthday="October 19",
sign="Libra",
likes="Ice Cream",
dislikes="Chocolate Mint",
description="Academically Empowered, Medically Helpless...",
currentThoughts="Study... Study... Study... Study.",
dateable=False,
mainChar = False
#pic="girl a 1.png"
)
$ Francesca = char(
name="Francesca",

342
2018 Ren’Py

bloodType="AB",
mood="Peacekeeping",
age="19",
birthday="March 12",
sign="Pisces",
likes="Pulla, Kiisseli",
dislikes="Salmiakki",
description="A force of lawful good... Disciplines any student who
violates the Academy's rules.",
currentThoughts="Soumi!",
dateable=False,
mainChar = False
#pic="b1.png"
)

$ Stefania = char(
name="Stefania",
bloodType="B",
mood="Programming",
age="17",
birthday="September 10",
sign="Libra",
likes="Mocnik, Fritaja, Prekmurska gibanica ",
dislikes="Kislo mleko",
description="Fairly physical for her type... She's an ACE!",
currentThoughts="Oh I can't wait for next spring...",
dateable=False,
mainChar = False
#pic="b1.png"
)

$ Angelo = char(
name="Angelo",
bloodType="B",
mood="Motivated",
age="19",
birthday="August 8",
sign="Leo",
likes="Women.",
dislikes="Traps",
description="Flirt. Adores all the women he sees. Except Stefania.",
currentThoughts="I wonder when's the next season of ****** going to
show.",
dateable=False,
mainChar = False
#pic="b1.png"
)

#these are the characters shown on the screen, you can add more as you
meet new people
$ allchars = [Elisa, Francesca, Stefania, Angelo]

$ affectionMax = 100000 #<-- maximum affection value is changed here


$ friendshipMax = 100000

$ healthMax = 100000
$ manaMax = 100000

$ charismaMax = 100000
$ intelligenceMax = 100000

343
2018 Ren’Py

$ stregnthMax = 100000
$ agilityMax = 100000
$ stressMax = 100000

$ show_profiles = False
$ viewing = "Francesca" #<-- the default character to show when the info
screen is first called

screen profile_screen:
tag menu
zorder 10
# creates a string for proper display of each fact (+some bars)
for i in allchars:
$ char = i
if viewing == char.name:
$ name = "Name: " + char.name
$ bloodType = "Blood Type: " + char.bloodType
$ mood = "Mood: " + char.mood
$ age = "Age: " + char.age
$ birthday = "Date of Birth: " + char.birthday
$ sign = "Sign: " + char.sign
$ likes = "Likes: " + char.likes
$ dislikes = "Dislikes: " + char.dislikes
$ description = "\n" + char.description + "\n"
$ thoughts = "Current Thoughts: \n \"" + char.currentThoughts +
"\""
$ pic = char.pic
$ mainChar = char.mainChar

$ affectionBar = False
$ friendshipBar = False
$ charismaBar = False
$ intelligenceBar = False
$ stregnthBar = False
$ agilityBar = False
$ healthBar = False
$ manaBar = False
$ dessertBar = False

if char.mainChar:
##For the main character

$ affectionBar = False
$ friendshipBar = False

$ charismaBar = True
$ intelligenceBar = True
$ stregnthBar = True
$ agilityBar = True
$ dessertBar = True
$ healthBar = True
$ manaBar = True

elif char.dateable: ##If you define the main character, change


this statement to elif
$ affectionBar = True
$ friendshipBar = True
else:
$ affectionBar = False
$ friendshipBar = True

344
2018 Ren’Py

$ affection = char.affection
$ friendship = char.friendship
$ charisma = char.charisma
$ intelligence = char.intelligence
$ stregnth = char.stregnth
$ agility = char.agility
$ stress = char.stress

$ health = char.health
$ mana = char.health

#actually displays everything


frame xminimum 240 xmaximum 240 yminimum ymax:
style_group "infoscreen"
vbox yalign 0.5 xalign 0.5:
for i in allchars:
#$ textbutton_name, dummy1, dummy2 = i.name.partition(' ')
#cuts off the name after the first space
textbutton i.name action SetVariable("viewing", i.name)
xminimum 220 xmaximum 220 yminimum 50
#code for future imagebuttons
#imagebutton idle "i.idlepic" hover "i.hoverpic" action
SetVariable("viewing", i.name)
$ i.normalizeAffection()
$ i.normalizeFriendship()
$ i.normalizeHealth()
$ i.normalizeMana()
$ i.normalizeCharisma()
$ i.normalizeIntelligence()
$ i.normalizeStregnth()
$ i.normalizeAgility()
$ i.normalizeStress()
textbutton "Return" action Return() ypos 0.8

window xanchor 0 xpos 240 yalign 0 xminimum 784 xmaximum 784 yminimum
ymax ymaximum ymax:
style_group "infoscreen"
vbox spacing 10:
vbox:
text name
text bloodType
if mood != 'Mood: ???':
text mood
text age
text birthday
text sign
vbox xmaximum 500:
text likes
text dislikes
vbox spacing 10 xmaximum 490:
text description
text thoughts
if affectionBar:
hbox ypos 0.7:
text "Love: "
bar value affection range affectionMax style
"infoscreen_bar" right_bar "bar_empty.png" left_bar "bar_full-pink.png"
if friendshipBar:
hbox ypos 0.8:

345
2018 Ren’Py

text "Friendship: "


bar value friendship range friendshipMax style
"infoscreen_bar" right_bar "bar_empty.png" left_bar "bar_full-purple.png"

if mainChar:
#if healthbar:
hbox ypos 0.7:
text "Health: "
bar value health range healthMax style
"infoscreen_bar" right_bar "bar_empty.png" left_bar "bar_full-red.png"
#if manaBar:
hbox ypos 0.59:
text "Mana: "
bar value mana range manaMax style
"infoscreen_bar" right_bar "bar_empty.png" left_bar "bar_full-blue.png"
#if charismaBar:
hbox ypos 0.5:
text "Charisma: "
bar value charisma range charismaMax style
"infoscreen_bar"
#if intelligenceBar:
hbox ypos 0.4:
text "Intelligence: "
bar value intelligence range intelligenceMax
style "infoscreen_bar"
#if stregnthBar:
hbox ypos 0.3:
text "Stregnth: "
bar value stregnth range stregnthMax style
"infoscreen_bar"
#if agilityBar:
hbox ypos 0.2:
text "Agility: "
bar value agility range agilityMax style
"infoscreen_bar"
#if dessertBar:
hbox ypos 0.1:
text "Stress: "
bar value stress range stressMax style
"infoscreen_bar"

if pic != 'none':
add pic xalign 0.6 yalign 0.0 #Tinker with these numbers as
needed to change where the image goes

ЛИСТАЕМ СТРАНИЦЫ КНИГИ

http://renpyfordummies.blogspot.ru/2017/02/blog-post.html
init -1 python:
# окно игры в центре экрана
import os
os.environ['SDL_VIDEO_CENTERED'] = '1'
# автоматическое объявление изображений
config.automatic_images_minimum_components = 1
config.automatic_images = [' ', '_', '/']

346
2018 Ren’Py

config.automatic_images_strip = ['images']
style.default.font = "fonts/AnimeAceV3.ttf"
style.default.size = 22

init:
# положение левой страницы
transform lf():
xpos .5 xanchor 1.0 yalign .5
# положение правой страницы
transform rg():
xpos .5 xanchor 0.0 yalign .5
# right to center (листание справа к центру)
transform r2c(delay=.25):
xpos .5 xanchor 0.0 xzoom 1.0 yalign .5
easeout delay xzoom 0.001
# center to left (листание от центра влево)
transform c2l(delay=.25):
xpos .5 xanchor 1.0 xzoom .001 yalign .5
easein delay xzoom 1.0
init python:
# перелистывание
# сначала новые страницы, затем старые
# если страницу не указывать, то будет пустая
def pflip(new1="pageleft", new2="pageright", old1="pageleft",
old2="pageright", delay=.5):
renpy.hide("pleft")
renpy.hide("pright")
renpy.show(old1, [lf()], tag="pleft")
renpy.show(new2, [rg()], tag="pright")
renpy.show(old2, [r2c(delay*.5)], tag="plist")
renpy.pause(delay*.5)
renpy.show(new1, [c2l(delay*.5)], tag="plist")
renpy.pause(delay*.5)
renpy.show(new1, [lf()], tag="pleft")
renpy.show(new2, [rg()], tag="pright")
renpy.hide("plist")

label start:
scene expression "#445"
show pagebook with dissolve
"Сейчас полистаем книгу. Просто щелкайте по экрану."
# с пустых на титульные
$ pflip("page0", "page1")
pause
# с титула на текст
$ pflip("page2", "page3", "page0", "page1")
pause
# снова переходим к пустым страницам

347
2018 Ren’Py

$ pflip(old1="page2", old2="page3")
"Остальные страницы почему-то пустые."
# с пустых на пустые
$ pflip()
"Ну и нет смысла листать дальше."
# убираем с экрана страницы и саму книгу
hide pleft
hide pright
hide pagebook
with dissolve
return

CТИЛИ

Это система которая контролирует внешний вид объектов.


Она используется для сокращения числа текста(имеется в виду, у вас
в проекте 300 кнопок, и у них у всех 1 единый стиль, тогда применив
style ко всем кнопок нем не придется вручную прописывать
характеристики к каждой кнопке и вам нужно будет только
прописывать координаты кнопки и текст кнопки)
Она берет информацию из 4 источников.

1 источник – экраны
Каждый объект созданный экраном может применить к себе
определенные настройки стиля.

screen text style():


frame:
textbutton _("Опасность"):
text_color "#c04040"
text_hover_color "#ff0000"
action Return(True)

348
2018 Ren’Py

at center
Если в экране есть текст, то настройки стиля с префиксом text_ будут
применяться к данному тексту.

2 источник – изображения
Здесь стиль применяется как часть оператора image
image style2 = Text(_("Этот текст красный"), color="#ffc0c0")

3 источник – персонажи
Здесь стиль применяется как часть оператора Character
define egreen = Character("Eileen", who_color="#c8ffc8", who_bold=True,
what_color="#c8ffc8")
Аргументы которые начинаются с приставки who_ - настройки стиля
для имени персонажа, а с what_ - к тексту диалога персонажа
А аргументы которые применяются без приставок – только для имени
персонажа
4 источник – оператор style
Он создает или изменяет уже существующий стиль.
style blue_text:
color "#c0c0ff"

image style3 = Text(_("Этот текст синего цвета"), style="blue_text")


Добавив к Text аргумент style мы говорим программе использовать
стиль blue_text
Так же обратите внимание, что любой текст(кнопка, рамка….)
изначально прописана в программе в режиме default (т.е. по
умолчанию). Мы ее определяем при запуске проекта, когда мы
выбираем тему проекта.

Что бы прописать 1 раз стиль по умолчанию, используют функцию is


349
2018 Ren’Py

Пример, пропишем цвет текста при вводе команды text или button
style blue_text is text:
color "#c0c0ff"
label start:
show text "Этот текст голубой в любом моменте" align 0.5
pause
или
style blue_button is button:
color "#c0c0ff"
screen test:
button:
align 0.5
text "Кнопка голубой будет"
label start:
show screen test
pause
Так же в экранах мы можем отдельно прописать каждому обьекту
стиль, или всему экрану.
Для этого используют style_prefix. Например размер и характеристику
всем кнопкам одинаковую прописать, как это было сделано в
настройках гуи
screen preferences():

tag menu

# Include the navigation.


use navigation

# Put the navigation columns in a three-wide grid.


grid 3 1:
style_prefix "prefs"
xfill True

# The left column.

350
2018 Ren’Py

vbox:
frame:
style_prefix "pref"
has vbox

label _("Display")
textbutton _("Window") action Preference("display", "window")
textbutton _("Fullscreen") action Preference("display", "fullscreen")

frame:
style_prefix "pref"
has vbox

label _("Transitions")
textbutton _("All") action Preference("transitions", "all")
textbutton _("None") action Preference("transitions", "none")

frame:
style_prefix "pref"
has vbox

label _("Text Speed")


bar value Preference("text speed")

frame:
style_prefix "pref"
has vbox

textbutton _("Joystick...") action ShowMenu("joystick_preferences")

vbox:

frame:
style_prefix "pref"
has vbox

label _("Skip")
textbutton _("Seen Messages") action Preference("skip", "seen")
textbutton _("All Messages") action Preference("skip", "all")

frame:
style_prefix "pref"
has vbox

textbutton _("Begin Skipping") action Skip()

frame:
style_prefix "pref"
has vbox

label _("After Choices")


textbutton _("Stop Skipping") action Preference("after choices", "stop")
textbutton _("Keep Skipping") action Preference("after choices", "skip")

351
2018 Ren’Py

frame:
style_prefix "pref"
has vbox

label _("Auto-Forward Time")


bar value Preference("auto-forward time")

vbox:

frame:
style_prefix "pref"
has vbox

label _("Music Volume")


bar value Preference("music volume")

frame:
style_prefix "pref"
has vbox

label _("Sound Volume")


bar value Preference("sound volume")
textbutton "Test" action Play("sound", "sound_test.ogg") style "soundtest_button"

frame:
style_prefix "pref"
has vbox

label _("Voice Volume")


bar value Preference("voice volume")
textbutton "Test" action Play("voice", "voice_test.ogg") style "soundtest_button"

init python:

style.pref_frame.xfill = True
style.pref_frame.xmargin = 5
style.pref_frame.top_margin = 5

style.pref_vbox.xfill = True

style.pref_button.size_group = "pref"
style.pref_button.xalign = 1.0

style.pref_slider.xmaximum = 192
style.pref_slider.xalign = 1.0

ЧЕРЕЗ СТИЛЬ МОЖНО ЗАДАТЬ КООРДИНАТЫ

style general is frame:

352
2018 Ren’Py

xalign 0.5

yalign 0.2

screen general():

frame:

style "general"

text _("Текст у которого координаты рамки прописаны в style")

label start:

show screen general

" Текст диалога"

ЧЕРЕЗ СТИЛЬ МОЖНО ЗАДАТЬ РАЗМЕРЫ РАМКИ

Оно задается через x(y)maximum и x(y)minimum


style general is frame:

xalign 0.5

yalign 0.2

xmaximum 400

yminimum 200

screen general():

frame:

style "general"

text _("Текст у которого координаты рамки прописаны в style")

label start:

show screen general

" Текст диалога"

353
2018 Ren’Py

Оно устанавливает минимальное-максимальное значение для x и у


координат. Если текст, изображение и т.д. будет больше или меньше
значения пикселей maximum или minimum то оно автоматически
сожмется до этих значений.

УСТАНОВИТЬ ТОЧНОЕ ЗНАЧЕНИЕ РАЗМЕРА РАМОК

style general is frame:

xalign 0.5

yalign 0.2

xsize 400

ysize 200

screen general():

frame:

style "general"

text _("Текст у которого координаты рамки прописаны в style")

label start:

show screen general

" Текст диалога"

Оно будет строго определенного размера, благородя size

ИЗМЕНЯЕМ ТЕКСТ ВОСПРОИЗВЕДЕНИЯ ДЛЯ СИНТЕЗАТОРА


РЕЧИ

Синтезатор речи применяется для плохо видящих, или слышащих людей. Он


воспроизводит весь текст, который написан на экране, или наведите на текстовую кнопку.

Что бы изменить текст для отображения прописывают в стиле alt

style general:

alt _("Ты ж мэне пидманула…")

354
2018 Ren’Py

screen general():

frame:

style "general"

text _("Текст у которого координаты рамки прописаны в style")

label start:

show screen general

" Текст диалога"

И теперь нужно включить синтезатор речи. Shift+V Очень часто применяется при бета
тесте, когда свои заметки и комментария говорит программист бета тестеру, или скрытая
пасхалка…. Как в Repyblicue (где девушка общается с камерой-игроком – там полно
такого плана пасхалок)

УДОБНЫЙ СПОСОБ НАПИСАНИЯ СТИЛЯ В ЭКРАНАХ

style general is frame:

xalign 0.5

yalign 0.2

screen general(style):

frame:

style style

text _("Orbiting Earth in the spaceship, I saw how beautiful our planet is.\n–Yuri Gagarin")

label start:

show screen general("general")

with dissolve

НАСТРОЙКИ ТЕКСТА СТИЛЯ В ЭКРАНАХ

Пропишем экран с условием, когда он будет вертикальным, и его


координаты.
screen Vasya(style, vertical=False):

frame:

xalign 0.5

355
2018 Ren’Py

ypos 50

if vertical:

left_padding 20

right_padding 35

bottom_padding 35

text _("Вертикальный текст") style style

else:

xsize 400

text _("Тут текст какой нибудь"):

style style

Мы записали удобный способ стиля и что при отрицательном значении


vertical=False у нас будут координаты
frame:

xalign 0.5

ypos 50

с текстом
else:

xsize 400

text _("Тут текст какой нибудь"):

style style

ВЕРТИКАЛЬНЫЙ ТЕКСТ

Что бы посмотреть на вертикальный текст


if vertical:

left_padding 20

right_padding 35

bottom_padding 35

356
2018 Ren’Py

text _("Вертикальный текст") style style

вам необходимо будет написать следующее


style vertical_text:

vertical True

size 18

screen Vasya(style, vertical=False):

frame:

xalign 0.5

ypos 50

if vertical:

left_padding 20

right_padding 35

bottom_padding 35

text _("Вертикальный текст") style style

else:

xsize 400

text _("Тут текст какой нибудь"):

style style

label start:

show screen Vasya("vertical_text", True)

"Тут текст какой нибудь"

Обычно вертикальный стиль используют в азиатских странах.

ЖИРНЫЙ ТЕКСТ

style bold_text:

357
2018 Ren’Py

bold True

label start:

show screen Vasya("bold_text")

pause

КУРСИВНЫЙ ТЕКСТ

style italic_text:

italic True

label start:

show screen Vasya("italic_text")

pause

НИЖНЕЕ ПОДЧЕРКИВАНИЕ

style underline_text:

underline True

label start:

show screen Vasya("underline_text")

pause

ЦВЕТ ТЕКСТУ

style color_text:

color "#c0ffc0"

label start:

show screen Vasya("color_text")

pause

ШРИФТ ТЕКСТУ

358
2018 Ren’Py

style font_text:

font "dejave.ttf"

label start:

show screen Vasya("font_text")

pause

ОБВОДКА ТЕСТА

style outlines_text:

outlines [ (1, "#408040", 0, 0) ]

label start:

show screen Vasya("outlines_text")

pause

СГЛАЖИВАНИЕ ТЕКСТА

style antialias_text:

antialias True

label start:

show screen Vasya("antialias_text")

pause

Если True, то по умолчанию, TrueType шрифт текста будет оказано сглаживание

ИНТЕРВАЛ РАССТОЯНИЯ ТЕКСТА

По умолчанию стоит True, при False не будет меняться размер растояние текста(как в
input)

style adjust_spacing_text1:

adjust_spacing False

style adjust_spacing_text2:

adjust_spacing True

359
2018 Ren’Py

label start:

show screen Vasya("adjust_spacing_text1")

pause

show screen Vasya("adjust_spacing_text2")

pause

ОТСТУП 1 СТРОКИ ТЕКСТА

style first_indent_text:

first_indent 25 ###расстояние в пикселях

label start:

show screen Vasya("first_indent_text")

pause

ДОПОЛНИТЕЛЬНЫЙ ПРОБЕЛ МЕЖДУ СЛОВАМИ

style justify_text:

justify True

label start:

show screen Vasya("justify_text")

pause

Оно не выполняется на последней строке обзаца

РАССТОЯНИЕ МЕЖДУ КАЖДОЙ БУКВОЙ

style kerning_text:

kerning 25

label start:

show screen Vasya("kerning_text")

pause

ИНТЕРВАЛ НАД СТРОКАМИ

360
2018 Ren’Py

style line_leading_text:

line_leading 25

label start:

show screen Vasya("line_leading_text")

pause

ИНТЕРВАЛ ПОД СТРОКАМИ

style line_spacing_text:

line_spacing 25

label start:

show screen Vasya("line_spacing_text")

МИНИМАЛЬНАЯ ШИРИНА СТРОКИ

style min_width_text:

min_width 600

label start:

show screen Vasya("min_width_text")

СКОРОСТЬ ПОЯВЛЕНИЯ ИМЕНИ ПЕРСОНАЖА

define eg = Character("Самое эпичное появление имени", slow_cps = 5)

label start:

eg "Вот как меня зовут"

Если значение будет True то скорость будет браться из настроек(скорость текста)

СКОРОСТЬ ДИАЛОГА ПЕРСОНАЖА

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

define eg = Character("Паника", slow_cps_multiplier = 5)

label start:

eg "Аааа!!!! Мы все умрем!!!!!"

361
2018 Ren’Py

ЗАЧЕРКНУТЬ ТЕКСТ

define eg = Character("Паника", strikethrough= True)

label start:

eg "Аааа!!!! Мы все умрем!!!!!"

СТИЛЬ РАМОК

ЗАДНИЙ ФОН

Задний фон принимает команда background которая в свою очередь имеет еще значения
style button:
idle_background "idle_button.png"
hover_background "hover_button.png"
insensitive_background "idle_button.png"

selected_idle_background "idle_button.png"
selected_hover_background "hover_button.png"
selected_insensitive_background "idle_button.png"

INSENSITIVE
Используется, когда пользователь не может взаимодействовать.
idle
Используется, когда отображаемый ни сосредоточенная, ни выбрано.
hover
Используется, когда отображаемая фокусируется, но не выбран.
SELECTED_IDLE
Используется, когда отображаемая не сфокусирован, и выбран.
selected_hover
Используется, когда отображаемая сфокусирован и выбран.

style example_button is default:

idle_background Frame("idle_background.png", 10, 10, tile=True)

hover_background Frame("hover_background.png", 10, 10, tile=True)

xalign 0.5

screen button(style):

default selected = "top"

362
2018 Ren’Py

frame:

xalign 0.5

ypos 50

background "#0004"

xsize 350

has vbox:

xalign 0.5

textbutton _("Верх"):

style style

action SetScreenVariable("Выбрать", "top")

text_style "example_button_text"

textbutton _("Вниз"):

style style

action SetScreenVariable("Выбрать", "bottom")

text_style "example_button_text"

label start:

show screen button('example_button')

pause

ИЗМЕНЯЕМ РАЗМЕРЫ ВНУТРИ ФОНА КНОПКИ

Добавим к стилю example_button и размер определенный рамки.

style oddly_padded_button is example_button:

left_padding 10

right_padding 40

top_padding 10

bottom_padding 5

style example_button is default:

idle_background Frame("idle_background.png", 10, 10, tile=True)

hover_background Frame("hover_background.png", 10, 10, tile=True)

363
2018 Ren’Py

xalign 0.5

screen button(style):

default selected = "top"

frame:

xalign 0.5

ypos 50

background "#0004"

xsize 350

has vbox:

xalign 0.5

textbutton _("Верх"):

style style

action SetScreenVariable("Выбрать", "top")

text_style "example_button_text"

textbutton _("Вниз"):

style style

action SetScreenVariable("Выбрать", "bottom")

text_style "example_button_text"

label start:

show screen button('example_button')

pause

show screen button('oddly_padded_button')

где
left_padding - Объем пространства между фоном и левой частью
содержимого окна, в пикселях.
right_padding - Объем пространства между фоном и правой частью
содержимого окна, в пикселях.
top_padding - Объем пространства между фоном и верхней частью
содержимого окна, в пикселях.
bottom_padding - Объем пространства между фоном и нижней частью
содержимого окна, в пикселях

364
2018 Ren’Py

ИЗМЕНЯЕМ РАЗМЕРЫ ВНЕ ФОНА КНОПКИ

style oddly_ margin _button is example_button:

left_ margin 10

right_ margin 40

top_ margin 10

bottom_ margin 5

label start:

show screen button('example_button')

pause

show screen button('oddly_ margin _button')

pause

где

left_ margin - Количество прозрачного пространства слева от фона, в пикселях.


right_ margin - Количество прозрачного пространства справа на заднем плане, в
пикселях.

top_ margin - Количество прозрачного пространства над фоном, в пикселях.


bottom_ margin - Количество прозрачного пространства ниже фона в пикселях.

ПЕРЕДНИЙ ФОН

Передний фон команда foreground которая аналогична заднему фону


style button:
idle_foreground "idle_button.png"
hover_ foreground "hover_button.png"
insensitive_ foreground "idle_button.png"

selected_idle_ foreground "idle_button.png"


selected_hover_ foreground "hover_button.png"
selected_insensitive_ foreground "idle_button.png"

СДЕЛАТЬ ОДИНАКОВЫМ РАЗМЕРОМ ВСЕ КНОПКИ

Простой пример – главное меню стандартное

style sized_button is margin_button:

365
2018 Ren’Py

size_group "example"

label start:

show screen button('sized_button')

pause

СТИЛЬ КНОПОК

ЗВУК ПРИ НАВЕДЕНИИ И НАЖАТИИ

style beep_button is example_button:

hover_sound "pong_beep.opus"

activate_sound "pong_boop.opus"

label start:

show screen button('beep_button')

pause

где

hover_sound – звук при наведении

activate_sound – звук при нажатии

НЕВИДИМАЯ ЗОНА НЕ АКТИВНА У КНОПКИ

style focus_button is example_button:

focus_mask True

label start:

show screen button('focus_button')

pause

СФОКУСИРОВАТЬ КНОПКУ ПРИ ПОМОЩИ КЛАВИАТУРЫ

style keyboard _button is example_button:

366
2018 Ren’Py

keyboard_focus True

label start:

show screen button('keyboard_button')

pause

МИНИМАЛЬНЫЙ И МАКСИМАЛЬНЫЙ РАЗМЕРЫ

style maxim_text:

xminimum 100

xmaximum 150

yminimum 200

ymaximum 250

screen Vasya(style, antialias=False):

frame:

xalign 0.5

ypos 50

if antialias:

left_padding 20

right_padding 35

bottom_padding 35

text _("Вертr hgshgshhgf shggsgfssshsfghsgf") style style

else:

xsize 400

text _("Тут текст какой нибудь"):

style style

label start:

show screen Vasya("maxim_text",True)

367
2018 Ren’Py

pause

minimum – минимальное значение х и у

maximum – максимальное значение х и у

ПРОПИСЫВАЕМ СТИЛЬ КНОПКАМ ВЫБОРА

init:
# стиль для кнопок выборов
style menu_choice_button:
# для фона можно выбрать и Frame("image", 16, 16),
# чтобы углы размером 16х16 оставались неизменными,
# когда кнопка растягивается под размер текста
# я просто для примера выбрал сплошные цвета
background "#0008" # обычная кнопка
hover_background "#0808" # с наведенным курсором
insensitive_background "#8888" # неактивная
# ограничения размеров кнопок по ширине
xminimum int(config.screen_width * 0.5)
xmaximum int(config.screen_width * 0.5)
# стиль для текста на кнопках выбора (размери цвета)
style menu_choice:
size 36
color "#fff"
hover_color "#ff8"
insensitive_color "#444"
label start:
menu:
"text1":
pass
"text2":
pass
return

ПРОПИСЫВАЕМ В НАСТРОЙКАХ ЦВЕТА КНОПОК ГЛАВНОГО


МЕНЮ

init python:

# список возможных цветов

# (вместо цветов могут быть картинки фонов для кнопок)

# эти цвета для темной темы colorblind

368
2018 Ren’Py

colors = ["#848", "#844", "#484", "#448"]

# поменять цвета или фоны кнопок главного меню

def newcolors(index=-1):

if index < 0 or index >= len(colors):

color = renpy.random.choice(colors)

else:

color = colors[index]

style.mm_button.background = color

style.mm_button.hover_background = "#884"

insensitive_background = "#444"

style.rebuild()

NewColors = renpy.curry(newcolors)

# теперь это можно привязать к любой кнопке

# textbutton _("Сменить цвета") action NewColors()

# или запускать при каждом запуске:

newcolors()

label start:

menu:

"Можно даже так выбрать цвет..."

"Цвет 1":

$ newcolors(0)

"Цвет 2":

$ newcolors(1)

"Цвет 3":

$ newcolors(2)

"Цвет 4":

$ newcolors(3)

"Случайный":

$ newcolors()

369
2018 Ren’Py

return

ВИДЕО

КАК ПРОИГРАТЬ ВИДЕОЗАСТАВКУ ДО


ПОЯВЛЕНИЯ ГЛАВНОГО МЕНЮ

label splashscreen:
#функция полноэкранного воспроизведения
#только она подходит для порта на android
$ renpy.movie_cutscene('movie.ogv')
return

label start:
#игра
return

КАК ДОБАВИТЬ ВИДЕО ФОНОМ


#файл script.rpy
#как добавить видео в фон меню:

init:
#на весь экран
image movie = Movie(size=(config.screen_width, config.screen_height))

label main_menu:
scene movie

370
2018 Ren’Py

$ renpy.music.play("vid.ogv", channel="movie", loop=True) #видео (можно


без звука)
$ renpy.music.play("muz.mp3", channel="music", loop=True) #мелодия для
меню - не обязательно
jump main_menu_screen

label start:
stop movie #без этого видео не остановится
$ renpy.music.stop #не обязательно, если нет музыки

КАК ДОБАВИТЬ ВИДЕО-СПРАЙТ.


Прописываем
image eileen movie = Movie(channel="eileen", play="eileen.webm",
mask="eileen_mask.webm")
Далее используем в игре show eileen movie и готово

КАК УКАЗАТЬ ВИДЕО КООРДИНАТЫ


image launch = Movie(play="oa4_launch.webm", pos=(10, 10), anchor=(0,
0))

КАК ОТКЛЮЧИТЬ ВОЗМОЖНОСТЬ ПРОПУСКА ВИДЕО.

screen block_scr(flag, t):


....timer t action Hide("block_scr") repeat False
....$ keys_list = ["dismiss", "game_menu", "rollback", "rollforward"]
....if not flag:
........for k in keys_list:
............key k action [[]]

# The game starts here.


label start:
...."Следующее видео каждый должен посмотреть хотябы один раз до конца..."
....show screen block_scr(persistent.video_1_seen, 8)

371
2018 Ren’Py

....$ renpy.movie_cutscene("oa4_launch.webm")
....$ persistent.video_1_seen = True
...."Сыграйте еще раз..."
...."?"
....return

РЕЖИМ РАЗРАБОТЧИКА

Что бы у вас появилась возможность пользоваться этим


инструментом, вам потребуется:
Зайти в файл сценария в option.rpy и найти в нем такую строку
init -1 python hide:
## Включать ли нам инструменты разработчика? Здесь нужно
## поставить False перед выпуском игры, чтобы
## пользователь не смог мошенничать, используя эти
инструменты.
config.developer = False
Если нету, то создаем ее, только меняем строку одну на
config.developer = True

Когда вы закончите проект и начнете создавать


дистрибьютеры, отключите ее
config.developer = False

Далее запускаем наш проект, нажали на старт игры. Переключаем


клавиатуру на английский язык.

КЛАВИШИ КОТОРЫЕ РАБОТАЮТ В РЕЖИМЕ


РАЗРАБОТЧИКА

372
2018 Ren’Py

1) Shift+R – Перезагрузить проект/включить авто режим перезагрузки.


Все изменения что мы внесем в сценарий, и сохранив их приведут к
тому что запущенный проект автоматически перезагрузит.
2) Shift+O – Включить консоль, где вы сможете вводить команды
питона и ренпая (введите там Help и программа покажет часто
используемые команды)
3) Shift+G – Системные настройки(там ускорение, геймад, OpenGL и
т.д)
4) Shift+E – Открыть файл перевода, текст сценария(не факт)
5)Shift+I – Открыть диспетчер обьектов(мышкой указываете обьект)
6)Shift+D – Открыть меню разработчика
7)Shift+C – вкл/выкл озвучку буфера( что оно делает я не знаю)
8)Shift+V - вкл/выкл Синтезатор речи. Включает компьютерный
женский голос который весь текст озвучивает, включая текст при
наведении и диалога.

ИНТЕРАКТИВНЫЙ ДИРЕКТОР
Он позволяет вам добавлять изображения, музыку, переходы
напрямую через ренпай.
Идея в том что вы сначало пишете текст и логику сценария, а затем
интерактивно расставить изображения там где надо.
Что бы приступить к работе вам потребуется включить режим
разработчика. Нажать на клавиши shift+d и выбрать пункт
интерактивный директор. Если с первого раза у вас не загрузился
директор то перезагрузите проект shift+r. У вас загрузится такое
окно

373
2018 Ren’Py

Где стрелкой указано, где пункт выбора что добавить в проект(символ


+)

Как будет выглядеть путь, что бы добавить фон.


Нажимаем на + > Выбираем пункт scene > Выбираем из списка
изображение > И нажимаем на кнопку Добавить

374
2018 Ren’Py

Как добавить спрай с переходом

Как указать координату

375
2018 Ren’Py

И звуки

Но стандартные значения, что тут прописаны – это очень мало!!!


Поэтому мы рассмотрим, что мы можем добавить в директора
Все значения пишутся в питон

ИЗМЕНЯЕМ ДИРЕКТОРА

376
2018 Ren’Py

1) $ director.tag_blacklist = { "black", "text", "vtext" }

Черный список тегов, которые не будут отображаться для инструкций show, scene или
hide.

2) $ director.scene_tags = { "bg" }

Набор тегов, которые будут представлены для оператора scene и скрыты от оператора
show. Если пусто то все изображения

3) $ director.show_tags = set("sprite")

Набор тегов, которые будут представлены для оператора show и скрыты от оператора
scene. Если пусто то все изображения

4) $ director.transforms = [ "left", "center", "right" ]

Список преобразований, которые будут представлены в составе редактора. Кроме того,


любое преобразование, определенное с помощью оператора transform вне самого
Ren'Py, будет добавлено в список преобразований, который затем сортируется.

5) $ director.transitions = [ "dissolve", "pixellate" ]

Список переходов, которые предоставляются вместе с заявлением. Поскольку переходы


не могут быть автоматически обнаружены, их необходимо добавить вручную.

6) $ director.audio_channels = [ "music", "sound", "audio" ]

Название аудио каналов, которые могут быть использованы

7) $ director.voice_channel = "voice"

Имя аудиоканала, используемого голосом.

8) $ director.audio_patterns = [ "*.opus", "*.ogg", "*.mp3" ]

Список шаблонов аудио по умолчанию, которые используются для сопоставления


файлов, доступных в аудиоканале.

9) $ director.audio_channel_patterns = { }

Карта от имени канала к списку звуковых шаблонов, доступных в этом звуковом канале.
Например, если установлено значение { 'sound' : [ 'sound/*.opus' ], 'музыка':
['музыка/*.opus']} музыка и звуковые каналы получают свои собственные списки
шаблонов.

10) $ director.button = True

Если значение равно True, директор отображает экран с кнопкой для доступа к окну
директора. Если False, то игра может предоставить свой собственный доступ, сделав
доступным директора.Начните действие.

11) $ director.spacing = 1

377
2018 Ren’Py

Интервал между линией режиссера (scene, show, hide, with, play, queue, and voice) и
линией, не являющейся режиссером, или наоборот. Эти интервалы должны быть 0 или 1
линии, более высокий интервал может не работать.

12) $ director.viewport_height = 280

Максимальная высота видовых окон прокрутки, используемых директором.

ВВОД ИМЕНИ ПЕРСОНАЖА


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

Это было связанно с 1 из версий Последней фантазии(точно не помню


какой именно толи 5-8). Там персонажу дают собаку(питомца) очень
похожую на «какашку» и большинство не задумываяся давали ей имя
соответствующее – Какашка. И что произошло. В логах боя, когда
собака атакует, выглядел так – Какашка кусает противника и т.д. и из
за того что поголовно все давали ей имя такое собаке, имел резонанс
в фирме разработчика, что я больше не видел в последующих
версиях последней фантазии ввод имени. Если вы все равно не
передумали вот несколько способов ввести имя.

1)ПРИМЕР ИЗ ОБУЧЕНИЯ

Введите в метке старт такой текст


define g = Character("[name]")

label start:
python:
name = renpy.input(_("Как тебя зовут?"))
name = name.strip() or __("Жора!t")

378
2018 Ren’Py

"привет [name]"
g "и тебе привет неизвестный"

Разберем что тут записано:


1)define g = Character("[name]")
- прописываем имя персонажа с переменной "[name]"
2)python:
- используем питон можно и $
3) name = renpy.input(_("Как тебя зовут?"))
- высвечиваем вопрос, и на ввод текста переменная name – будет
иметь такое значение
4) name = name.strip() or __("Жора!t")
- страховка на тот случай если пользователь ничего не ввел, тогда
имя будет автоматически подобрано Жора а !t – что бы в переводе
отобразилась переменная
5)"привет [name]"
-текст диалога, в квадратных скобках пишут переменную которую

379
2018 Ren’Py

необходимо отразить в тексте(имя, число денег, осталось монет…. в


тексте диалога).
Что бы вызвать квадратные скобки переведите клавиатуру на
английский язык, и просто нажните на русскую х и ъ
6) g "и тебе привет неизвестный"
- что мы прописывали 1 пунктом и теперь персонаж с именем name
обращается к кому то в диалоге
У данного способа куча минусов:
1) Неограниченное число ввода знаков. Т.е. введите 60 символов и
продолжите текст, у вас высвечится ошибка. Мы не ввели ограничение
на мин и макс число символов
2)Китаец если введет имя на своем родном то вместо иероглифов у
него будет квакодзябра, из за того что шрифт диалога не
поддерживает его язык. И мы не ввели ограничение на язык ввода.
3) Не красивый, и не понятный интерфейс ввода для новичков,
которые впервые играют в новеллы.

2) БОЛЕЕ ПРОДУМАННЫЙ СПОСОБ

define vasja = DynamicCharacter(u'mc', image="vasja",


ctc=anim.Blink("arrow.png"))
label start:
$ mc = renpy.input("ПОЖАЛУСТА ДАЙТЕ ВАШЕМУ ПЕРСОНАЖУ
ИМЯ. Колличество символов 2-10.", default =_("Вася"), allow="
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZйц
укенгшщзхъэждлорпавыфячсмитьбюЙЦУКЕНГШЩЗХЪЭЖДЛОР
ПАВЫФЯЧСМИТЬБЮ", length=10)
$ mc = mc.strip()
if len(mc) < 2:
"Вы должны использовать минимум 2 буквы"
jump start

380
2018 Ren’Py

window show
zhora ulibaetsja "[mc]...Я тебя нигде не видела..."
menu:
"Вы хотите быть [mc]?"
"Нет":
jump name_vibor2
"Да":
pass
vasja ulibaetsja "Да я новенький..."

Появились новые пункты


1) default ="Вася" - имя которое будет высвечено в самом начале
2) allow="
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZйц
укенгшщзхъэждлорпавыфячсмитьбюЙЦУКЕНГШЩЗХЪЭЖДЛОР
ПАВЫФЯЧСМИТЬБЮ"
Мы прописали, что может быть введенено в проект (Если буквы, то
большие и маленькие - иначе не примет), как видно тут нет ни
символов, ни значков – только буквы русского и английского языка.
3) length=10
Максимальное число символом, которое мы можем ввести
4) $ mc = mc.strip()
Мы убрали значение, если ничего не выбрал пользователь
5) if len(mc) < 2:
"Вы должны использовать минимум 2 буквы"

381
2018 Ren’Py

jump start
Условие если символов меньше 2 было введенено с клавиатуры с
поледующим перенесением обратно в окно выбора.
6) window show – для красоты появление фона диалога не
обязательно

3)ПРИМЕР ИЗ ХОТ СПОТА


Пропишем значение
init:
default firstname = ""
default lastname = ""

init python:
def name_func(newstring):
store.firstname = newstring

def lastname_func(newstring):
store.lastname = newstring

style.input.caret = "my_caret"
style.input.size = 60
style.input.color = "#000"

382
2018 Ren’Py

style.input.caret = "my_caret" – палка вертикальная что мигает, в


кавычках имя изображения размером примерно 5х50

Отдельно пропишем это изображение


##for custom cursor caret
image my_caret:
"caret.png"

ypos 10

linear 1.0 alpha 1.0


linear 1.0 alpha 0.0
repeat

И прописываем сам экран ввода в горячих точках

383
2018 Ren’Py

screen text_input_screen():
default screenvar = False
imagemap:
ground "background.png"
idle "idle.png"
hover "hover.png"
selected_idle "hover.png"

hotspot (150,140,475,200) action


SetScreenVariable("screenvar",True)
hotspot (625,140,110,100) action
[Hide("text_input_screen"),Jump("complete")]
if screenvar == True:

input default firstname pos(200,165) changed name_func


label start:
call screen text_input_screen
label complete:
d "Your name is [firstname]!"
background.png 800x400

hover.png 800x400

384
2018 Ren’Py

idle.png 800x400

4) ПРОПИСЫВАЕМ ИМЯ И ФАМИЛИЮ


ПЕРСОНАЖА

init python:
first_name = 'Безымянный!t'
last_name = ''
input_first_name = 'Иван!t'
input_last_name = 'Иванов!t'
min_name_len = 2
max_name_len = 10
nameless = Character("'{0} {1}'.format(first_name,last_name).strip()",
dynamic=True)

label start:
scene bg timelessness
nameless "Пора выбрать себе имя. Имя само себя не выберет."
label first_name_input:
385
2018 Ren’Py

call screen screen_name_input("Введите имя:",'input_first_name')


if _return == '_b_enter':
if len(input_first_name) < min_name_len:
"Слишком короткое имя!"
jump first_name_input
else:
$ first_name = input_first_name
nameless "Моё имя будет [first_name]"
elif _return == '_b_cancle':
nameless "Оставлю всё как есть..."

label last_name_input:
call screen screen_name_input("Введите фамилию:",'input_last_name')
if _return == '_b_enter':
if len(input_last_name) < min_name_len:
"Слишком короткая фамилия!"
jump last_name_input
else:
$ last_name = input_last_name
nameless "Моя фамилия будет [last_name]"
elif _return == '_b_cancle':
nameless "Оставлю всё как есть..."

jump continued
screen screen_name_input(t,v):
key 'input_enter' action Return('_b_enter')

386
2018 Ren’Py

key 'K_ESCAPE' action Return('_b_cancle')


frame:
align (0.5,0.5)
xsize 300
vbox:
text "[t]":
xalign 0.5
text "(от [min_name_len] до [max_name_len] символов)":
xalign 0.5
input:
xalign 0.5
value VariableInputValue(v)
length max_name_len
allow
"ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфыва
пролджэячсмитьбюQWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasd
fghjklzxcvbnm"
hbox:
xfill True
textbutton "Cancle":
action Return('_b_cancle')
xalign 0.5
textbutton "Enter":
action Return('_b_enter')
xalign 0.5

387
2018 Ren’Py

label continued:
nameless "Моё имя будет [first_name]"
nameless "Моя фамилия будет [last_name]"
nameless "Меня зовут [nameless]"

5) "ГЕРОЙ БЕЗ КОНКРЕТНОГО ИМЕНИ"

define m = DynamicCharacter("hero_name") # Первоначально не


прописываем конкретное имя персонажа.
label start:
$ hero_name = "???!t " # Переменная, где имя персонажа "???"
m "Кто я?"
$ hero_name = u"Герой!t " # Переменная, где у персонажа
появляется конкретное имя
m "Так я – [hero_name]!!!"
$ hero_name = "???!t " # Переменная, где имя персонажа снова "???"
m "Нет?"
$ hero_name = u"Злодей!t " # Переменная, где у персонажа
появляется конкретное имя
m "Наверно, я – [hero_name]!"

388
2018 Ren’Py

ИМЯ ПОЛЬЗОВАТЕЛЯ КОТОРАЯ


ПРОПИСАНА НА ВАШЕМ КОМПЬЮТОРЕ
init python:
import os
player = os.environ.get( 'USERNAME',
os.environ.get( 'USER',
os.environ.get( 'LNAME',
os.environ.get( 'LOGNAME', 'Player' ))))
label start:
"Hello there, [player]."

СОЗДАЕМ ЭКРАННУЮ КЛАВИАТУРУ

Заранее предупреждаю, в новой версии ренпая в андроид НЕ НУЖНО


СОЗДАВАТЬ ТАКУЮ КЛАВИАТУРУ – ОНА УЖЕ ПРОПИСАННА
ПРОГРАМНО!
А если как я любите по настольгировать по старым играм – вот
https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=25972

ГЕНЕРАТОРЫ СЛУЧАЙНЫХ ЧИСЕЛ

1) RENPY.RANDOM.CHOICE
Генератор переменных и значений

ПРОСТОЙ ПРИМЕР – КАМЕНЬ НОЖНИЦЫ И


БУМАГА С СПИСКОМ
# Игра начинается здесь.

389
2018 Ren’Py

label start:

$ rps_beats = [("камень", "ножницы"), ("ножницы", "бумага"), ("бумага", "камень")]


###условия победы

"камень ножницы и бумага"

menu:

"Камень!":

$ rps_player = "камень"

"Бумага!":

$ rps_player = "бумага"

"Ножницы!":

$ rps_player = "ножницы"

$ rps_npc = renpy.random.choice(["камень", "бумага", "ножницы"])

e "Я выбрала %(rps_npc)s!"

if (rps_player, rps_npc) in rps_beats:

e "Ты выиграл! Давай еще сыграем"

jump rps

elif (rps_npc, rps_player) in rps_beats:

e "Я выиграла! Давай еще раз сыграем"

jump rps

else:

e "Ничья! Давай еще сыграем"

jump rps

label rps:

"Ты как будто знала, что у меня будет [rps_player]!!!"

"А Ты как будто знал, что у меня будет [rps_npc]!!!"

Разберем что мы тут записали

390
2018 Ren’Py

Мы прописываем список значений при победе, и прописываем все в 1


переменную $ rps_beats = [("камень", "ножницы"), ("ножницы",
"бумага"), ("бумага", "камень")]
Потом делаем выбор пользователя с тем, какая будет переменная у
пользователя $ rps_player

menu:
"Камень":
$ rps_player = "камень"
"Бумага!":
$ rps_player = "бумага"
"Ножницы!":
$ rps_player = "ножницы"
Далее вызываем генератор случайных чисел, и в нем пишем
переменную, что выпала у компьютера $ rps_npc
$ rps_npc = renpy.random.choice(["камень", "бумага", "ножницы"])
И потом мы прописываем условие, если будет совпадение со списком
победы у пользователя
if (rps_player, rps_npc) in rps_beats:
e "Ты выиграл! Давай еще сыграем"
jump rps
и такое же условие прописываем и на победу компьютера
elif (rps_npc, rps_player) in rps_beats:
e "Я выиграла! Давай еще раз сыграем"
jump rps
И если будет ничья тоже необходимо условие прописать. В любом
варианте переменной в конце всегда пишите else, что избегать
ошибок

391
2018 Ren’Py

else:
e "Ничья! Давай еще сыграем"
jump rps

Переменные используют аналогичным способом, только слегка


модернизируют значение(переменные в квадратные скобки)

ПРИМЕР ПЕРЕМЕННОЙ С РАЗНЫМИ


ПЕРЕМЕННЫМИ
label start:
$ r1 = 1
$ r2 = 0
"Что я сегодня буду делать...."
$ r3 = renpy.random.choice([r1, r2])
label vibor:
if r3 == 1:
"Спать"
jump sleep
else:
"Работать"
jump arbaiter

Мы рассмотрели функцию случайных


перменных(renpy.random.choice), а что делать, если требуется
отобразить случайное целое число? Для этого используют
(renpy.random.randint)

392
2018 Ren’Py

КАК ОТОБРАЗИТЬ ИЗОБРАЖЕНИЕ


РАНДОМНО

$ rand = renpy.random.choice(["bg test1","bg test2"])


scene expression rand

ГЕНЕРАТОР СЛУЧАЙНЫХ ЧИСЕЛ В ТЕКСТЕ


init python:

# Используем в формате:
# {txt_f=func}arg{/txt_f}
# Где:
# func - Нужная нам функция.
# arg - аргументы функции.
# Пример:
# Обычный формат:
# renpy.random.choice(('a', 'b', 'c'))
# in text формат:
# {txt_f=renpy.random.choice}('a', 'b', 'c'){/txt_f}

config.custom_text_tags["txt_f"] = lambda tag, argument, contents:tuple((kind,


unicode(eval("{}({})".format(argument, text)))) for kind, text in contents)

label start:
"В {txt_f=renpy.random.randint}5, 116{/txt_f} лет Анжелика перевела бабушку через
дорогу "
jump start

2) RENPY.RANDOM.RANDINT

ЧИСЛОВЫЕ ЗНАЧЕНИЯ
Простой пример
$ mwar = mwar + renpy.random.choice([1,3])
И еще пример

393
2018 Ren’Py

# Игра начинается здесь.


label start:
$ money = 7
$ r1 =0
"У меня [money] монет"
$ r1 = renpy.random.randint(1, 101)
$ money2 = money + r1
"Когда я пошла домой я нашла [r1] монет"
"Итого у меня монет стало - [money2]"
Или еще больше запутайте пользователя
label start:
$ money = renpy.random.randint(1, 101)
$ r1 = renpy.random.randint(1, 101)
$ money2 = money + r1
"У меня [money] монет"
"Когда я пошла домой я нашла [r1] монет"
"Итого у меня монет стало - [money2]"

КАК ПРОПИСАТЬ ПРЫЖКИ СЛУЧАЙНЫЕ ПО


МЕТКАМ
label loc:
#Обнуляю значение в начале действия.
$ gtm = 0
"Здесь реплика персонажа. "

394
2018 Ren’Py

#Генерируем случайное целое число между 1 и 100.


$ gtm = renpy.random.randint(1, 100)
if gtm >= 90:
jump loc1
elif gtm >= 70:
jump loc2
else:
jump loc3

КАК ПРОПИСЫВАТЬ ДЕЙСТВИЯ В


ПРОЦЕНТНОМ СООТНОШЕНИИ.

"У тебя 35% что ты ничего не поймешь из этой книги"


"У тебя 25% что что ты может быть и поймешь что тут пишут"
"У тебя 40% что ты все поймешь"

$ sila= renpy.random.randint(1, 100)


if sila <35:
"Я тугодум и я ничего не понял"
jump povtorit_vse
elif sila < 60:
"Я почти понял о чем тут речь"
else:
"Я все понял"
Разьясняю, о чем тут написано. Мы задали переменной диапазон от 1
и до 100 ( $ sila= renpy.random.randint(1, 100) ) и мы сделали еще

395
2018 Ren’Py

условия, при которых - if sila <35: - будет воспроизведенена в


значениях от 1 и до 35 т.е. 35%, elif sila < 60: в значениях от 35 до 60
т.е. 25 %, else: будет от 60 и до 100 т.е. 40 %. Тут соответственно
можно логически понять, о чем речь

3) RENPY.RANDOM.RANDOM()
Генерация числа от 0 и до 1 (там 0.35 и т.д) применяется зачастую в
прописях координат

Пример
screen main_menu:

# Это заменяет другие меню.


tag menu
# Фон главного меню.
window:
style "mm_root"
# Кнопки главного меню.
frame:
style_group "mm"
xalign renpy.random.random()
yalign renpy.random.random()
has vbox
textbutton _("Начать игру") action Start()
textbutton _("Загрузить игру") action ShowMenu("load")

396
2018 Ren’Py

textbutton _("Настройки") action ShowMenu("preferences")


textbutton _("Справка") action Help()
textbutton _("Выход") action Quit(confirm=False)

init -2 python:

# Сделать все кнопки главного меню одноразмерными.


style.mm_button.size_group = "mm"
И получили плавающее главное меню.

4) RENPY.RANDOM.SHUFFLE
Случайный распорядок
$ playlist = ["song1.mp3", "song2.mp3", "song3.mp3", "song4.mp3",
"song5.mp3"]

$ renpy.random.shuffle(playlist)

play music playlist fadeout 1.0 fadein 1.0


и
$ items = [1, 2, 3, 4, 5, 6, 7] # в начале
$ random.shuffle(items) # команда
$ items = [7, 3, 2, 5, 6, 4, 1] # получить можем

5) RANDOM.SAMPLE

Несколько значений взять


label start:
$ money = 7

397
2018 Ren’Py

$ r1 =0
"У меня [money] монет"
$ r1 = renpy.random.sample([1, 2, 3, 4, 5], 3)

"Когда я пошла домой я нашла 3 монеты номиналом [r1]рублей"

ЧТО-ТО ТИПА ЧИТ-КОДОВ


(http://renpyfordummies.blogspot.ru/2016/03/blog-post_18.html)

init python:
# функции из файла 7dots.rpy
images_auto()
window_center()
money = 100
# обводка
style.default.outlines = [(2, "#0008", 0, 0), (1, "#0008", 0, 0)]
# для хранения экранов
screens = []
# вызов скрипта из экрана
def call_input():
global screens
screens = renpy.current_screen().screen_name
# сам вызов, он очищает экран
renpy.call_in_new_context("my_input")
CallInput = renpy.curry(call_input)

# этот экран ждет нажатия кнопки табуляции


screen cheat:
key "K_TAB" action CallInput()
# индикатор денюжек

398
2018 Ren’Py

frame align(.95, .05) background "#0008":


text "$[money]" color "#dd4" size 48

# ввод кода и обработка результатов


label my_input:
# показать спрятанные ренпаем экраны
python:
for i in screens[-1:]:
renpy.show_screen(i)
# ввод данных (можно через renpy.input)
$ res = input("Введите код:", length=4)
# обработка результатов
if res == "1234":
$ money += 100
# сохранение переменных и обновление экрана
$ renpy.retain_after_load()
$ renpy.restart_interaction()
centered "Правильно. Держите ещё 100 денег."
elif not res:
centered "Нажата «Отмена»."
else:
centered "Код неверный."
return

# Игра начинается здесь.


label start:
scene bg
show neko with dissolve
# показать экран, который отлавливает кнопку чит-кода
show screen cheat
"Нажмите TAB для ввода чит-кода. И введите «1234»."
"Игра окончена."
return

399
2018 Ren’Py

КАК ПЕРЕМЕНОЙ ПРОПИСАТЬ


КООРДИНАТЫ
init:

$ x1 = Position(xanchor = 0.5, xpos = 0.5, yalign = 0.2)

$ x2 = Position(xanchor = 0.5, xpos = 0.5, yalign = 0.4)

$ x3 = Position(xanchor = 0.5, xpos = 0.5, yalign = 0.6)

$ x4 = Position(xanchor = 0.5, xpos = 0.5, yalign = 0.8)

label start:

show text "So much blood!" at x1 as line1 with dissolve

$ renpy.pause(1.5)

show text "How did I not hear {i}him{/i} come in?" at x2 as line2 with dissolve

$ renpy.pause(1.5)

return

СОЗДАЕМ ПАРОЛЬ
Пример пароля с числом попыток
init:
# правильный пароль, очень сложный и криптоустойчивый!
$ password = "12345"

label start:
$ i = 3 # число попыток
"Для продолжения нужно ввести ключевое слово."
# сюда возвращаемся при следующих попытках
label again:
$ p = renpy.input("Введите пароль:") # вводим пароль
# если неверный пароль и ещё есть попытки
if (p != password) and (i > 1):
# то уменьшаем количество попыток
$ i -= 1
"Не угадал. Осталось попыток: [i]"
# и отправляемся вводить пароль заново

400
2018 Ren’Py

jump again
# если кончились попытки
if i < 2:
"Попытки закончились. Ваша карта заблокирована."
# то прыгаем на соответствующую метку
jump bad
# если не прыгнули, значит попытки не кончились
# → пароль правильный
"Пароль подтвержден."
# хорошо, пароль правильный
return
label bad:
# плохо, не угадал
"Запоминайте пароли от карточек."
return

ТАЙМЕРЫ.
Посмотрите здесь https://www.renpy.org/wiki/renpy/doc/cookbook/Timed_menus

Мы задаем временные рамки, что бы пользовать быстро принимал


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

ЧИСЛОВОЙ ТАЙМЕР

401
2018 Ren’Py

screen battletime:
timer 0.1 repeat True action If(time > 0, True=SetVariable('time', time -
0.1), False = [Hide('battletime'), Jump(timerjump)])
if time <=3:
text _("{color=#f00}{size=72} [time]") xalign 0.5 yalign 0.2### на 3
секунде оно покраснеет
else:
text _("{color=#fff}{size=72} [time]") xalign 0.5 yalign 0.2### до 3
секунды оно белое

label balbes:
pause 0.1
"Вот и стой у разбитого корыта"

402
2018 Ren’Py

return

laber start:
"Тест числ таймера"
$ time = 5 #####Таймер всегда пишется в самом начале любой
метки, если раньше написать текст а потом вызов, то будет ошибка
$ timerjump = "balbes" ###Если не успел выбрать, то перейдешь в
эту метку
show screen battletime###вызываем таймер
menu:
"1)Поцеловать":
"Я" "Каэда!"
"Каэда" "Что тебе?!"
"чмок"
return

"2)Обнять":
"Каэда" "Убери от меня руки! {w} Я ненавижу тебя!!!"
"Я" "Прости"
"Мы так и простояли обнявшись. Она успокоилась и
заплакала"
return

Разберем что тут записали


screen battletime:– прописываем экран где мы указываем паузу( timer
0.1) включаем условия если больше 0 то будет отниматься по 0,1
секунде (If(time > 0, True=SetVariable('time', time - 0.1), ) если меньше 0
то закрывается экран с таймером (), False = [Hide('battletime'), ) и

403
2018 Ren’Py

автоматически переносимся в метку (Jump(timerjump)])) если не


уложились по времени

ТАЙМЕР В ВИДЕ БАРА

###Картинка бара
init -5 python:
style.timebar = Style(style.default)
style.timebar.left_bar = Frame("ui/interface/timerfull.png", 0, 0)
style.timebar.right_bar = Frame("ui/interface/timerempty.png", 0, 0)
style.timebar.xmaximum = 695 # bar width
style.timebar.ymaximum = 27 # bar height

404
2018 Ren’Py

screen battletime:
timer 0.1 repeat True action If(time > 0, True=SetVariable('time', time -
0.03), False = [Hide('battletime'), Jump(timerjump)])
bar:
style "timebar"
value time
xalign 0.5 yalign 0.2# расположение бара
label balbes:
pause 0.1
"Вот и стой у разбитого корыта"
return
laber start:
"Тест бара"
$ time = 1 #####Таймер всегда пишется в самом начале любой
метки, если раньше написать текст а потом вызов, то будет ошибка
$ timerjump = "balbes" ###Если не успел выбрать, то перейдешь в
эту метку
show screen battletime###вызываем таймер
menu:
"1)Поцеловать":
"Я" "Каэда!"
"Каэда" "Что тебе?!"
"чмок"

405
2018 Ren’Py

return
"2)Обнять":
"Каэда" "Убери от меня руки! {w} Я ненавижу тебя!!!"
"Я" "Прости"
"Мы так и простояли обнявшись. Она успокоилась и
заплакала"
return

ВЫБОРЫ МЕНЮ ИЗЧЕЗАЮТ КАЖДЫЕ 2


СЕКУНДЫ
init python:
def dynamicMenuManager(origin, target):
global menuLimit
menuLimit -= 1
if menuLimit == 0:
menuLimit = None
renpy.jump(target)
renpy.jump(origin)
label start:
$ shkaf = None
$ ulicha = None
$ cherdak = None
$ menuLimit = 0
"Телефонный звонок и от туда голос"
"Маньяк" "Я нашел тебя…"
"Маньяк" "Я уже у тебя в доме…"

406
2018 Ren’Py

"Маньяк" "Спасай свою жизнь ХА-ХА-ХААХАХАХ!!!"


$ menuLimit = 4 #Пункты меню
$ menuManager = renpy.curry(dynamicMenuManager)
label dynamicMenu1:
"В дом проник маньяк, быстрей убегай из дома!!!"
$ ui.timer(2.0, menuManager("dynamicMenu1", "set2"))
menu:
"Быстрей!!! Выбери куда бежать!!!!"
"Спрятаться в шкафу" if menuLimit >= 1:
"Бежать к шкафу"
$ shkaf = True
jump set1
" Проигнорировать звонок " if menuLimit >= 2:
"Ты бросила трубку, мало ли придурков могут звонить"
jump set2
"Залезть на чердак" if menuLimit >= 3:
"Ты побежала на чердак…"
$ cherdak = True
jump set1
" Пойти на балкон " if menuLimit >= 4:
" Надо покурить"
$ ulicha = True
jump set1
label set2: ###Не правильный выбор и по времени не уложились
"Девушка" "Я что то услышала сзади…"
"*Чмяк*"
407
2018 Ren’Py

"И на пол упало женское тело"


return
label set1:
"Только ты зашла, и услышала в доме чьи-то шаги…"
Его можно и подругому сделать, а как именно смотрите разделы
таймеры.

СОЗДАЕМ ХЕНТАЙ ЦЕНЗУРУ


#Где-нибудь в script.rpy создайте переменные:
....$ hentai = False
....$ censored = True # Цензура по умолчанию

#Затем в screen preferences создадим две кнопки:


....label _("Цензура")
....textbutton _("Да") action SetVariable("censored", True),
SetVariable("hentai", False)
....textbutton _("Нет") action SetVariable("hentai", True),
SetVariable("censored", False)

И в script-е объявляем изображения:

init:
image hentai = "hentai.png"
image censored = "censored.png"

#Делаем простую проверочку:


label start:
if hentai == True and censored == False:
show hentai with fade
else:

408
2018 Ren’Py

show censored with fade

СОХРАНЯЕМ И ЗАГРУЖАЕМСЯ ПРЯМО ИЗ


СКРИПТА
init python:
# сохранение i - номер слота на странице № page
def FSave(i=1, page="1"):
file_name = FileSlotName(i, 10)
file_time = FileTime(i, empty=_("Empty Slot."))
save_name = FileSaveName(i)
FileSave(i, page=page, confirm=False)()
# загрузка (по умолчанию грузим 1 слот с "1" страницы)
# но можно и со страниц "quick" и "auto"
def FLoad(i=1, page="1"):
FileLoad(i, page=page, confirm=False, newest=False)()

label start:
"Text1"

$ FSave()
"Text2"

"Text3"

$ FLoad()
return

НАСТРАИВАЕМ ГЛАВНОЕ МЕНЮ

СОЗДАЕМ КНОПКУ ПРОДОЛЖИТЬ ИГРУ И


ТЕКСТ ПОДТВЕЖДЕНИЯ

1 ВАРИАНТ
409
2018 Ren’Py

Для начала сделаем запись в самом начале сценария script.rpy


label main_menu:
call screen main_menu

label restart:
call screen confirm(message=u"Точно хотите начать игру заново?",
yes_action=Start(), no_action=Jump("main_menu"))
### активацию автосохранения:
init -1 python hide:
config.has_autosave = True

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

screen navigation():

vbox:
style_prefix "navigation"

410
2018 Ren’Py

xpos gui.navigation_xpos
yalign 0.5

spacing gui.navigation_spacing

if main_menu:

textbutton _("Начать игру") action Jump("restart")

else:

textbutton _("История") action ShowMenu("history")

textbutton _("Сохранить") action ShowMenu("save")

textbutton _("Продолжить игру") action FileLoad(1, confirm=False,


page="auto", newest=True)

textbutton _("Загрузить игру") action ShowMenu("load")

textbutton _("Настройки") action ShowMenu("preferences")

Что мы тут записали:


При нажатии на кнопку Начать игру мы вызываем метку рестарт, в котором
высвечивается сообщение экрана уведомления(confirm – на новых, на старых
- yesno_prompt ) в котором у вас уточняют хотите ли вы начать новую игру.
А нажимая на кнопку Продолжить игру мы автоматически загружаем
последнее авто сохранение. Благодоря тому, что мы прописали активацию
автосохранения, у нас загрузится наше последнее место на котором мы
остановились.

2 ВАРИАНТ
411
2018 Ren’Py

# действие - продолжить игру оттуда, где закончили


# если загружать пока нечего, то кнопка неактивна
# textbutton _("Продолжить игру") action Continue()
init -999 python
class Continue(Action, DictEquality):
def __call__(self):
FileLoad(1, confirm=False, page="auto", newest=True)()
# кликабельность кнопки
def get_sensitive(self):
return FileLoadable(1, page="auto")

СОЗДАЕМ ПАУЗУ В ПРОЕКТЕ


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

screen pause_menu:
tag menu
vbox:
pos (0.5, 0.5)
anchor (0.5, 0.5)
textbutton _("Continue") action Return()
textbutton _("Save Game") action ShowMenu("save")
textbutton _("Load Game") action ShowMenu("load")
textbutton _("Preferences") action ShowMenu("preferences")
textbutton _("Main Menu") action MainMenu()
textbutton _("Help") action Help()
textbutton _("Quit") action Quit()
412
2018 Ren’Py

Это самый простой экран, вам самостоятельно потребуется его


украсить
Теперь сразу после метки старт пропишите следующее
label start:
$ _game_menu_screen = "pause_menu"
Сохраните и запустите проект. И при нажатии на правую кнопку и
эскейп у вас васветится экран паузы.
Так же бывают моменты когда требуется что бы пользователь не мог
вызвать этот экран. Для этого пишут:
$ _game_menu_screen = None ###нельзя вызвать

#сценна

$ _game_menu_screen = "pause_menu"###можем вызывать

КРАСИВЫЙ ПЕРЕХОД ДЛЯ ГЛАВНОГО


МЕНЮ
screen main_menu:
# отключаем переход
timer sec repeat False action SetVariable("moving", False)

# Это заменяет другие меню.


tag menu

# Фон главного меню.


window:
style "mm_root"

# Кнопки главного меню.


style_group "mm"

# если переход, то двигаем кнопки


if moving:
textbutton _("Назад ") align (0.0, 1.0) at alpha_out action Return()
textbutton _("Меню ") align (0.2, 1.0) at alpha_out action MainMenu()

413
2018 Ren’Py

textbutton _("Играть") at align_to(0.4, 1.0, 1.0, 0.7) action Start()


textbutton _("Загр. ") at align_to(0.6, 1.0, 1.0, 0.8) action
[SetVariable("moving", True), ShowMenu("load")]
textbutton _("Настр.") at align_to(0.8, 1.0, 1.0, 0.9) action
[SetVariable("moving", True), ShowMenu("preferences")]
textbutton _("Выход ") at align_to(1.0, 1.0, 1.0, 1.0) action
Quit(confirm=False)
# иначе они сразу стоят на месте
else:
textbutton _("Играть") align(1.0, 0.7) action Start()
textbutton _("Загр. ") align(1.0, 0.8) action [SetVariable("moving",
True), ShowMenu("load")]
textbutton _("Настр.") align(1.0, 0.9) action [SetVariable("moving",
True), ShowMenu("preferences")]
textbutton _("Выход ") align(1.0, 1.0) action Quit(confirm=False)

init -2 python:

# Сделать все кнопки главного меню одноразмерными.


style.mm_button.size_group = "mm"

init:
python:
style.button.xminimum = 128
style.mm_button.xminimum = 128
style.gm_nav_button.xminimum = 128
# переменная указывает, что осуществляется переход
moving = False
# длительность перехода
sec = 0.5
# переходы
transform align_to(old_x, old_y, new_x, new_y):
align(old_x, old_y)
easein sec align(new_x, new_y)
transform alpha_in:
alpha 0.0
easeout sec alpha 1.0
transform alpha_out:
alpha 1.0
easein sec alpha 0.0

screen navigation:

414
2018 Ren’Py

# отключаем переход
timer sec repeat False action SetVariable("moving", False)
# Фон игрового меню.
window:
style "gm_root"

# Кнопки.
style_group "gm_nav"

# если переход, то двигаем кнопки


if moving:
textbutton _("Назад ") at alpha_in align(0.0, 1.0) action
[SetVariable("moving", True), Return()]
textbutton _("Меню ") at alpha_in align(0.2, 1.0) action
[SetVariable("moving", True), MainMenu()]
textbutton _("Настр.") at align_to(1.0, 0.7, 0.4, 1.0) action
ShowMenu("preferences")
textbutton _("Сохр. ") at align_to(1.0, 0.8, 0.6, 1.0) action
ShowMenu("save")
textbutton _("Загр. ") at align_to(1.0, 0.9, 0.8, 1.0) action
ShowMenu("load")
textbutton _("Выход ") at align_to(1.0, 1.0, 1.0, 1.0) action Quit()
# иначе они сразу стоят на месте
else:
textbutton _("Назад ") align (0.0, 1.0) action [SetVariable("moving",
True), Return()]
textbutton _("Меню ") align (0.2, 1.0) action [SetVariable("moving",
True), MainMenu()]
textbutton _("Настр.") align (0.4, 1.0) action
ShowMenu("preferences")
textbutton _("Сохр. ") align (0.6, 1.0) action ShowMenu("save")
textbutton _("Загр. ") align (0.8, 1.0) action ShowMenu("load")
textbutton _("Выход ") align (1.0, 1.0) action Quit()

МЕНЯЕМ ИЗОБРАЖЕНИЕ РАБОЧЕГО СТОЛА


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

415
2018 Ren’Py

И рекомендую прописать вопрос, мол вам предлогается сменить фон


главного меню – вы согласны? А то возврат старого изображения не
работает на 10 виндовсе, хотя на 7 работает четко, и есть
возможность потерять фоновое изображение.

init python:
import ctypes, os
# здесь лежат старые обои:
def_wall_fn = os.getenv("APPDATA") +
"/Microsoft/Windows/Themes/TranscodedWallpaper.jpg"
# папка с картинками игры
imgs_path = config.basedir + "/game/images/"
# копируем старые обои в папку картинок
temp_wall_fn = imgs_path + "TranscodedWallpaper.jpg"
os.system ('copy "%s" "%s"' % (def_wall_fn, temp_wall_fn))
# функция для смены обоев
def set_wall(name):
fn = imgs_path + name
ctypes.windll.user32.SystemParametersInfoW(20, 0, fn, 0)
# функция для возвращения старых обоев
def res_wall():
ctypes.windll.user32.SystemParametersInfoW(20, 0, temp_wall_fn, 0)

label start:
# сменить обои
$ set_wall("wallpaper.jpg")
pause
# вернуть прежние
$ res_wall()
return

РАЗНЫЕ ФОНЫ ДЛЯ ГЛАВНОГО МЕНЮ В


ЗАВИСИМОСТИ ОТ КОНЦОВОК

#script.rpy:
label start:
"Смена фона в прямой зависимости от концовки."

416
2018 Ren’Py

menu:
"Первыйнах.":
$ persistent.ending = "first"
"Второй.":
$ persistent.ending = "second"
"Вернуть основной фон.":
$ persistent.ending = "main"
return

#screens.rpy:
screen main_menu:
# Это заменяет другие меню.
tag menu
# Фон главного меню.
window:
style "mm_root"
if persistent.ending == None:
$ persistent.ending = "main"
background ("images/mm-%s.jpg" % (persistent.ending))
# и т.д.

ФОН МЕНЮ ОТ ВРЕМЕНИ СУТОК НА


КОМПЬЮТЕРЕ

(http://renpyfordummies.blogspot.ru/2015/01/blog-post.html)

#окно игры – в центр экрана


init python hide:
import os
os.environ['SDL_VIDEO_CENTERED'] = '1'

417
2018 Ren’Py

init:
# свет для каждого времени суток
image day = Null()
image morning = "#8404"
image evening = "#0484"
image night = "#000b"
# спрайт, фон
image man = "man.png"
image bg = "bg.jpg"

# функция, переводящая системное время в название времени суток


init python:
import datetime
def gett():
h = int(datetime.datetime.now().strftime("%H"))
res = "night" # по умолчанию ночь
# границы любого времени суток можно поменять
if (h > 6) and (h < 11):
res = "morning"
if (h >= 11) and (h <= 18):
res = "day"
if (h > 18) and (h < 23):
res = "evening"
return res
# чтобы фон меню зависел от текущего времени суток,
# в раздел main_menu в screens.rpy добавить строку:
# add "%s" % (gett())

# пример для игры, а не для системных часов


label start:
scene bg
show man

show morning as light

418
2018 Ren’Py

"Утро."

show day as light


"День."

show evening as light


"Вечер."

show night as light


"Ночь."
return

КАК ВЫВЕСТИ НА ЭКРАН ВРЕМЯ,


ПРОВЕДЕННОЕ В ИГРЕ

В отличие от renpy.get_game_runtime () мой способ не сбрасывает


время при перезапуске игры или при выходе в меню. Время считается
всегда. Но лучше добавить изображение таймера в главное меню,
чтобы при запуске начался отсчет, а при выходе счетчик сохранился в
постоянные данные.
init python:
import datetime
# время старта текущей сессии игры = время последней проверки
persistent.game_last_time = datetime.datetime.now()
# общее время в игре в секундах
if persistent.gametime is None:
persistent.gametime = 0
# функция для отображения текущего общего времени в игре
def show_gametime(st, at):
# сколько прошло со времени последней проверки
t = datetime.datetime.now()
dt = t - persistent.game_last_time
# запоминаем текущее время, как время последней проверки
419
2018 Ren’Py

persistent.game_last_time = t
# суммируем время в игре со временем с последней проверки
persistent.gametime += dt.total_seconds() # в секундах
# переводим секунды в часы, минуты, секунды
minutes, seconds = divmod(int(persistent.gametime), 60)
hours, minutes = divmod(minutes, 60)
# переводим текст в изображение
# с форматированием (добавлением нулей, если число не двузначное)
img = Text("%0*d:%0*d:%0*d" % (2, hours, 2, minutes, 2, seconds))
# на выходе изображение со временем
return img, .1
init:
# привязываем функцию к динамическому изображению,
# чтобы счетчик тикал без обновления экранов
image gametime = DynamicDisplayable(show_gametime)

screen scr_game_time:
# эту же строку можно добавить и в главное меню:
add "gametime" align(.95, .05)

# для сброса времени в игре:


# $ persistent.gametime = 0
# или привязать к кнопке:
# textbutton _("Сброс времени") action SetField(persistent, "gametime", 0)

# Игра начинается здесь.


label start:
show screen scr_game_time
"Текст игры."
return

КАК ОТОБРАЗИТЬ % ПРОЙДЕННОЙ ИГРЫ

420
2018 Ren’Py

1 ВАРИАНТ

init python:
def percent():
global result
result = seen * 100 / dialogue
label start:
$ result = 0
$ dialogue = renpy.count_dialogue_blocks()
$ seen = renpy.count_seen_dialogue_blocks()

и вызвать результат
$ percent()
"[result]\%"

2 ВАРИАНТ

init:
default seen = renpy.count_seen_dialogue_blocks()
default dialogue = renpy.count_dialogue_blocks()
default result = seen * 100 / dialogue

затем в screen.rpy, в экране main_menu добавил это

vbox:
xpos 0.02 ypos 0.98
xanchor 0.0 yanchor 1.0
$ percent = "Finished: [result]%"
text percent xalign 0.5

КАК ОТОБРАЗИТЬ ТЕКУЩЕЕ ВРЕМЯ НА ПК

# часы с секундами на любом экране

screen clock_scr:

add "clock" align(1.0, 0)

init:

421
2018 Ren’Py

python:

def show_clock(st, at):

import datetime

return Text(datetime.datetime.now().strftime("%H:%M:%S")), .1

image clock = DynamicDisplayable(show_clock)

label start:

show screen clock_scr

pause

ДОБАВЛЯЕМ ВЫБОР СТИЛЯ ДЛЯ QUICK MENU

############################################################
##################
# Quick Menu
#
# Экран, входящий в экран save и дающий некоторые полезные
функции
screen q1:
hbox:
style_group "quick"
xalign 1.0
yalign 1.0
textbutton _("Назад") action Rollback()
textbutton _("Сохранить") action ShowMenu('save')
textbutton _("Настр") action ShowMenu('preferences')
textbutton _("Пропуск") action Skip()
textbutton _("Вид") action SetField(persistent, "qm", "q2")
screen q2:
hbox:
style_group "mm"
xalign 1.0
yalign 1.0
textbutton _("Назад") action Rollback()
textbutton _("Настр") action ShowMenu('preferences')
textbutton _("Вид") action SetField(persistent, "qm", "q1")
screen quick_menu:

422
2018 Ren’Py

if persistent.qm == "q1":
use q1
if persistent.qm == "q2":
use q2

init -2 python:
if persistent.qm == None:
persistent.qm = "q2"

ДОБАВЛЯЕМ В НАСТРОЙКИ РАЗМЕР


ТЕКСТА

https://yadi.sk/d/pnm13XXL35aSWN

# screens.rpy
screen preferences:
tag menu
# и т.д. содержимое экрана
#...
# в самом конце добавляем этот код:
frame:
style_group "pref"
has vbox
label _("Размер текста %s" % (ts_min + persistent.ts))
bar value FieldValue(persistent, "ts", ts_max - ts_min)
on 'hide' action SetTS()
on 'replace' action SetTS()

init python:
# размеры шрифта
ts_min = 16 # от сих
ts_max = 48 # до сих
if persistent.ts is None:
persistent.ts = 0
def setts():
style.default.size = ts_min + persistent.ts
style.rebuild()
SetTS = renpy.curry(setts)
423
2018 Ren’Py

setts()

и пример для кнопок. это в init python:

def setts(ts):
__persistent.ts = ts
__style.default.size = ts
__style.rebuild()
SetTS = renpy.curry(setts)
всё, теперь можно вызывать любой кнопкой. например:
textbutton _("Мелкий шрифт") action SetTS(22)
textbutton _("Средний шрифт") action SetTS(28)
textbutton _("Крупный шрифт") action SetTS(36)

ПРОПИСЫВАЕМ НЕСКОЛЬКО РАЗРЕШЕНИЙ


ЭКРАНА В ПРОЕКТ.
init python:
# своя версия команды show
def my_show(name, at_list=[], layer=None, what=None, zorder=None,
tag=None, behind=[], atl=None, transient=False, munge_name=True):
# добавляем в хвост имени разрешение
name = name + ("x" + str(config.screen_width) + "x" +
str(config.screen_height), )
# вызываем стандартную команду show
renpy.show(name, at_list, layer, what, zorder, tag, behind, atl,
transient, munge_name)
# меняем вызов команды show на наш вариант
config.show = my_show
# смена разрешения
def resolution(w = 800, h = 600):
config.screen_width, config.screen_height = (w, h)
# перерисовка окна (способ дурацкий, но другого не придумалось)
fs = _preferences.fullscreen
Preference("display", 1.0)()
if fs:

424
2018 Ren’Py

Preference("display", "fullscreen")()
# превращаем в action, чтобы можно было привязать к кнопке
Resolution = renpy.curry(resolution)
init:
image cg x800x600 = "images/cg_x800x600.jpg"
image cg x1920x1080 = "images/cg_x1920x1080.jpg"
label start:
show cg
pause
$ resolution(1920, 1080)
show cg
pause
$ resolution(800, 600)
return

КАК СОЗДАТЬ РАЗДЕЛ ПОВТОР СЦЕНЫ


label meaning_of_life:

scene

"Mage" "What is the meaning of life, you say?"

"Mage" "I've thought about it long and hard. A long time, I've
spent pondering that very thing."

"Mage" "And I'll say - the answer - the meaning of life


itself..."

"Mage" "Is forty-three."

$ renpy.end_replay()

"Mage" "Something like that, anyway."

И потом создаем кнопку

textbutton "The meaning of life" action Replay("meaning_of_life"

425
2018 Ren’Py

КАК СОЗДАТЬ ПАПКУ И КИНУТЬ ТУДА


ИЗОБРАЖЕНИЯ

init python:
def unarchive(original_filename, new_filename):
import os
import os.path

new_filename = config.basedir + "/" + new_filename


dirname = os.path.dirname(new_filename)

if not os.path.exists(dirname):
os.makedirs(dirname)

orig = renpy.file(original_filename)
new = file(new_filename, "wb")

new.write(orig.read())

new.close()
orig.close()

426
2018 Ren’Py

label start:
$ unarchive("images/hitry_tits.png", "bonus/hitry_tits.png")

КАК УДАЛИТЬ ФАЙЛ/ПАПКУ ИЗ РЕНПАЯ

# At the start of script.rpy, add this code:


init python:
import os

# Then, when you wish to delete files etc., try this.


label start:
python:
os.remove('Desktop/MyFile.png')
# Specify the file path as well
Папку
init python:
import shutil

label start:
python:
shutil.rmtree('DesktopDay')
# This would remove the Desktop directory if I ran it properly

КАК ПЕРЕЗАГРУЗИТЬ ПРОЕКТ В ГЛАВНОЕ МЕНЮ

Используют следующие команды


$ renpy.utter_restart()
и
$ renpy.full_restart()

КАК УБРАТЬ КУРСОР ВО ВРЕМЯ ИГРЫ

427
2018 Ren’Py

Как сделать, чтобы курсор исчез с экрана во время игры:


$ config.mouse_hide_time = 10 # Исчезновение курсора через 10 сек (время можно
менять)

ИЗУЧАЕМ ПИТОН
Что бы у вас было понимание, что значит та или иная питоновская
функция, которая будет использована в данной книге, мы кратко
изучим базу по питону.
Python – один из тех редких языков программирования, которые
одновременно претендует на звание простых и мощных. Вас приятно
удивит то, как легко можно сосредоточиться на решении поставленной
задачи, а не на синтаксисе и структуре языка, на котором вы
программируете.

Официально Python представляют так:

Python – это простой в освоении и мощный язык программирования.


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

История названия
Гвидо ван Россум, создатель языка Python, назвал его так в честь
телешоу на
BBC под названием «Летающий цирк Монти Пайтона»1, а вовсе не
потому,

428
2018 Ren’Py

что он любит змей, убивающих животных обвиванием своего длинного


тела вокруг них и задавливанием.

ОСОБЕННОСТИ PYTHON

1.Простота
Python – простой и минималистичный язык. Чтение хорошей
программы на Python
очень напоминает чтение английского текста, хотя и достаточно
строгого! Такая псевдо-кодовая природа Python является одной из его
самых сильных сторон. Она позволяет вам сосредоточиться на
решении задачи, а не на самом языке.

2.Лёгкий в освоении
Как вы увидите, на Python чрезвычайно легко начать
программировать. Python обладает исключительно простым
синтаксисом, как уже отмечалось выше.

3.Свободный и открытый
Python – это пример свободного и открытого программного
обеспечения – FLOSS
(Free/Libré and Open Source Soware). Проще говоря, вы имеете
право свободно распространять копии этого программного
обеспечения, читать его исходные тексты, вносить изменения, а также
использовать его части в своих программах. В основе свободного ПО
лежит идея сообщества, которое делится своими знаниями. Это одна
из причин, по которым Python так хорош: он был создан и постоянно
улучшается сообществом, которое просто хочет сделать его лучше.

4. Язык высокого уровня


При написании программы на Python вам никогда не придётся
отвлекаться на такие низкоуровневые детали, как управление
памятью, используемой вашей программой, и т.п.

5.Интерпретируемый
Это требует некоторого пояснения.
Программа, написанная на компилируемом языке программирования,
как например, C или C++, преобразуется из исходного языка (т.е. C
или C++) в язык, понятный компьютеру (бинарный код, т.е. нули и
единицы) при помощи компилятора с применением разнообразных
флагов и параметров. Когда вы запускаете такую программу,

429
2018 Ren’Py

компоновщик/загрузчик копирует программу с диска в оперативную


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

6.Объектно-ориентированный
Python поддерживает как процедурно-ориентированное, так и
объектно-
ориентированное программирование. В процедурно-
ориентированных языках программы строятся на основе процедур
или функций, которые представляют собой просто-напросто
многократно используемые фрагменты программы. В объектно-
ориентированных языках программирования программы строятся на
основе объектов, объединяющих в себе данные и функционал. Python
предоставляет простые, но мощные средства для ООП, особенно в
сравнении с такими большими языками программирования, как C++
или Java.

7.Расширяемый
Если вам нужно, чтобы некоторая критическая часть программы
работала очень быстро или вы вынуждены скрыть часть алгоритма,
вы можете написать эту часть программы на C или C++, а затем
вызывать её из программы на Python.

8. Встраиваемый
Python можно встраивать в программы на C/C++, чтобы предоставлять
возможности на писания сценариев их пользователям.

9. Обширные библиотеки
Стандартная библиотека Python просто огромна. Она может помочь в
решении самых разнообразных задач, связанных с использованием
регулярных выражений, генерированием документации, проверкой
блоков кода, распараллеливанием процессов, базами данных, веб-
браузерами, CGI, FTP, электронной почтой, XML, XML-RPC, HTML,
WAV файлами, криптографией, GUI (графическим интерфейсом

430
2018 Ren’Py

пользователя) и другими системно-зависимыми вещами. Помните, что


всё это доступно абсолютно везде, где уста-
новлен Python. В этом заключается философия Python “Всё
включено”.
Кроме стандартной библиотеки, существует множество других
высококачественных библиотек, которые можно найти в Каталоге
пакетов Python
https://pypi.python.org/pypi

Питер Норвиг – широко известный автор Lisp, а также директор по


качеству поиска в Google. Он говорит, что Python всегда был
неотъемлемой частью Google. Вы можете убедиться в этом, заглянув
на страницу Google Jobs http://www.google.com/jobs/index.html, на
которой владение Python указано как требование для разработчиков
программного обеспечения.

СТИЛЬ ПРОГРАММИРОВАНИЯ

Итак, вы постепенно начинаете писать более длинные программы, и


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

РЕКОМЕНДАЦИИ ПО СТИЛЮ

Когда кто-нибудь хочет внести изменения в язык Python, он пишет


документ PEP (Python Enhancement Proposal). Одним из самых старых
PEP является документ PEP 8 с рекомендациями по стилевому

431
2018 Ren’Py

оформлению кода. PEP 8 имеет довольно большую длину, но


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

ОТСТУПЫ

PEP 8 рекомендует обозначать уровень отступа четырьмя пробелами.


Использование четырех пробелов упрощает чтение программы и при
этом оставляет достаточно места для нескольких уровней отступов в
каждой строке.
В программах форматирования текста для создания отступов часто
используются табуляции вместо пробелов. Такой способ хорошо
работает в текстовых процессорах, но интерпретатор Python приходит
в замешательство, когда табуляции смешиваются с пробелами. В
каждом текстовом редакторе имеется параметр конфигурации,
который заменяет нажатие клавиши табуляции заданным количеством
пробелов. Конечно, клавиша табуляции удобна, но вы должны
проследить за тем, чтобы редактор вставлял в документ пробелы
вместо табуляций.
Смешение табуляций и пробелов в файле может создать проблемы,
сильно затрудняющие диагностику. Если вы думаете, что в программе
табуляции смешались с пробелами, помните, что в большинстве
редакторов существует возможность преобразования всех табуляций
в пробелы. Многие программисты Python рекомендуют ограничивать
длину строк 80 символами. Исторически эта рекомендация появилась
из-за того, что в большинстве компьютеров в одной строке
терминального окна помещалось всего 79 символов. В настоящее
время на экранах помещаются куда более длинные строки, но для

432
2018 Ren’Py

применения стандартной длины строки в 79 символов существуют и


другие причины. Профессиональные программисты часто открывают
на одном экране сразу несколько файлов; стандартная длина строки
позволяет видеть все строки в двух или трех файлах, открытых на
экране одновременно. PEP 8 также рекомендует ограничивать
комментарии 72 символами на строку, потому что некоторые
служебные программы, автоматически генерирующие документацию в
больших проектах, добавляют символы форматирования в начале
каждой строки комментария. Рекомендации PEP 8 по выбору длины
строки не являются незыблемыми, и некоторые программисты
предпочитают ограничение в 99 символов. Пока вы учитесь, длина
строки в коде не так важна, но учтите, что при совместной работе в
группах почти всегда соблюдаются рекомендации PEP 8. В
большинстве редакторов можно установить визуальный ориентир
(обычно вертикальную линию на экране), показывающий, где проходит
граница.

ПУСТЫЕ СТРОКИ

Пустые строки применяются для визуальной группировки частей


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

Пустые строки не влияют на работу кода, но отражаются на его


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

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

433
2018 Ren’Py

ЗАЧЕМ НУЖЕН БЛОК INIT?

В любом проекте есть информация, такая как используемые


изображения и персонажи, которая должна быть определенна до
собственно начала истории. Такая информация объявляется в блоке
init. Он может находиться в коде где угодно, но обычно его помещают
в самое начало. Этот блок начинается со строчки:

init:

записанной без отступа, и все строчки с отступом, следующие за ней,


принадлежат блоку init. Строчек этих может быть любое количество.
Заканчивается блок первой же строкой БЕЗ отступа. И эта строка,
конечно же, блоку init уже не принадлежит.

КАК ВЫЗЫВАТЬ КОДЫ ПИТОНА В РЕНПАЕ.


Переменные, у которых значения изменяются, пишут через $ или
python

label start:
$ gul = True
$ money = 0
И еще как пример(именно его и рекомендую если больше 1
переменной требуется указать, так как у $ минус, каждую строку
придется со знаком доллара прописывать)
label start:
python:
n=0
n1 = 0
money = 0
434
2018 Ren’Py

normani = False
vostok = False
kiev = False
doom = 0
db = 0
И их пишут обычно сразу в метке start что бы избежать многих ошибок,
которые возникают из за того, что ренпай не видит нужную вам
переменную.

Переменные, у которых значение не меняются – ВСЕГДА ПИШУТ


ЧЕРЕЗ ИНИТ И ИХ ПИШУТ ДО МЕТОК

init:
first_name = 'Безымянный!t'
input_first_name = 'Иван!t'
input_last_name = 'Иванов!t'
label start:
….

А вызываются переменные в текст-диалога в квадратных скобках


label start:
$ zakaz = 'Компот'
"Я заказал пиво"
"А привезли [zakaz]"

СВЯЗКА IF, ELIF, ELSE


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

435
2018 Ren’Py

Команда if в языке Python позволяет проверить текущее состояние


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

Команда elif позволяет выбрать еще варианты действий. Код может


содержать сколько угодно блоков elif.

Команда else выполняет единственный вариант действий, который не


перечислили в if и elif

После if или elif всегда пишется переменная с ее значениями и на


конце двоеточие, т.е. мы прописываем события при таком то условии
if gul == 1:

Если вы хотите, чтобы в программе выполнялся только один блок


кода, — используйте цепочку if-elif-else.
Если же выполняться должны несколько блоков, используйте серию
независимых команд if

В этой главе вы научитесь писать условные проверки для любых


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

ОСНОВНЫЕ ДЕЙСТВИЯ С ПЕРЕМЕННЫМИ


Оператор Название Обьяснение Пример
+ Сложение Суммирует 2 обьекта 3 + 2 даст 5, а
'a' + 'b' даст 'ab'
- Вычитание Даёт разность двух -5.2 даст
чисел; если первый отрицательное число,
операнд отсутствует, а 50 - 24 даст 26.
он считается равным
нулю

436
2018 Ren’Py

* Умножение Даёт произведение 2 * 3 даст 6.


двух чисел или а 'la' * 3 даст 'lalala'.
возвращает строку,
повторённую заданное
число раз.
** Возведение в степень Возвращает число х, 3 ** 4 даст 81 (т.е. 3 * 3
возведённое в степень * 3 * 3)
y
/ Деление Возвращает частное от 4 .0 / 3 даст
деления x на y 1.3333333333333333.
// Целочислительное Возвращает неполное 4 // 3 даст 1.
деление частное от деления
% Деление по модулю Возвращает остаток от 8 % 3 даст 2.
деления -25.5 % 2.25 даст 1.5.
<< Сдвиг влево Сдвигает биты числа 2 << 2 даст 8.
влево на заданное В двоичном виде 2
количество позиций. представляет собой
(Любое число в памяти 10. Сдвиг влево на 2
компьютера бита даёт 1000, что в
представлено в виде десятичном виде
битов или двоичных означает 8.
чисел, т.е. 0 и 1)
>> Сдвиг в право Сдвигает биты числа 11 >> 1 даст 5. В
вправо на заданное двоичном виде 11
число позиций. представляется как
1011, что будучи
смещённым на 1 бит
вправо, даёт 101, а
это, в свою очередь,
ни что иное как
десятичное 5
& Побитовое И Побитовая операция 5 & 3 даёт 1.
И над числами
| Побитовое ИЛИ Побитовая операция 5 | 3 даёт 7
ИЛИ над
числами
^ Побитовое Побитовая операция 5 ^ 3 даёт 6
ИСКЛЮЧИТЕЛЬНО ИСКЛЮЧИТЕЛЬНО
ИЛИ ИЛИ
~ Побитовое НЕ Побитовая операция ~5 даёт -6.
НЕ для числа x
соответствует -(x+1)
< Меньше Определяет, верно ли, 5 < 3 даст False,
что x меньше y. Все а 3 < 5 даст True.
операторы сравнения Можно составлять
возвращают True произвольные цепочки
или False 1. Обратите сравнений: 3 < 5 < 7
внимание на даёт True.
заглавные буквы в
этих словах.
<= Меньше или равно Определяет, верно ли, x = 3; y = 6; x <= y даёт
что x меньше или True.
равно y
>= Больше или равно Определяет, верно ли, x = 4; y = 3; x >= 3 даёт
что x больше или True.
равно y
== Равно Проверяет, одинаковы x = 2; y = 2; x == y даёт
ли объекты True. x = 'str'; y = 'stR';
x == y даёт False. x =

437
2018 Ren’Py

'str';
y = 'str'; x == y даёт
True.
!= Не равно Проверяет, верно ли, x = 2; y = 3; x != y даёт
что объекты не равны True.
not Логическое НЕ Если x равно True, x = True; not x даёт
оператор вернёт False. False.
Если же x равно
False, получим True.
and Логическое И x and y даёт False, x = False; y = True; x
если x равно False , в and
противном случае y возвращает False,
возвращает значение y поскольку
x равно False. В этом
случае Python не
станет проверять
значение y, так как уже
знает, что левая часть
выражения ‘and’
равняется False, что
подразумевает, что и
всё выражение в
целом будет
равно False,
независимо от
значений всех
остальных
операндов. Это
называется
укороченной оценкой
булевых (логических)
выражений.
or Логическое ИЛИ Если x равно True, в x = True; y = False; x or
результате получим y
True, в противном даёт True. Здесь также
случае получим может
значение y производиться
укороченная оценка
выражений.

Разделы у которых новичков чаще всего возникают вопросы что


и как
Изменение значений
1) $ rep +=1 и $ rep -=1 – мы прибавили и отняли значение у
переменной rep
2) $ rep = rep +2 и $ rep = rep -2 – как и первый вариант, + и – к
переменной
3) $ mwar = mwar + renpy.random.choice([1,3]) – к переменной мы
прибавляем случайное значение 1-3

438
2018 Ren’Py

4) умножаем
$ sila = 10
$ ves = 5*ves
"[ves]"
получим 50 веса, но так никто не делает на рпг – ошибки будут
5) делим
$ zashita = 10
$ uron = 2/zashita
"[uron]"
получим 5 урона, но так никто не делает на рпг – ошибки будут
НО обратите внимание!
$ zashita = 2
$ uron = 3/zashita
"[uron]"
Получите 1. Результатом деления целых чисел в Python 2 становится целое
число с потерей остатка. Обратите внимание: результат не округляется,
просто остаток от деления пропадает.

Чтобы избежать этого поведения в Python 2, проследите за тем, чтобы


хотя бы одно из двух чисел было вещественным. В этом случае
результат также будет вещественным:
$ zashita = 2
$ uron = 3.0 / zashita
"[uron]"
Получим 1.5
6) Проверяем неравенство
label start:

439
2018 Ren’Py

$ zakaz = 'Компот'
"Я заказал пиво"
"А привезли [zakaz]"
if zakaz != 'Пиво':
"Я пиво заказывал а не [zakaz]!!!"
7) Устанавливаем степень
$ sila = 10 ** 2
"[sila]"
Получим 100
8) Устанавливаем порядок выполнения скобки
$ sila = 20+(10-5 * 2)

Устанавливаем значение
1) $ rep = 10 и $ rep = -100 – Значение переменной будет равна 10 и -
100, т.е. допустим у персонажа 10 отношений, он украл что то и
отношение сразу стали равны -100
2) $ wolf_hp = wolf_max_hp – значение 1 переменной равна значению
другой

Условие
1) if mmo – При значении True
2) elif mmo == 1 - При точном значении 1
3) if mmo >= 1 или if mmo <= 1 - при равном или большем значении 1
или наоборот
4) if mmo >1 или if mmo < 1 - Если больше 1 или меньше

ЛОГИЧЕСКИЕ ВЫРАЖЕНИЯ [ФЛАГИ]


440
2018 Ren’Py

Логические выражения часто используются для проверки некоторых


условий — например, запущена ли компьютерная игра или разрешено
ли пользователю редактирование некоторой информации.
Флаги – условия, которые изначально прописаны в языке питона

True - верное истинное значение, Логическая истина


False – Логическая ложь, ложное значение
None - ни один, отсутствие значения
В зависимости от результата проверки Python решает, должен ли
выполняться код. Если результат условия равен True, то Python
выполняет код, Если False то Python не выполнит код,
Пример использование кода
label start:
$ gul = True
"Ты будешь гулять сегодня?"
menu:
"Да":
jump da_gul
"Нет":
jump net_gul
label da_gul:
$ gul = True
"Катя" "Хорошо ждем тебя на улице"
jump den_2
label net_gul:
$ gul = False
"Катя" "Жалко… Тогда до завтра"

441
2018 Ren’Py

jump den_2
label den_2:
if gul:
"Катя" "Классно мы вчера с компанией погуляли))) Почаще
выходи с нами )"
else:
"Катя" "Мы вчера так весело погуляли!!! Жалко тебя не было…"
"Учитель" "Показываем ваши домашние задания"
if gul:
"Катя" "Упс…."
"Катя" " Ты тоже спать после прогулки лег?"
else:
"Катя" "Дай списать!!!!! ПОЖАЛУСТА!!!!!"
"Катя" " Ты то точно написал ее!!!"
Разберем, что тут мы записали
После выбора гулять или нет, мы видим после метки значение $ gul =
True.
Значком $ в начале помечают коды питона, переменные. Делаем
такой же отступ, как и на обычный диалог,
$ gul – так мы назвали переменную, а ее логическое выражение True
или False т.е. мы можем так же и цифры, и буквенно-цифровые
значения прописать, самое главное не забыть как вы их записали. И
что бы не было ошибки, вам нужно сделать прыжок к другой
метке(jump den_2), т.к. если после выбора значение флага (=) не
сделать этого - оно примет то условие что будет записано в
следующей метке.
После того как вы сделали выбор, у вас переменная приняла свое
значение (= ) , потом на следующий день включается проверка
переменной (if gul: ) если переменная включена (True) то произойдет
событие которое должно произойти при включенной переменной.
Если нужно значение переменной любое другое кроме тех, что были

442
2018 Ren’Py

прописаны ранее, то пишут (else: - оно так и переводится любое


другое).
Так же посмотрите на отступы фраза "Учитель" "Показываем ваши
домашние задания" и if gul: они стоят на 1 уровне, это значит что
фраза "Учитель" "Показываем ваши домашние задания" будет общей
и для if gul: и для else: и она не попадает под проверку переменной
gul

ЧИСЛОВОЕ ЗНАЧЕНИЕ
До этого мы рассматривали, как прописать флаги, теперь мы
рассмотрим значения числовые.
label start:
$ gul = 0
"Ты будешь гулять сегодня?"
menu:
"Да":
$ gul +=1
jump da_gul
"Нет":
jump net_gul
label da_gul:
"Катя" "Хорошо ждем тебя на улице"
"Во время прогулки ты ее поцелуешь?"
menu:
"Да":
$ gul +=1

443
2018 Ren’Py

"ок"
"Нет":
"ок"
jump den_2
label net_gul:
"Катя" "Жалко… Тогда до завтра"
jump den_2
label den_2:
if gul ==1:
"Катя" "Классно мы вчера с компанией погуляли))) Почаще
выходи в белый свет)
elif gul >1:
"Девушка покраснела когда встретилась взглядом с тобой"
else:
"Катя" "Мы вчера так весело погуляли!!! Жалко тебя не было…"
"Учитель" "Показываем ваши домашние задания"
if gul ==1:
"Катя" "Упс…."
elif gul >1:
"Катя" "*шепотом* Какие блин уроки после вчерашнего...."
else:
"Катя" "Дай списать!!!!! ПОЖАЛУСТА!!!!!"
"Катя" " Ты то точно написал ее!!!"

Теперь рассмотрим что мы тут записали.


В начале строки мы прописываем переменную со значением 0, т.к. мы
только начали ($ gul = 0 ), потом мы выбираем, пойдет он($ gul +=1)

444
2018 Ren’Py

или нет гулять, и пропишем, поцелует он ее($ gul +=1) или нет.
символ =+ обозначает что мы к переменной прибавляем ее значение,
а 1 знак равно будет значить что переменная приняла такое
значение. В отличии от фагов в числах можно кучу событий прописать
и развязок…. и фагами в принципе можно, но это куча лишних
переменных, и еще бы их всех запомнить. А в числовых переменных
можно кучу условий прописать для скрытой концовки всего 1
переменной.
Далее на следующий день у нас должна произойти развязка после
событий.
Что бы заработало по выбранным условиям, нам необходимо
прописать эти условия.
Опять обращаю внимание на фразу "Учитель" "Показываем ваши
домашние задания" она на таком же уровне пишется, как и все
остальные условия
if gul ==1: - Если мы пошли, но не поцеловались, что бы система
прочитала правильно-точное значение то пишут знак = два раза( = =
)
elif gul >1: - Если нужно прописать еще одно возможное событие то
его необходимо записать в elif, и что бы его значение было больше 1
то пишут >1: (больше 1) или пишут (равен или больше 2) =>2: или
(точное значение) ==2
else: - Если не совпадает с предыдущими событиями

ТЕКСТ В ВИДЕ ПЕРЕМЕННОЙ


В переменной можно так же задать и текст, пример такого текста
init:
define ger = Character(_("[name]"), color="#008000", who_suffix = ':')
label start:
python:
age = 23
message = "C " + str(age) + "-ем Братишка!"

445
2018 Ren’Py

name = "серж горелый."


name2 = "Меня зовут - " + name.title() + " Очень приятно
познакомиться."
"[message]"
"[name2]"
ger "А как тебя зовут?"
Как вы заметили, мы прописали несколько вариантов реализации
переменной.
1) Братишку поздравили переменной, которая может в любой момент
может поменять свое значение, что будет довольно актуально,
например, если персонаж спрашивает, какой сегодня день.
Но если прописать message = "C " + age + "-ем Братишка!"
появится ошибка.
На этот раз произошла ошибка типа. Это означает, что Python не
понимает, какую информацию вы используете. В данном примере
Python видит, что используется переменная с целочисленным
значением (int), но не знает, как следует интерпретировать это
значение. Дело в том, что переменная может представлять как число
23, так и пару отдельных символов 2 и 3. При таком использовании
целых чисел в строках необходимо явно указать, что целое число
должно использоваться как строка из символов. Для этого переменная
передается функции str(), преобразующей не-строковые значения к
строковому виду:
message = "C " + str(age) + "-ем Братишка!"
Теперь Python понимает, что вы хотите преобразовать числовое
значение 23 в строку и вывести символы 2 и 3 в составе
поздравления. Ожидаемый результат выводится без всяких ошибок.
2) Прописали переменную, которую можно использовать как имя
персонажа, и в других переменных. Особенно актуально если в
проекте используется ввод имени, оружию имя задается….

446
2018 Ren’Py

ИЗМЕНЕНИЕ РЕГИСТРА СИМВОЛОВ В


СТРОКАХ

В этом примере в переменной name сохраняется строка, состоящая из


букв нижнего регистра "Серж Горелый". За именем переменной
следует вызов метода title().

Метод представляет собой действие, которое Python выполняет с


данными.

Точка (.) после name в конструкции name.title() приказывает Python


применить метод title() к переменной name. За именем метода всегда
следует пара круглых скобок, потому что методам для выполнения их
работы часто требуется дополнительная информация. Эта
информация указывается в скобках. Функции title() дополнительная
информация не нужна, поэтому в круглых скобках ничего нет.

Метод title() преобразует первый символ каждого слова в строке к


верхнему регистру, тогда как все остальные символы выводятся в
нижнем регистре.(т.е. Текст переменной написан мелкими буквами,
метод title() сделает заглавными буквами любой текст)
label start:
python:
name = "серж горелый."
message = name.title()
"[message]"

Например, данная возможность может быть полезна, если в вашей


программе входные значения СеРж ГореЛый, cерж горелый должны
рассматриваться как одно и то же имя, и все они должны
отображаться в виде Серж Горелый.
Для работы с регистром также существуют другие полезные методы.
Например, все символы строки можно преобразовать к верхнему или
нижнему регистру:

label start:

447
2018 Ren’Py

python:
name = "серж горелый."
message = name.title() ###Заглавные буквы
message1 = name.upper() ###Все большое
message2 = name.lower() ###Все маленькое
"[message]"
"[message1]"
"[message2]"
Программа выводит следующий результат:
Серж Горелый
СЕРЖ ГОРЕЛЫЙ
серж горелый
Метод lower() особенно полезен для хранения данных. Нередко
программист не может рассчитывать на то, что пользователи введут
все данные с точным соблюдением регистра, поэтому строки перед
сохранением преобразуются к нижнему регистру. Затем, когда
потребуется вывести информацию, используется регистр, наиболее
подходящий для каждой строки.

КОНКАТЕНАЦИЯ. ОБЪЕДИНЕНИЕ
ПЕРЕМЕННЫХ
Также часто возникает необходимость в объединении строк.
Представьте, что имя и фамилия хранятся в разных переменных, и вы
хотите объединить их для вывода полного имени. Для объединения
строк в Python используется знак «плюс» (+).

label start:
python:
name = "серж"

448
2018 Ren’Py

family = "горелый"
ger = name + " " + family
message = ger.title()
"[message]"
Такой способ объединения строк называется конкатенацией. Вы
можете использовать конкатенацию для построения сложных
сообщений с информацией, хранящейся в переменных.
name2 = "Меня зовут - " + name.title() + " .Очень приятно
познакомиться."

УДАЛЕНИЕ ПРОПУСКОВ
Лишние пропуски могут вызвать путаницу в программах. Для
программиста строки 'python' и 'python ' внешне неотличимы, но для
программы это совершенно разные строки. Python видит лишний
пробел в 'python ' и считает, что он действительно важен — до тех пор,
пока вы не сообщите о противоположном.
Обращайте внимание на пропуски, потому что в программах часто
приходится сравнивать строки, чтобы проверить на совпадение их
содержимое. Типичный пример — проверка имен пользователей при
входе на сайт. Лишние пропуски могут создавать путаницу и в более
простых ситуациях. К счастью, Python позволяет легко удалить
лишние пропуски из данных, введенных пользователем.
Python может искать лишние пропуски у левого и правого края строки.
Чтобы убедиться в том, что у правого края (в конце) строки нет
пропусков, вызовите метод rstrip().

label start:
python:
name = "python "
message = name.rstrip().
"[message]"
И получим текст

449
2018 Ren’Py

python
Операция изменения значения переменной с последующим его
сохранением в исходной переменной часто выполняется в
программировании. Так значение переменной может изменяться в
ходе выполнения программы или в ответ на действия пользователя.
Пропуски также можно удалить у левого края (в начале) строки при
помощи метода lstrip(), а метод strip() удаляет пропуски с обоих
концов
Поэкспериментируйте с функциями удаления пропусков, это поможет
вам освоиться с работой со строками. На практике эти функции чаще
всего применяются для «очистки» пользовательского ввода перед его
сохранением в программе.

СПИСКИ

В этой и следующей главах вы узнаете, что собой представляют


списки и как начать работать с элементами списка. Списки позволяют
хранить в одном месте взаимосвязанные данные, сколько бы их ни
было — несколько элементов или несколько миллионов элементов.
Работа со списками относится к числу самых выдающихся
возможностей Python, доступных для начинающего программиста.
Операции со списками связывают воедино многие важные концепции
в программировании.
Список — это набор элементов, следующих в определенном порядке.
Вы можете создать список для хранения букв алфавита, цифр от 0 до
9 или имен всех членов вашей семьи. В список можно поместить
любую информацию, причем данные в списке даже не обязаны быть
как-то связаны друг с другом.
В языке Python список обозначается квадратными скобками ([]), а
отдельные элементы списка разделяются запятыми.
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None

450
2018 Ren’Py

grid 1 1:
frame:
vbox:
text "Мой список блюд:"
vbox:
for my_food in my_foods:
text "[my_food]"

label start:
window hide
python:
my_foods = ['Пицца', 'Маккароны', 'Тортик']
show screen for_screen
pause
Сохраните и запустите проект.

ОБРАЩЕНИЕ К ЭЛЕМЕНТАМ СПИСКА


Списки представляют собой упорядоченные наборы данных, поэтому
для обращения к любому элементу списка следует сообщить Python
позицию (индекс) нужного Индексы начинаются с 0, а не с 1. Чтобы
обратиться к элементу в списке, укажите имя списка, за которым
следует индекс элемента в квадратных скобках.
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:

451
2018 Ren’Py

vbox:
text "Мой список блюд:"
vbox:
for my_food in my_foods:
text "[my_food]"

label start:
window hide
python:
my_foods = ['Пицца', 'Маккароны', 'Тортик']
show screen for_screen
pause
hide screen for_screen
"Надеюсь никто не откажется от [my_foods[0]]"
pause
У вас высветится пицца в тексте
$ re =my_foods[0].title() – что бы оно было с заглавной буквы
$ mi = "Ты будешь" + my_foods[0].title() + "?"
или
$ mi = "Ты будешь [re]?"

Если запросить элемент с индексом –1, Python всегда возвращает


последний элемент в списке
label start:
window hide
python:

452
2018 Ren’Py

my_foods = ['Пицца', 'Маккароны', 'Тортик']


show screen for_screen
pause
hide screen for_screen
"Надеюсь никто не откажется от [my_foods[0]]"
"Или [my_foods[-1]]а?"
pause
Получим в тексте тортик
Индекс –2 возвращает второй элемент от конца списка и т.д.

ИЗМЕНЕНИЕ ЭЛЕМЕНТОВ В СПИСКЕ


Синтаксис изменения элемента напоминает синтаксис обращения к
элементу списка. Чтобы изменить элемент, укажите имя списка и
индекс изменяемого элемента в квадратных скобках; далее задайте
новое значение, которое должно быть присвоено элементу.
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Мой список блюд:"
vbox:
for my_food in my_foods:
text "[my_food]"

453
2018 Ren’Py

label start:
window hide
python:
my_foods = ['Пицца', 'Маккароны', 'Тортик']
show screen for_screen
pause
python:
my_foods[0] = 'Шашлык'
pause
Изменить можно значение любого элемента в списке, не только
первого.
Пицца Маккароны Тортик###до
Шашлык Маккароны Тортик ###после

ДОБАВЛЕНИЕ ЭЛЕМЕНТОВ В СПИСОК


Новые элементы могут добавляться в списки по разным причинам —
например, для появления на экране новых объектов, включения новых
данных в визуализацию. Python предоставляет несколько способов
добавления новых данных в существующие списки.

ПРИСОЕДИНЕНИЕ ЭЛЕМЕНТОВ В КОНЕЦ


СПИСКА
Простейший способ добавления новых элементов в список —
присоединение элемента в конец списка. Используя список из
предыдущего примера, добавим новый элемент
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None

454
2018 Ren’Py

grid 1 1:
frame:
vbox:
text "Мой список блюд:"
vbox:
for my_food in my_foods:
text "[my_food]"

label start:
window hide
python:
my_foods = ['Пицца', 'Маккароны', 'Тортик']
show screen for_screen
pause
python:
my_foods.append('Шашлык')
pause
Получим
Пицца Маккароны Тортик ###до
Пицца Маккароны Тортик Шашлык ###после
Метод append() упрощает динамическое построение списков.
Например, вы можете начать с пустого списка и добавлять в него
элементы серией команд append(). В следующем примере в пустой
список добавляются элементы блюд:
label start:
window hide
python:
my_foods = [ ]

455
2018 Ren’Py

show screen for_screen


pause
python:
my_foods.append('Пицца')
my_foods.append('Маккароны')
my_foods.append('Тортик')
my_foods.append('Шашлык')
pause

ВСТАВКА ЭЛЕМЕНТОВ В СПИСОК


Метод insert() позволяет добавить новый элемент в произвольную
позицию списка. Для этого следует указать индекс и значение нового
элемента.
label start:
window hide
python:
my_foods = ['Пицца', 'Маккароны', 'Тортик']
show screen for_screen
pause
python:
my_foods.insert(0,'Шашлык')
pause
Получим
Шашлык Пицца Маккароны Тортик

456
2018 Ren’Py

УДАЛЕНИЕ ЭЛЕМЕНТА С
ИСПОЛЬЗОВАНИЕМ КОМАНДЫ DEL
Если вам известна позиция элемента, который должен быть удален из
списка, воспользуйтесь командой del.
label start:
window hide
python:
my_foods = ['Пицца', 'Маккароны', 'Тортик']
show screen for_screen
pause
python:
del my_foods[0]
pause

Пицца Маккароны Тортик###до


Маккароны Тортик###после
Команда del позволяет удалить элемент из любой позиции списка,
если вам известен его индекс.
Значение, удаленное из списка после использования команды del,
становится недоступным.

УДАЛЕНИЕ ЭЛЕМЕНТА С
ИСПОЛЬЗОВАНИЕМ МЕТОДА POP()
Метод pop() удаляет последний элемент из списка, но позволяет
работать с ним после удаления.
screen for_screen():
frame:

457
2018 Ren’Py

xalign 0.5 yalign 0.5


background None
grid 1 1:
frame:
vbox:
text "1 список блюд:"
vbox:
for my_food in my_foods:
text "[my_food]"

label start:
window hide
python:
my_foods = ['Пицца', 'Маккароны', 'Тортик']
show screen for_screen
python:
popped_my_foods = my_foods.pop()
pause
Получаем
Пицца Маккароны Тортик #до
Пицца Маккароны #после
Для чего может понадобиться метод pop()? Представьте, что
мотоциклы в списке хранятся в хронологическом порядке в
соответствии с датой их покупки. В таком случае команда pop() может
использоваться для вывода сообщения о последнем купленном
мотоцикле:
label start:

458
2018 Ren’Py

python:
motorcycle = ['honda', 'yamaha', 'suzuki']
last_owned = motorcycle.pop()
"Список оставшихся мотоциклов"
"[motorcycle]"
"До этого у нас был продан [last_owned]"

ИЗВЛЕЧЕНИЕ ЭЛЕМЕНТОВ ИЗ
ПРОИЗВОЛЬНОЙ ПОЗИЦИИ СПИСКА
Вызов pop() может использоваться для удаления элемента в
произвольной позиции списка; для этого следует указать индекс
удаляемого элемента в круглых скобках.
label start:
python:
motorcycle = ['honda', 'yamaha', 'suzuki']
last_owned = motorcycle.pop(0) ### 0 в скобках
"Список оставшихся мотоциклов"
"[motorcycle]"
"До этого у нас был продан [last_owned]"
Если вы не уверены в том, какой из двух способов выбрать — команду
del или метод pop(), — то простое правило поможет вам определиться.
Если вы собираетесь просто удалить элемент из списка, никак не
используя его, выбирайте команду del; если же вы намерены
использовать элемент после удаления из списка, выбирайте метод
pop().

УДАЛЕНИЕ ЭЛЕМЕНТОВ ПО ЗНАЧЕНИЮ


Иногда позиция удаляемого элемента неизвестна. Если вы знаете
только значение элемента, используйте метод remove().

459
2018 Ren’Py

label start:
python:
motorcycle = ['honda', 'yamaha', 'suzuki', 'ducati']
motorcycles.remove('ducati')

ПОСТОЯННАЯ СОРТИРОВКА СПИСКА


МЕТОДОМ SORT()
Метод sort() позволяет относительно легко отсортировать список.
Предположим, имеется список машин, и вы хотите переупорядочить
эти элементы по алфавиту.
label start:
python:
cars = ['bmw', 'audi', 'toyota', 'subaru']
me = cars.sort()
"[me]"
Названия машин располагаются в алфавитном порядке, и вернуться к
исходному порядку уже не удастся:
[u'audi',u 'bmw', u'subaru', u'toyota']
Список также можно отсортировать в обратном алфавитном порядке;
для этого методу sort() следует передать аргумент reverse=True. В
следующем примере список сортируется в порядке, обратном
алфавитному:
label start:
python:
cars = ['bmw', 'audi', 'toyota', 'subaru']
me = cars.sort(reverse=True)
"[me]"
[u'toyota', u'subaru', u'bmw', u'audi']

460
2018 Ren’Py

ВЫВОД СПИСКА В ОБРАТНОМ ПОРЯДКЕ

Чтобы переставить элементы списка в обратном порядке, используйте


метод reverse(). Скажем, если список машин первоначально хранился в
хронологическом порядке даты приобретения, элементы можно легко
переупорядочить в обратном хронологическом порядке
label start:
python:
cars = ['bmw', 'audi', 'toyota', 'subaru']
me = cars.reverse()
"[me]"
[u'subaru',u'toyota', u'audi', u'bmw']

ОПРЕДЕЛЕНИЕ ДЛИНЫ СПИСКА


Вы можете быстро определить длину списка с помощью функции len().
Список в нашем примере состоит из четырех элементов, поэтому его
длина равна 4:
label start:
python:
cars = ['bmw', 'audi', 'toyota', 'subaru']
me = len(cars)
"[me]"
4
Python подсчитывает элементы списка, начиная с 1, поэтому при
определении длины списка ошибок «смещения на 1» уже быть не
должно.

ПЕРЕБОР ВСЕГО СПИСКА

461
2018 Ren’Py

Типичная задача из области программирования — перебрать все


элементы списка и выполнить с каждым элементом одну и ту же
операцию. Например, в компьютерной игре все экранные объекты
могут смещаться на одинаковую величину, или в списке чисел к
каждому элементу может применяться одна и та же статистическая
операция. А может быть, вам нужно вывести все заголовки из списка
статей на сайте. В ситуациях, требующих применения одного действия
к каждому элементу списка, можно воспользоваться циклами for.
Допустим, имеется список с именами фокусников, и вы хотите вывести
каждое имя из списка. Конечно, можно обратиться к каждому элементу
по отдельности, но такой подход создает ряд проблем. Во-первых, для
очень длинных списков все сведется к однообразным повторениям.
Во-вторых, при любом изменении длины списка в программу придется
вносить изменения. Цикл for решает обе проблемы: Python будет
следить за всеми техническими деталями в своей внутренней реали-
зации.
В следующем примере цикл for используется для вывода имен
фокусников
screen for_screen():
$ magicians = ['alice', 'david', 'carolina']
frame:
xalign 0.5 ypos 50
vbox:
for magician in magicians:
text "[magician]"
label start:
show screen for_screen
Этот код можно описать так: «Для каждого фокусника в списке
вывести его имя». Результат представляет собой простой перечень
имен из списка.

ПОДРОБНЕЕ О ЦИКЛАХ
Концепция циклов очень важна, потому что она представляет один из
основных способов автоматизации повторяющихся задач

462
2018 Ren’Py

компьютером. Например, в простом цикле, использованном в


magicians Python сначала читает первую строку цикла:

for magician in magicians:

Эта строка означает, что нужно взять первое значение из списка


magicians и сохранить его в переменной magician. Первое значение в
списке — 'alice'. Затем Python читает следующую строку:

"[magician]"

Python выводит текущее значение magician, которое все еще равно


'alice'. Так как в списке еще остались другие значения, Python
возвращается к первой строке цикла:

for magician in magicians:

Python берет следующее значение из списка — 'david' — и сохраняет


его в magician. Затем выполняется строка:

"[magician]"

Python снова выводит текущее значение magician; теперь это строка


'david'. Весь цикл повторяется еще раз с последним значением в
списке, 'carolina'. Так как других значений в списке не осталось,
Python переходит к следующей строке в программе. В данном случае
после цикла for ничего нет, поэтому программа просто завершается.
Помните, что все действия повторяются по одному разу для каждого
элемента в списке независимо от их количества. Если список
содержит миллион элементов, Python повторит эти действия миллион
раз — обычно это происходит очень быстро.
Также помните, что при написании собственных циклов for временной
переменной для текущего значения из списка можно присвоить любое
имя. Однако на практике рекомендуется выбирать осмысленное имя,
описывающее отдельный элемент списка. Несколько примеров:

for cat in cats:


for dog in dogs:
for item in list_of_items:

Выполнение этого правила поможет вам проследить за тем, какие


действия выполняются с каждым элементом в цикле for. В

463
2018 Ren’Py

зависимости от того, какое число используется — одиночное и


множественное, вы сможете понять, работает ли данная часть кода с
отдельным элементом из списка или со всем списком.

Так же можно и записать каждому персонажу текст


screen for_screen():
$ magicians = ['Alice', 'David', 'Carolina']
frame:
xalign 0.5 ypos 50
vbox:
for magician in magicians:
text "[magician] волшебник"
label start:
show screen for_screen
pause

ГЕНЕРАТОР СПИСОК

Описанный выше способ генерирования списка squares состоял из


трех или четырех строк кода.
Генератор списка (list comprehension) позволяет сгенерировать тот же
список всего в одной строке. Генератор списка объединяет цикл for и
создание новых элементов в одну строку и автоматически
присоединяет к списку все новые элементы. Учебники не всегда
рассказывают о генераторах списка начинающим программистам, но я
привожу этот материал, потому что вы с большой вероятностью
встретите эту конструкцию, как только начнете просматривать код
других разработчиков.
В следующем примере список квадратов, знакомый вам по
предыдущим примерам, строится с использованием генератора
списка:
screen for_screen():
$ squares = [value**2 for value in range(1,11)]

464
2018 Ren’Py

frame:
xalign 0.5 ypos 50
vbox:
for square in squares:
text "[square] денег"

label start:
show screen for_screen
pause
Чтобы использовать этот синтаксис, начните с содержательного
имени списка, например squares. Затем откройте квадратные скобки и
определите выражение для значений, которые должны быть
сохранены в новом списке. В данном примере это выражение value**2,
которое возводит значение во вторую степень. Затем напишите цикл
for для генерирования чисел, которые должны передаваться вы-
ражению, и закройте квадратные скобки. Цикл for в данном примере —
for value in range(1,11) — передает значения с 1 до 10 выражению
value**2. Обратите внимание на отсутствие двоеточия в конце
команды for.
Результатом будет уже знакомый вам список квадратов:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Чтобы успешно писать собственные генераторы списков, необходим


определенный опыт. Тем не менее, как только вы освоитесь с
созданием обычных списков, вы оцените возможности генераторов.
Когда после очередного трех-четырехстрочного блока вам это
надоест, подумайте о написании собственных генераторов списков.

СОЗДАНИЕ СРЕЗА

Чтобы создать срез списка, следует задать индексы первого и


последнего элементов, с которыми вы намереваетесь работать. Как и
в случае с функцией range(), Python останавливается на элементе,
предшествующем второму индексу. Скажем, чтобы вывести первые

465
2018 Ren’Py

три элемента списка, запросите индексы с 0 по 3, и вы получите


элементы 0, 1 и 2.
В следующем примере используется список игроков команды:
label start:
python:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
player2 = players[0:3]
"[player2]"
pause
Выводится срез списка, включающий только первых трех игроков.
Вывод сохраняет структуру списка, но включает только первых трех
игроков:

['charles', 'martina', 'michael']

Подмножество может включать любую часть списка. Например, чтобы


ограничиться вторым, третьим и четвертым элементами списка, срез
начинается с индекса 1 и заканчивается на индексе 4:
label start:
python:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
player2 = players[1:4]
"[player2]"
pause
На этот раз срез начинается с элемента 'martina' и заканчивается
элементом 'florence':

['martina', 'michael', 'florence']


Если первый индекс среза не указан, то Python автоматически
начинает срез от начала списка:
label start:

466
2018 Ren’Py

python:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
player2 = players[:4]
"[player2]"
pause
Без начального индекса Python берет элементы от начала списка:

['charles', 'martina', 'michael', 'florence']


Аналогичный синтаксис работает и для срезов, включающих конец
списка. Например, если вам нужны все элементы с третьего до
последнего, начните с индекса 2 и не указывайте второй индекс:
label start:
python:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
player2 = players[2:]
"[player2]"
pause
Python возвращает все элементы с третьего до конца списка:

['michael', 'florence', 'eli']


Этот синтаксис позволяет вывести все элементы от любой позиции до
конца списка независимо от его длины. Вспомните, что отрицательный
индекс возвращает элемент, находящийся на заданном расстоянии от
конца списка; следовательно, вы можете получить любой срез от
конца списка. Например, чтобы отобрать последних трех игроков,
используйте срез players[-3:]:
label start:
python:
players = ['charles', 'martina', 'michael', 'florence', 'eli']

467
2018 Ren’Py

player2 = players[-3:]
"[player2]"
pause
Программа выводит имена трех последних игроков, причем
продолжает работать даже при изменении размера списка.

ПЕРЕБОР СОДЕРЖИМОГО СРЕЗА

Если вы хотите перебрать элементы, входящие в подмножество


элементов, используйте срез в цикле for. В следующем примере
программа перебирает первых трех игроков и выводит их имена:
screen for_screen():
frame:
xalign 0.5 ypos 50
vbox:
text "Список имен:"
for player in players[:3]:
text "[player] в классе"

label start:
$ players = ['Charles', 'Martina', 'Michael', 'Florence', 'Eli']
show screen for_screen
pause

КОПИРОВАНИЕ СПИСКА

Часто разработчик берет существующий список и создает на его


основе совершенно новый. Посмотрим, как работает копирование
списков, и рассмотрим одну ситуацию, в которой копирование списка
может принести пользу.

468
2018 Ren’Py

Чтобы скопировать список, создайте срез, включающий весь исходный


список без указания первого и второго индекса ([:]). Эта конструкция
создает срез, который начинается с первого элемента и завершается
последним; в результате создается копия всего списка.
Представьте, что вы создали список своих любимых блюд и теперь
хотите создать отдельный список блюд, которые нравятся вашему
другу. Пока вашему другу нравятся все блюда из нашего списка,
поэтому вы можете создать другой список простым копированием
нашего:
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 2 1:
frame:
vbox:
text "Мой список блюд:"
for my_food in my_foods:
text "[my_food]"
frame:
vbox:
text "Друга список блюд:"
for friend_food in friend_foods:
text "[friend_food]"

label start:
python:
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]

469
2018 Ren’Py

show screen for_screen


pause
При выводе обоих списков становится видно, что они содержат
одинаковые данные
Чтобы доказать, что речь в действительности идет о двух разных
списках, добавим новое блюдо в каждый список:
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 2 1:
frame:
vbox:
text "Мой список блюд:"
for my_food in my_foods:
text "[my_food]"
frame:
vbox:
text "Друга список блюд:"
for friend_food in friend_foods:
text "[friend_food]"

label start:
window hide
python:
my_foods = ['pizza', 'falafel', 'carrot cake']

470
2018 Ren’Py

friend_foods = my_foods[:]
show screen for_screen
pause
"Разные блюда добавим"
window hide
python:
my_foods.append('cannoli')
friend_foods.append('ice cream')
pause

СЛОВАРИ

В этой главе речь пойдет о словарях — структурах данных,


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

ПРОСТОЙ СЛОВАРЬ

screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:

471
2018 Ren’Py

frame:
vbox:
text "Мой список блюд:"
vbox:
text "Блюдо: [my_foods[Блюдо]]"
text "Порции: [my_foods[Порции]]"

label start:
window hide
python:
my_foods = {'Блюдо': 'Пицца', 'Порции':1}
show screen for_screen
pause
В словаре my_foods хранятся два атрибута: блюдо и количество
порций Следующие две команды "[my_foods[Блюдо]]" и
"[my_foods[Порции]]" читают эту информацию из словаря и выводят
ее на экран:

Мой список блюд


Пицца
2

Работа со словарями, как и большинство других новых концепций,


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

РАБОТА СО СЛОВАРЯМИ

Словарь в языке Python представляет собой совокупность пар «ключ


—значение». Каждый ключ связывается с некоторым значением, и
программа может получить значение, связанное с заданным ключом.
Значением может быть число, строка, список и даже другой словарь.
Собственно, любой объект, создаваемый в программе Python, может
стать значением в словаре.
В Python словарь заключается в фигурные скобки {}, в которых
приводится последовательность пар «ключ—значение», как в
предыдущем примере:

472
2018 Ren’Py

my_foods = {"Блюдо": 'Пицца', 'Порции’ : 1}


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

ОБРАЩЕНИЕ К ЗНАЧЕНИЯМ В СЛОВАРЕ

Чтобы получить значение, связанное с ключом, укажите имя словаря,


а затем ключ в квадратных скобках:
my_foods = {"Блюдо": 'Пицца'}
"[my_foods[Блюдо]]"
Эта конструкция возвращает значение, связанное с ключом "Блюдо"
из словаря my_foods
Количество пар «ключ—значение» в словаре не ограничено.

ДОБАВЛЕНИЕ НОВЫХ ПАР «КЛЮЧ—ЗНАЧЕНИЕ»

Словари относятся к динамическим структурам данных: в словарь


можно в любой момент добавлять новые пары «ключ—значение». Для
этого указывается имя словаря, за которым в квадратных скобках
следует новый ключ с новым значением.
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:

473
2018 Ren’Py

text "Мой список блюд:"


vbox:
text "Блюдо: [my_foods[Блюдо]]"
text "Порции: [my_foods[Порции]]"
if aes == 1:
text "Гостей: [my_foods[Гостей]]"

label start:
$ aes = 0
window hide
python:
my_foods = {'Блюдо': 'Пицца', 'Порции':1}
show screen for_screen
pause
$ aes = 1
$ my_foods['Гостей'] = 2 # Добавляем новую пару в словарь
pause

СОЗДАНИЕ ПУСТОГО СЛОВАРЯ

В некоторых ситуациях бывает удобно (или даже необходимо) начать


с пустого словаря, а затем добавлять в него новые элементы. Чтобы
начать заполнение пустого словаря, определите словарь с пустой
парой фигурных скобок, а затем добавляйте новые пары «ключ—
значение» (каждая пара в отдельной строке).
screen for_screen():
frame:

474
2018 Ren’Py

xalign 0.5 yalign 0.5


background None
grid 1 1:
frame:
vbox:
text "Мой список блюд:"
vbox:
if aes == 1:
text "Блюдо: [my_foods[Блюдо]]"
elif aes == 2:
text "Блюдо: [my_foods[Блюдо]]"
text "Порции: [my_foods[Порции]]"
elif aes == 3:
text "Блюдо: [my_foods[Блюдо]]"
text "Порции: [my_foods[Порции]]"
text "Гостей: [my_foods[Гостей]]"

label start:
$ aes = 0
$ my_foods = { }
show screen for_screen
"Что будем гостям накрывать?"
$ aes = 1
$ my_foods['Блюдо'] = 'Шашлык'
"А сколько порций?"

475
2018 Ren’Py

$ aes = 2
$ my_foods['Порции'] = 2
$ aes = 3
$ my_foods['Гостей'] = 2
"А гостей сколько будет?"
pause

ИЗМЕНЕНИЕ ЗНАЧЕНИЙ В СЛОВАРЕ

Чтобы изменить значение в словаре, укажите имя словаря с ключом в


квадратных скобках, а затем новое значение, которое должно быть
связано с этим ключом.
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Мой список блюд:"
vbox:
text "Блюдо: [my_foods[Блюдо]]"

label start:
$ my_foods = {'Блюдо': 'Пицца'} #значение пицца
show screen for_screen

476
2018 Ren’Py

"Подать пиццу?"
$ my_foods['Блюдо'] = 'Шашлык' #меняем на шашлык
"Или шашлыка пожарить?"
pause

УДАЛЕНИЕ ПАР «КЛЮЧ—ЗНАЧЕНИЕ»

Когда информация, хранящаяся в словаре, перестает быть ненужной,


пару «ключ—значение» можно полностью удалить при помощи
команды del. При вызове достаточно передать имя словаря и
удаляемый ключ.
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Мой список блюд:"
vbox:
if aes == 1:
text "Блюдо: [my_foods[Блюдо]]"
text "Порции: [my_foods[Порции]]"
else :
text "Порции: [my_foods[Блюдо]]"
label start:

477
2018 Ren’Py

window hide
$ aes = 1
python:
my_foods = {'Блюдо': 'Пицца', 'Порции':1}
show screen for_screen
pause
$ del my_foods['Порции']
$ aes = 2
pause

СЛОВАРЬ С ОДНОТИПНЫМИ ОБЪЕКТАМИ

В предыдущем примере в словаре сохранялась разнообразная


информация об одном объекте. Словарь также может использоваться
для хранения одного вида информации о многих объектах. Допустим,
вы хотите провести опрос среди коллег и узнать их любимый язык
программирования. Результаты простого опроса удобно сохранить в
словаре:
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Любимый язык програмирования:"
vbox:
text "У Фила любимый язык: [favorite_languages[phil]]"

478
2018 Ren’Py

text "У Эдварда любимый язык:


[favorite_languages[edward]]"
text "У Сары любимый язык: [favorite_languages[sarah]]"
text "У Ен любимый язык: [favorite_languages[jen]]"

label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
show screen for_screen
pause
Пары в словаре в этой записи разбиты по строкам. Ключами являются
имена участников опроса, а значениями — выбранные ими языки.
Если вы знаете, что для определения словаря потребуется более
одной строки, нажмите клавишу Enter после ввода открывающей
фигурной скобки. Снабдите следующую строку отступом на один
уровень (четыре пробела) и запишите первую пару «ключ—значение»,
поставив за ней запятую. После этого при нажатии Enter ваш
текстовый редактор будет автоматически снабжать все последующие
пары таким же отступом, как у первой.
Завершив определение словаря, добавьте закрывающую фигурную
скобку в новой строке после последней пары «ключ—значение» и
снабдите ее отступом на один уровень, чтобы она была выровнена по
ключам. За последней парой также рекомендуется включить запятую,
чтобы при необходимости все было готово к добавлению новой пары
«ключ—значение» в следующей строке.

ПЕРЕБОР ВСЕХ ПАР «КЛЮЧ—ЗНАЧЕНИЕ»

479
2018 Ren’Py

Прежде чем ознакомиться с разными способами перебора,


рассмотрим новый словарь, предназначенный для хранения
информации о пользователе веб-сайта. В следующем словаре
хранится имя пользователя, его имя и фамилия:
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Информация пользователя:"
vbox:
for key, value in user_0.items():
text "\nЛогин: " + key
text "Пароль: " + value
label start:
$ user_0 = {
'username': 'efermi',
'first': 'enrico',
'last': 'fermi',
}
show screen for_screen
pause
То, что вы уже узнали в этой главе, позволит вам обратиться к любому
отдельному атрибуту user_0. Но что если вы хотите просмотреть все

480
2018 Ren’Py

данные из словаря этого пользователя? Для этого можно


воспользоваться перебором в цикле for
Как мы видим чтобы написать цикл for для словаря, необходимо
создать имена для двух переменных, в которых будет храниться ключ
и значение из каждой пары «ключ—значение». Этим двум
переменным можно присвоить любые имена — с короткими
однобуквенными именами код будет работать точно так же:
for key, value in user_0.items():
Вторая половина команды for ключает в себя имя словаря, за которым
следует вызов метода items(), возвращающий список пар «ключ—
значение». Цикл for сохраняет компоненты пары в двух указанных
переменных. В предыдущем примере мы используем переменные для
вывода каждого ключа v, за которым следует связанное значение w. "\
n" в первой команде print гарантирует, что перед каждой парой «ключ
—значение» в выводе будет вставлена пустая строка
Снова обратите внимание на то, что пары «ключ—значение» не
возвращаются в порядке их хранения даже при переборе в словаре.
Python не интересует порядок хранения пар «ключ—значение»;
отслеживаются только связи между отдельными ключами и их
значениями.
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Опрос. Любимый язык програмирования:"
vbox:
for name, language in favorite_languages.items():

481
2018 Ren’Py

text "\nУ " +name.title() + " любимый язык


програмирования " + language.title() + "."

label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
show screen for_screen
pause
Код
for name, language in favorite_languages.items():
приказывает Python перебрать все пары «ключ—значение» в словаре.
В процессе перебора пар ключ сохраняется в переменной name, а
значение — в переменной language. С этими содержательными
именами намного проще понять, что делает команда
text "\nУ " +name.title() + " любимый язык програмирования " +
language.title() + "."
Всего в нескольких строках кода выводится вся информация из опроса
.
Такой способ перебора точно так же работает и в том случае, если в
словаре будут храниться результаты опроса тысяч и даже миллионов
людей.

ПЕРЕБОР ВСЕХ КЛЮЧЕЙ В СЛОВАРЕ

482
2018 Ren’Py

Переберем словарь favorite_languages и выведем имена всех людей,


участвовавших в опросе:
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Друзья которые принимали участие в опросе:"
vbox:
for name, language in favorite_languages.items():
text "name.title()
label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
show screen for_screen
pause
Чтобы обратиться в цикле к значению, связанному с интересующим
вас ключом, используйте текущий ключ. Для примера выведем для
пары друзей сообщение о выбранном ими языке. Мы переберем
имена в словаре, как это делалось ранее, но, когда имя совпадает с
именем одного из друзей, программа будет выводить специальное
сообщение об их любимом языке:

483
2018 Ren’Py

screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Люди которые принимали участие в опросе:"
vbox:
for name, language in favorite_languages.items():
text "\n" + name.title()
if name in friends:
text "А " + name.title() + ", мой друг и он любит " +
favorite_languages[name].title() + "!"

label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
$ friends = ['phil', 'sarah']

show screen for_screen

484
2018 Ren’Py

pause
Метод keys() также может использоваться для проверки того,
участвовал ли конкретный человек в опросе:
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Люди которые принимали участие в опросе:"
vbox:
for name, language in favorite_languages.items():
text "\n" + name.title()
if name in friends:
text "А " + name.title() + ", мой друг и он любит " +
favorite_languages[name].title() + "!"
if 'erin' not in favorite_languages.items():
text "Erin, не прошла тест!"
label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}

485
2018 Ren’Py

$ friends = ['phil', 'sarah']

show screen for_screen


pause

УПОРЯДОЧЕННЫЙ ПЕРЕБОР КЛЮЧЕЙ СЛОВАРЯ

Словарь всегда поддерживает связь между ключом и связанным с ним


значением, но порядок получения элементов из словаря
непредсказуем. Впрочем, это не создает проблем, потому что обычно
требуется лишь получить правильное значение, связанное с каждым
ключом.
Один из способов получения элементов в определенном порядке
основан на сортировке ключей, возвращаемых циклом for. Для
получения упорядоченной копии ключей можно воспользоваться
функцией sorted():
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Люди которые принимали участие в опросе:"
vbox:
for name in sorted(favorite_languages.keys()):###функция
text "\n" + name.title()
if name in friends:
text "А " + name.title() + ", мой друг и он любит " +
favorite_languages[name].title() + "!"

486
2018 Ren’Py

if 'erin' not in favorite_languages.items():


text "\n Erin, не прошла тест!"
label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
$ friends = ['phil', 'sarah']

show screen for_screen


pause
Эта команда for не отличается от других команд for, если не считать
того, что метод dictionary.keys() заключен в вызов функции sorted().
Эта конструкция приказывает Python выдать список всех ключей в
словаре и отсортировать его перед тем, как перебирать элементы. В
выводе перечислены все пользователи, участвовавшие в опросе, а их
имена упорядочены по алфавиту:

ПЕРЕБОР ВСЕХ ЗНАЧЕНИЙ В СЛОВАРЕ

Если вас прежде всего интересуют значения, содержащиеся в


словаре, используйте метод values() для получения списка значений
без ключей. Допустим, вы хотите просто получить список всех языков,
выбранных в опросе, и вас не интересуют имена людей, выбравших
каждый язык:
screen for_screen():
frame:
xalign 0.5 yalign 0.5
487
2018 Ren’Py

background None
grid 1 1:
frame:
vbox:
text "Какие языки были в опросе:"
vbox:
for language in favorite_languages.values():
text language.title()
label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}

show screen for_screen


pause
Команда for читает каждое значение из словаря и сохраняет его в
переменной language. При выводе этих значений будет получен
список всех выбранных языков
Значения извлекаются из словаря без проверки на возможные
повторения. Для небольших словарей это может быть приемлемо, но
в опросах с большим количеством респондентов список будет
содержать слишком много дубликатов. Чтобы получить список
выбранных языков без повторений, можно воспользоваться
множеством (set). Множество в целом похоже на список, но все его
элементы должны быть уникальными:
screen for_screen():

488
2018 Ren’Py

frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Какие языки были в опросе:"
vbox:
for language in set(favorite_languages.values()):
text language.title()
label start:
$ favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}

show screen for_screen


pause
Когда список, содержащий дубликаты, заключается в вызов set(),
Python находит уникальные элементы списка и строит множество из
этих элементов.

СПИСОК В СЛОВАРЕ

Иногда бывает удобно поместить список в словарь, вместо того чтобы


помещать словарь в список. Представьте, как бы вы описали в
программе заказанную пиццу. Если ограничиться только списком,

489
2018 Ren’Py

сохранить удастся разве что список дополнений к пицце. При


использовании словаря список дополнений может быть всего лишь
одним аспектом описания пиццы.
В следующем примере для каждой пиццы сохраняются два вида
информации: тип теста и список дополнений. Список дополнений
представляет собой значение, связанное с ключом 'toppings'. Чтобы
использовать элементы в списке, нужно указать имя словаря и ключ
'toppings', как и для любого другого значения в словаре. Вместо одного
значения будет получен список дополнений
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Меню:"
vbox:
text "Новая пицца " + pizza['crust'] + "-шеф повара " +
"Есть такие начинки:"
for topping in pizza['toppings']:
text "\t" + topping

label start:
$ pizza = {
'crust': 'Обед',
'toppings': ['Сыр', 'Помидоры'],
}

490
2018 Ren’Py

show screen for_screen


pause
Вложение списка в словарь может применяться каждый раз, когда с
одним ключом словаря должно быть связано более одного значения.
Если бы в предыдущем примере с языками программирования ответы
сохранялись в списке, один участник опроса мог бы выбрать сразу
несколько любимых языков. При переборе словаря значение,
связанное с каждым человеком, представляло бы собой список языков
screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:
text "Любимые языки программирования:"
vbox:
for name, languages in favorite_languages.items():
text "\n У " + name.title() + " любимый язык:"
for language in languages:
text "\t" + language.title()
label start:
$ favorite_languages = {
'jen': ['python', 'ruby'],
'sarah': ['c'],
'edward': ['ruby', 'go'],
'phil': ['python', 'haskell'],
491
2018 Ren’Py

}
show screen for_screen
pause
Вы видите что значение, связанное с каждым именем, теперь
представляет собой список. У некоторых участников только один
любимый язык программирования, у других таких языков несколько.
При переборе словаря переменная с именем languages используется
для хранения каждого значения из словаря, потому что мы знаем, что
каждое значение будет представлять собой список. В основном цикле
по элементам словаря другой цикл перебирает элементы списка
любимых языков каждого участника.
Теперь каждый участник опроса может указать сколько угодно
любимых языков программирования

СЛОВАРЬ В СЛОВАРЕ

Словарь также можно вложить в другой словарь, но в таких случаях


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

screen for_screen():
frame:
xalign 0.5 yalign 0.5
background None
grid 1 1:
frame:
vbox:

492
2018 Ren’Py

text "Пользовательская информация:"


vbox:
for username, user_info in users.items():
$ full_name = user_info['first'] + " " + user_info['last']
$ location = user_info['location']
text "\nИмя пользователя: " + username
text "\Полное имя: " + full_name.title()
text "\tПроживает: " + location.title()

label start:
$ users = {
'aeinstein': {
'first': 'Сергей',
'last': 'Романов',
'location': 'Москва',
},
'mcurie': {
'first': 'Анастасия',
'last': 'Тяпченко',
'location': 'Сочи',
},
}

show screen for_screen


pause

493
2018 Ren’Py

В программе определяется словарь с именем users, содержащий


два ключа: для пользователей 'aeinstein' и 'mcurie'. Значение,
связанное с каждым ключом, представляет собой словарь с именем,
фамилией и местом жительства пользователя. В процессе перебора
словаря users Python сохраняет каждый ключ в переменной username,
а словарь, связанный с каждым именем пользователя, сохраняется в
переменной user_info. Внутри основного цикла в словаре выводится
имя пользователя начинается работа с внутренним словарем.
Переменная user_info, содержащая словарь с информацией о
пользователе, содержит три ключа: 'first', 'last' и 'location'. Каждый ключ
используется для построения аккуратно отформатированных данных с
полным именем и местом жительства пользователя, с последующим
выводом сводки известной информации о пользователе

ЦИКЛЫ WHILE

Цикл for получает коллекцию элементов и выполняет блок кода по


одному разу для каждого элемента в коллекции. В отличие от него,
цикл while продолжает выполняться, пока остается истинным
некоторое условие.

ЦИКЛ WHILE В ДЕЙСТВИИ

Цикл while может использоваться для перебора числовой


последовательности. Например, следующий цикл считает от 1 до 5:
label start:
$ current_number = 1
while current_number <= 5:
"[current_number]"
$ current_number += 1
"Конец"
pause
В первой строке отсчет начинается с 1, для чего current_number
присваивается значение 1. Далее запускается цикл while, который

494
2018 Ren’Py

продолжает работать, пока значение current_number остается


меньшим или равным 5. Код в цикле выводит значение current_number
и увеличивает его на 1 командой current_number += 1. (Оператор +=
является сокращенной формой записи для current_number =
current_number + 1.)
Цикл повторяется, пока условие current_number <= 5 остается
истинным. Так как 1 меньше 5, Python выводит 1, а затем увеличивает
значение на 1, отчего current_number становится равным 2. Так как 2
меньше 5, Python выводит 2 и снова при бавляет 1 и т. д. Как только
значение current_number превысит 5, цикл останавливается, а
программа завершается
Очень многие повседневные программы содержат циклы while.
Например, представьте компьютерную игру: цикл while выполняется,
пока игра продолжается, и завершается, как только игрок захочет
остановить игру. Вряд ли кого-нибудь обрадует, если программа
завершает работу преждевременно или продолжает работать, когда
ей приказали остановиться, так что циклы while весьма полезны.

ПОЛЬЗОВАТЕЛЬ РЕШАЕТ ПРЕРВАТЬ РАБОТУ ПРОГРАММЫ

Пользователь может выполняться, пока пользователь не захочет


остановить ее, — для этого бульшая часть кода заключается в цикл
while. В программе определяется признак завершения, и программа
работает, пока пользователь не введет нужное значение:
label start:
$ message = " "
$ prompt = "\nВведите команду:"
while message != 'quit':
message = renpy.input(prompt)
"\nНажмите quit Что бы закрыть цикл. Вы ввели [message]"
"Конец"
pause
Программа работает неплохо, если не считать того, что она выводит
слово 'quit', словно оно является обычным сообщением. Простая
проверка if решает проблему:
495
2018 Ren’Py

screen for_screen():
frame:
xalign 0.5 ypos 50
vbox:
if message != 'quit':
text "[message]"
else:
text "Все верно"
label start:
$ message = " "
show screen for_screen
$ prompt = "\nВведите команду:"
while message != 'quit':
$ message = renpy.input(prompt)
"\nНажмите quit Что бы закрыть цикл"
"Конец"
pause

ФЛАГИ

В предыдущем примере программа выполняла некоторые операции,


пока заданное условие оставалось истинным. А что если вы пишете
более сложную программу, выполнение которой может прерываться
по нескольким разным условиям?
Например, компьютерная игра может завершаться по разным
причинам: у игрока кончились все «жизни»; прошло отведенное время;
все города, которые он должен был защищать, были уничтожены и т.
д. Игра должна завершаться при выполнении любого из этих условий.
Попытки проверять все возможные условия в одной команде while
быстро усложняются и становятся слишком громоздкими

496
2018 Ren’Py

Если программа должна выполняться только при истинности


нескольких условий, определите одну переменную-флаг. Эта
переменная сообщает, должна ли программа выполняться далее.
Программу можно написать так, чтобы она продолжала выполнение,
если флаг находится в состоянии True, и завершалась, если любое из
нескольких событий перевело флаг в состояние False. В результате в
команде while достаточно проверить всего одно условие: находится ли
флаг в состоянии True. Все остальные проверки (которые должны
определить, произошло ли событие, переводящее флаг в состояние
False) удобно организуются в остальном коде.
label start:
$ message = " "
$ active = True
$ prompt = "\nВведите команду:"
while active:
$ message = renpy.input(prompt)
if message == 'quit':
$ active = False
else:
"\nНажмите quit Вы ввели [message]"
"Конец"
pause
Результаты работы этой программы ничем не отличаются от
предыдущего примера, в котором условная проверка выполняется
прямо в команде while. Но теперь в программе имеется флаг,
указывающий, находится ли она в активном состоянии, и вы сможете
легко добавить новые проверки (в форме команд elif) для событий, с
которыми переменная active может перейти в состояние False. Это
может быть удобно в сложных программах — например, в
компьютерных играх с многочисленными событиями, каждое из
которых может привести к завершению программы. Когда по любому
из этих событий флаг active переходит в состояние False, основной

497
2018 Ren’Py

игровой цикл прервется, выводится сообщение о завершении игры, и у


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

ИСПОЛЬЗОВАНИЕ ЦИКЛА WHILE СО СПИСКАМИ И


СЛОВАРЯМИ

До настоящего момента мы работали только с одним фрагментом


информации, полученной от пользователя. Мы получали ввод
пользователя, а затем выводили ответ на него. При следующем
проходе цикла while программа получала новое входное значение и
реагировала на него. Но, чтобы работать с несколькими фрагментами
информации, необходимо использовать в циклах while списки и
словари.
Цикл for хорошо подходит для перебора списков, но, скорее всего,
список не должен изменяться в цикле, потому что у Python возникнут
проблемы с отслеживанием элементов. Чтобы изменять список в
процессе обработки, используйте цикл while. Использование циклов
while со списками и словарями позволяет собирать, хранить и
упорядочивать большие объемы данных для последующего анализа и
обработки.
Возьмем список недавно зарегистрированных, но еще не проверенных
пользователей сайта. Как переместить пользователей после проверки
в отдельный список проверенных пользователей? Одно из возможных
решений: используем цикл while для извлечения пользователей из
списка непроверенных, проверяем их и включаем в отдельный список
проверенных пользователей. Код может выглядеть так:
screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 2 1:
frame:
vbox:
text "Список провереных пользователей"
for confirmed_user in confirmed_users:

498
2018 Ren’Py

text confirmed_user.title()
frame:
vbox:
text "Список не провереных пользователей"
for unconfirmed_user in unconfirmed_users:
text unconfirmed_user.title()
# Начинаем с двух списков: пользователей для проверки
# и пустого списка для хранения проверенных пользователей.
label start:
show screen for_screen
$ unconfirmed_users = ['alice', 'brian', 'candace']
$ confirmed_users = []
"Начать проверку"
# Проверяем каждого пользователя, пока остаются непроверенные
# пользователи. Каждый пользователь, прошедший проверку,
# перемещается в список проверенных.
while unconfirmed_users:
""
$ current_user = unconfirmed_users.pop()
"Проверка пользователя: [current_user]"
$ confirmed_users.append(current_user)
# Вывод всех проверенных пользователей.
$ ser = current_user.title()
"\nПользователь [ser] подтвержден"
"Список окончен"
pause
499
2018 Ren’Py

УДАЛЕНИЕ ВСЕХ ВХОЖДЕНИЙ КОНКРЕТНОГО ЗНАЧЕНИЯ


ИЗ СПИСКА

Допустим, имеется список pets, в котором значение 'cat' встречается


многократно. Чтобы удалить все экземпляры этого значения, можно
выполнять цикл while до тех пор, пока в списке не останется ни одного
экземпляра 'cat':
screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
text "Список животных"
for pet in pets:
text pet.title()

label start:

$ pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']


"Начать проверку"
show screen for_screen
pause
python:
while 'cat' in pets:
pets.remove('cat')

500
2018 Ren’Py

pause

Программа начинает со списка, содержащего множественные


экземпляры 'cat'. После вывода списка Python входит в цикл while,
потому что значение 'cat' присутствует в списке хотя бы в одном
экземпляре. После входа цикл Python удаляет первое вхождение 'cat',
возвращается к строке while, а затем обнаруживает, что экземпляры
'cat' все еще присутствуют в списке, и проходит цикл заново. Вхож-
дения 'cat' удаляются до тех пор, пока не окажется, что в списке
значений 'cat' не осталось; в этот момент Python завершает цикл и
выводит список заново.

ЗАПОЛНЕНИЕ СЛОВАРЯ ДАННЫМИ, ВВЕДЕННЫМИ


ПОЛЬЗОВАТЕЛЕМ

При каждом проходе цикла while ваша программа может запрашивать


любое необходимое количество данных. Напишем программу, которая
при каждом проходе цикла запрашивает имя участника и его ответ.
Собранные данные будут сохраняться в словаре, потому что каждый
ответ должен быть связан с конкретным пользователем:
screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
for name, response in responses.items():
text name + " учил в школе " + response + " язык."
label start:
$ responses = {}

501
2018 Ren’Py

$ polling_active = True
"Начать анкетирование"
show screen for_screen
pause
python:
while polling_active:
name = renpy.input("\nКак тебя зовут? ")
response = renpy.input("Ты какой язык учил в школе? ")
responses[name] = response
repeats = renpy.input("Хочешь добавить еще анкету? (yes/ no) ")
if repeats == 'no':
polling_active = False

"\n--- Ваш результат ---"

ФУНКЦИИ

Эта глава посвящена функциям — именованным блокам кода,


предназначенным для решения одной конкретной задачи. Чтобы
выполнить задачу, определенную в виде функции, вы указываете имя
функции, отвечающей за эту задачу. Если задача должна многократно
выполняться в программе, вам не придется заново вводить весь
необходимый код; просто вызовите функцию, предназначенную для
решения задачи, и этот вызов приказывает Python выполнить код,
содержащийся внутри функции. Как вы вскоре убедитесь,
использование функций упрощает чтение, написание, тестирование
кода и исправление ошибок.
В этой главе также рассматриваются возможности передачи
информации функциям. Вы узнаете, как писать функции, основной
задачей которых является вывод информации, и другие функции,
предназначенные для обработки данных и возвращения значения
(или набора значений.) Наконец, вы научитесь хранить функции в

502
2018 Ren’Py

отдельных файлах, называемых модулями, для упорядочения файлов


основной программы.

ОПРЕДЕЛЕНИЕ ФУНКЦИИ

init python: # 1 строка


def get_formatt(first_name, last_name): # 2 строка
"""Возвращает аккуратно отформатированное полное имя.""" #3
строка
full_name = first_name + ' ' + last_name # 4 строка
return full_name.title()# 5 строка

screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
text "[musician]"
label start:
$ musician = get_formatt('Вася', 'Пупкин') # 6 строка
show screen for_screen
pause
Разберем что мы тут записали:
Строка 1 – обьявляем функцию в питоне, инит требуется для
определения кода до начала запуска проекта
Строка 2 при помощи ключевого слова def сообщает Python, что вы
определяете функцию. В определении функции указывается имя
503
2018 Ren’Py

функции и, если нужно, описание информации, необходимой функции


для решения ее задачи. Эта информация заключается в круглые
скобки(если она даже не нуждается в информации и значении все
равно пишем круглые скобки). В данном примере функции присвоено
имя get_formatted_name у которой есть параметр first_name и
last_name. Наконец, определение завершается двоеточием.
Все строки с отступами, следующие за def greet_user():, образуют
тело функции. Текст в строке 3 представляет собой комментарий
— строку документации.
С описанием функции. Строки документации заключаются в
утроенные одинарные кавычки(пишутся на английской раскладке
нажав на букву э ); Python опознает их по этой последовательности
символов во время генерирования документации к функциям в ваших
программах.
4 строка Функция объединяет эти два имени, добавляет между ними
пробел и сохраняет результат в full_name
5 строка Значение full_name преобразуется в формат с начальной
буквой верхнего регистра, а затем возвращается в точку вызова
6 строка Вызывая функцию, которая возвращает значение,
необходимо предоставить переменную, в которой должно храниться
возвращаемое значение. В данном случае возвращаемое значение
сохраняется в переменной musician Результат содержит аккуратно
отформатированное полное имя, построенное из имени и фамилии

НЕОБЯЗАТЕЛЬНЫЕ АРГУМЕНТЫ

Иногда бывает удобно сделать аргумент необязательным, чтобы


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

init python:
def get_formatt(first_name, middle_name, last_name):
504
2018 Ren’Py

"""Возвращает аккуратно отформатированное полное имя."""


full_name = first_name + ' ' + middle_name + ' ' + last_name
return full_name.title()

screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
for musicians in musician:
text "[musicians]"
label start:
$ musician = get_formatt('john', 'lee', 'hooker')
show screen for_screen
pause
Функция работает при получении имени, второго имени и фамилии.
Она получает все три части имени, а затем строит из них строку.
Функция добавляет пробелы там, где это уместно, и преобразует
полное имя в формат с капитализацией
Однако вторые имена нужны не всегда, а в такой записи функция не
будет работать, если при вызове ей передаются только имя и
фамилия. Чтобы средний аргумент был необязательным, можно
присвоить аргументу middle_name пустое значение по умолчанию;
этот аргумент игнорируется, если пользователь не передал для него
значение. Чтобы функция get_formatt() работала без второго
имени, следует назначить для параметра middle_name пустую строку
значением по умолчанию и переместить его в конец списка
параметров:
505
2018 Ren’Py

init python:
def get_formatt(first_name, last_name, middle_name= ' ' ):
"""Возвращает аккуратно отформатированное полное имя."""
if middle_name:
full_name = first_name + ' ' + middle_name + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
return full_name.title()
screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
text "[musician]"
label start:
$ musician = get_formatt('john', 'lee')
show screen for_screen
pause
$ musician = get_formatt('john', 'lee', 'hooker')
pause
В этом примере имя строится из трех возможных частей. Поскольку
имя и фамилия указываются всегда, эти параметры стоят в начале
списка в определении функции. Второе имя не обязательно, поэтому
оно находится на последнем месте в определении, а его значением по
умолчанию является пустая строка.

506
2018 Ren’Py

В теле функции мы сначала проверяем, было ли задано второе имя.


Python интерпретирует непустые строки как истинное значение, и,
если при вызове задан аргумент второго имени, middle_name дает
результат True . Если второе имя указано, то из имени, второго имени
и фамилии строится полное имя. Затем имя преобразуется с
капитализацией символов и возвращается в строку вызова функции,
где оно сохраняется в переменной musician и выводится. Если второе
имя не указано, то пустая строка не проходит проверку if и выполняет
блок else В этом случае полное имя строится только из имени и
фамилии, и отформатированное имя возвращается в строку вызова,
где оно сохраняется в переменной musician и выводится.
Вызов этой функции с именем и фамилией достаточно тривиален. Но
при использовании второго имени придется проследить за тем, чтобы
второе имя было последним из передаваемых аргументов. Это
необходимо для правильного связывания позиционных аргументов в
строке
Необязательные значения позволяют функциям работать в
максимально широком спектре сценариев использования без
усложнения вызовов.

ВОЗВРАЩЕНИЕ СЛОВАРЯ

Функция может вернуть любое значение, нужное вам, в том числе и


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

init python:
def build_person(first_name, last_name):

507
2018 Ren’Py

"""Возвращает словарь с информацией о человеке."""


pers = {'Имя': first_name, 'Фамилия': last_name} #1
return pers #2
screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
text "Имя [musician[Имя]]"
text "Фамилия [musician[Фамилия]]"

label start:
$ musician = build_person('Эдди', 'Мерфи') #3
show screen for_screen
pause
Функция build_person() получает имя и фамилию и сохраняет
полученные значения в словаре в точке . Значение first_name
сохраняется с ключом 'Имя', а значение last_name — с ключом
'Фамилия'. Весь словарь с описанием человека возвращается в точке
. Возвращаемое значение выводится в точке с двумя исходными
фрагментами текстовой информации, теперь хранящимися в словаре
Функция получает простую текстовую информацию и помещает ее в
более удобную структуру данных, которая позволяет работать с
информацией (помимо простого вывода). Строки 'Эдди' и 'Мерфи'
теперь помечены как имя и фамилия. Функцию можно легко
расширить так, чтобы она принимала дополнительные значения: —

508
2018 Ren’Py

второе имя, возраст, профессию или любую другую информацию о че-


ловеке, которую вы хотите сохранить. Например, следующее
изменение позволяет также сохранить возраст человека:
init python:
def build_person(first_name, last_name, age=' '):
"""Возвращает словарь с информацией о человеке."""
pers = {'Имя': first_name, 'Фамилия': last_name}
if age:
pers['age'] = age
return pers
screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
text "Имя [musician[Имя]]"
text "Фамилия [musician[Фамилия]]"
text "Возраст [musician[age]]"
label start:
$ musician = build_person('Эдди', 'Мерфи', age=27)
show screen for_screen
pause
В определение функции добавляется новый необязательный
параметр age, которому назначается пустое значение по умолчанию.
Если вызов функции включает значение этого параметра, то значение

509
2018 Ren’Py

сохраняется в словаре. Функция всегда сохраняет имя, но ее также


можно модифицировать, чтобы она сохраняла любую необходимую
информацию о человеке.

ИСПОЛЬЗОВАНИЕ ФУНКЦИИ В ЦИКЛЕ WHILE

Функции могут использоваться со всеми структурами Python, уже


известными вам. Например, используем функцию get_formatted_name()
в цикле while, чтобы поприветствовать пользователей более официально.
Первая версия программы, приветствующей пользователей по имени и
фамилии, может выглядеть так:
init python:
def get_formatted_name(first_name, last_name):
"""Возвращает аккуратно отформатированное полное имя."""
full_name = first_name + ' ' + last_name
return full_name.title()

screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
frame:
vbox:
text "\nHello, " + formatted_name + "!"

label start:
$ formatted_name = " "

510
2018 Ren’Py

$ f_name = ""
$ l_name = ""
show screen for_screen

python:
while True:
formatted_name = get_formatted_name(f_name, l_name)
f_name = renpy.input("First name: ")
l_name = renpy.input("Last name: ")

pause
В этом примере используется простая версия get_formatted_name(),
без вторых имен. В цикле while имя и фамилия пользователя
запрашиваются по отдельности.

ИЗМЕНЕНИЕ СПИСКА В ФУНКЦИИ

Если вы передаете список функции, код функции сможет изменить


список. Все изменения, внесенные в список в теле функции,
закрепляются, что позволяет эффективно работать со списком даже
при больших объемах данных.
Допустим, компания печатает на 3D-принтере модели,
предоставленные пользователем. Проекты хранятся в списке, а после
печати перемещаются в отдельный список. В следующем примере
приведена реализация, не использующая функции:
screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
hbox:

511
2018 Ren’Py

frame:
vbox:
text "Печатается модель: " + current_design
frame:
vbox:
for completed_model in completed_models:
text "Готовые модели " + completed_model

label start:
python:
completed_models = []
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
current_design = " "
show screen for_screen
"Начало"
while unprinted_designs:
$ current_design = unprinted_designs.pop()
"Готово"
$ completed_models.append(current_design)
pause
В начале программы создается список моделей и пустой список
completed_models, в который каждая модель перемещается после
печати. Пока в unprinted_designs остаются модели, цикл while
имитирует печать каждой модели: модель удаляется с конца списка,
сохраняется в current_design, а пользователь получает сообщение о
том, что текущая модель была напечатана. Затем модель
перемещается в список напечатанных. После завершения цикла
выводится список напечатанных моделей

512
2018 Ren’Py

Мы можем изменить структуру этого кода: для этого следует


написать две функции, каждая из которых решает одну конкретную
задачу. Бульшая часть кода останется неизменной; просто программа
становится более эффективной.
init python:
def print_models(unprinted_designs, completed_models):
"""
Имитирует печать моделей, пока список не станет пустым.
Каждая модель после печати перемещается в completed_models.
"""
while unprinted_designs:
current_design = unprinted_designs.pop()
completed_models.append(current_design)
""

screen for_screen():
frame:
background None
xalign 0.5 yalign 0.5
grid 1 1:
hbox:
frame:
vbox:
text "Печатается модель: " + current_design
frame:
vbox:
for completed_model in completed_models:

513
2018 Ren’Py

text "Готовые модели " + completed_model

label start:
python:
completed_models = []
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
current_design = " "

show screen for_screen


"Начало"
$ print_models(unprinted_designs, completed_models)

pause

ЗАПРЕТ ИЗМЕНЕНИЯ СПИСКА В ФУНКЦИИ

Иногда требуется предотвратить изменение списка в функции.


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

514
2018 Ren’Py

список, будут распространяться только на копию, а оригинал списка


остается неизменным.
Чтобы передать функции копию списка, можно поступить так:
имя_функции(имя_списка[:])
Синтаксис среза [:] создает копию списка для передачи функции. Если
удаление элементов из списка unprinted_designs нежелательно,
функцию print_models() можно вызвать так:
$ print_models(unprinted_designs[:], completed_models)
Функция print_models() может выполнить свою работу, потому что она
все равно получает имена всех ненапечатаных моделей. Но на этот
раз она получает не сам список unprinted_designs, а его копию.
Список completed_models заполняетсяименами напечатанных
моделей, как и в предыдущем случае, но исходный список функцией
не изменяется.
Несмотря на то что передача копии позволяет сохранить содержимое
списка, обычно функциям следует передавать исходный список (если
у вас нет веских причин для передачи копии). Работа с существующим
списком более эффективна, потому что программе не приходится
тратить время и память на создание отдельной копии (лишние
затраты особенно заметны при работе с большими списками).

ГЕНЕРАТОР ЦЕПИ МАРКОВА

Скачать проект где было реализована данная установка

https://patchydollgames.itch.io/yourswimsuit

Следующая установка имеет следующие особенности:


1. принимает входной сигнал от трех отдельных источников: один для
персонажа NPC (dialogM.txt), один для вашего персонажа /
повествования (dialogY.txt), и один для опций меню (dialogC.txt). Эти
текстовые файлы находятся в папке / игр.
2. Формирует либо двухсекционный вариант или выбор меню из трех
опций, с произвольным текстом.
3. Изменяет переменный в случайном порядке , когда игрок выбирает

515
2018 Ren’Py

опцию меню. (В моей оригинальной игре, это используется для


отслеживания прогресса в ухаживании Мико. Код не показывает выбор
результатов игрока.)
Существует один из основного предостережения: Ваши файлы
должны быть простым ASCII.Генератор Марков может создать вывод
, который ломает Ren'Py. Я предполагаю , что иногда проходит
управляющие символы , которые заставляют Ren'Py думать , что
теперь получать аргументы вместо текста диалога. Там очень простой
багфикс добавил в сценарий Markovgen что - то обрабатывает эту
проблему. Тем не менее, важно , что бы вы использовали инструмент
редактирования текста , чтобы удалить не-ASCII символы из вашего
исходного текста. Все цитаты должны быть прямыми, а также
специальные знаки препинания , такие как эм черточки должны быть
удалены.
Создайте файл с именем markovgen.py
import renpy.store as store
import renpy.exports as renpy
import random

class Markov(object):

def __init__(self, open_file):


self.cache = {}
self.open_file = open_file
self.words = self.file_to_words()
self.word_size = len(self.words)
self.database()

def file_to_words(self):
self.open_file.seek(0)
data = self.open_file.read()
words = data.split()
return words

def triples(self):
""" Generates triples from the given data string. So if our string
were
"What a lovely day", we'd generate (What, a, lovely) and then
(a, lovely, day).
"""

if len(self.words) < 3:
return

for i in range(len(self.words) - 2):


yield (self.words[i], self.words[i+1], self.words[i+2])

def database(self):

516
2018 Ren’Py

for w1, w2, w3 in self.triples():


key = (w1, w2)
if key in self.cache:
self.cache[key].append(w3)
else:
self.cache[key] = [w3]

def generate_markov_text(self, size=25):


seed = random.randint(0, self.word_size-3)
seed_word, next_word = self.words[seed], self.words[seed+1]
w1, w2 = seed_word, next_word
gen_words = []
for i in xrange(size): # Cheap fix for Ren'Py errors caused by EOF
gen_words.append(w1)
try:
w1, w2 = w2, random.choice(self.cache[(w1, w2)])
except KeyError:
break
gen_words.append(w2)
return ' '.join(gen_words)

Сохраняем файл и заходим в script.rpy и пишем следующее


init python:
import markovgen

filenameM = "dialogM.txt" # Компьютер


filenameY = "dialogY.txt" # Ты
filenameC = "dialogC.txt" # Меню выбора

fileM_ = open(renpy.loader.transfn(filenameM)) # Открываем файлы что бы


markovgen.py мог получить к ним доступ
fileY_ = open(renpy.loader.transfn(filenameY))
fileC_ = open(renpy.loader.transfn(filenameC))

markovM = markovgen.Markov(fileM_) # Сгенерировать данные цепи Маркова


markovY = markovgen.Markov(fileY_)
markovC = markovgen.Markov(fileC_)

choice = 0 # записывает выбор меню, выбранный игроком

effectGen = 0 #
effectA = 0 # Использовать для рандомизации моддинга переменной типа
effectB = 0 # в меню выбора.
effectC = 0 # (различный путь «победить» каждый раз)

like = 0 # отслеживать, насколько хорошо вы делаете (например> 0 to "win")


Следующие вызовы функций , которые вы можете получить доступ в сценарии с
использованием "call [label]" команда. Поместите их перед меткой старта

label Msay: # Сделать NPC что-то сказать


$ mString = markovM.generate_markov_text()
m "%(mString)s"
return

label Nsay: # Заставить рассказчика что-то думать.


$ mString = markovY.generate_markov_text()

517
2018 Ren’Py

"%(mString)s"
return

label Ysay: # Заставить вас что-то сказать.


$ mString = markovY.generate_markov_text()
y "%(mString)s"
return

label Gen: # генерирует серию из трех строк для параметров меню, не вызывайте
напрямую
$ mStringA = markovC.generate_markov_text()
$ mStringB = markovC.generate_markov_text()
$ mStringC = markovC.generate_markov_text()
return

label GenEffect: # генерирует рандомизированные эффекты для «подобной»


переменной в меню, используя ужасное программирование. Не вызывайте напрямую.
python:
effectGen = renpy.random.randint(0, 2)

if (effectGen == 0):
effectA = -1

effectGen = renpy.random.randint(0,1)

if (effectGen == 0):
effectB = 0
effectC = 1
else:
effectC = 0
effectB = 1

elif (effectGen == 1):


effectB = -1

effectGen = renpy.random.randint(0,1)

if (effectGen == 0):
effectA = 0
effectC = 1
else:
effectC = 0
effectA = 1

elif (effectGen == 2):


effectC = -1

effectGen = renpy.random.randint(0,1)

if (effectGen == 0):
effectA = 0
effectB = 1
else:
effectB = 0
effectA = 1

#"like=%(like)s\n\n%(effectA)s, %(effectB)s, %(effectC)s" -- CHEAT CODE!


Uncomment to see menu effects and your "score"
return

518
2018 Ren’Py

label MenuTwo: # два варианта меню


call GenEffect
call Gen
menu:
"%(mStringA)s":
$ choice = 1
$ like += effectA
return
"%(mStringB)s":
$ choice = 2
$ like += effectB
return

label MenuThree: # три варианта меню


call GenEffect
call Gen
menu:
"%(mStringA)s":
$ choice = 1
$ like += effectA
return
"%(mStringB)s":
$ choice = 2
$ like += effectB
return
"%(mStringC)s":
$ choice = 3
$ like += effectC
return
Этикетки вы на самом деле называют в сценарии являются Ysay, Nsay, Msay, MenuTwo
и MenuThree . Например (это не будет работать из коробки, это просто , чтобы показать
вам , как используются звонки):
label start:
play music "music/music_beach_house.ogg" fadeout 0.25 fadein 0

scene bg classroom day


with dissolve

call Nsay
call Nsay

show m
with dissolve

call Msay
call Msay
call Ysay

m "..."

call Nsay
call Nsay
call Msay

call MenuTwo

# the menu modified the "like" variable, so let's change the story branch
based on its new value
if like > 0:

519
2018 Ren’Py

jump branch1
else:
jump branch2
Там вы идете! Случайный текст, случайные опции меню, случайные результаты. Это
действительно простой , но результат может быть очень весело.

ПЕРВЫЕ ШАГИ НА ПУТИ ПОРТИРОВАНИЯ С PYGAME НА


RENPY.

Единственная предпосылка для этого урока является пониманием Python в


некоторой степени. Знание Pygame на самом деле не нужно, но если вы хотите ,
что-то построить на этом коде , то вам нужно будет знать Pygame. На Pygame
достаточно легко работать , если вы уже знаете Python.

Для начало посмотрим на код который мы хотим портировать (Это будет звездное
небо которое двигается)

#!/usr/bin/python

# simple example of side scrolling pixels for renpy game

import pygame, sys, random

TOTAL_STARS = 500
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

class Star(object):
color = [0,0,0]
position = [0,0]
speed = 1

def __init__(self):
self.generateStartPosition(xrandom=True)

def generateStartPosition(self, xrandom=False):


# start at right of screen, scroll left
if xrandom:
xpos = random.randint(1, SCREEN_WIDTH - 1)
else:
xpos = SCREEN_WIDTH - 1
self.position = [xpos, random.randint(1, SCREEN_HEIGHT - 1)]
brightness = random.randint(1, 255)
self.color = [brightness, brightness, brightness]
self.speed = float(brightness / 400.0)

def update(self):
self.position[0] -= self.speed
if(self.position[0] < 0):
# generate new star
self.generateStartPosition()

def draw(self, screen):

520
2018 Ren’Py

xpos = int(self.position[0])
ypos = int(self.position[1])
screen.fill(self.color, pygame.Rect(xpos, ypos, 1, 1))

def setup():
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
return(screen)

def checkEvents():
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# or exit on spacebar being pressed
if event.type == pygame.KEYDOWN:
if event.key == 32:
sys.exit()

def loop(screen):
stars = [Star() for x in range(TOTAL_STARS)]
while(True):
screen.fill([0,0,0])
for star in stars:
star.draw(screen)
star.update()
pygame.display.flip()
checkEvents()

if __name__ == '__main__':
screen = setup()
loop(screen)

Здесь прописан class Star в котором прописано положение, цвет и объекты


которые в нем рисуются.
В основном, цвета и скорость звезд связаны между собой: темные звезды будут
двигаться медленнее, давая иллюзию 3D.

После класса, мы имеем некоторые простые функции, в которых все довольно


очевидно. Есть def setup(), checkEvents () и простой цикл , который просто
повторяет обновление звезд.

Если у вас есть установленный питон и Pygame запустите этот код в них, и вы
увидите красивые звезды

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

Для начало создайте новый проект на ренпае.


Зайдите в скрипт script.rpy

Очистите весь текст и пропишите следующее:

label start:
"Тут начнется звездопад"
return

521
2018 Ren’Py

Далее нам нужно создать новый файл сценария в проекте (назовем его star.rpy)

И прописать в нем код, который показывал бы ренпаю что это код питона

init -1 python:

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

init -1 python:

# мы импортируем без sys


import random, pygame

# и разрешения(константы)
TOTAL_STARS = 500
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

# Прописываем так же класс без изменений


class Star(object):
color = (0,0,0)
position = [0,0]
speed = 1

def __init__(self):
self.generateStartPosition(xrandom=True)

def generateStartPosition(self, xrandom=False):


# start at right of screen, scroll left
if xrandom:
xpos = random.randint(1, SCREEN_WIDTH - 1)
else:
xpos = SCREEN_WIDTH - 1
self.position = [xpos, random.randint(1, SCREEN_HEIGHT - 1)]
brightness = random.randint(1, 255)
self.color = (brightness, brightness, brightness)
self.speed = float(brightness / 400.0)

def update(self):
self.position[0] -= self.speed
if(self.position[0] < 0):
# генерируем новые звезды
self.generateStartPosition()

def draw(self, canvas):


xpos = int(self.position[0])
ypos = int(self.position[1])
canvas.rect(self.color, pygame.Rect(xpos, ypos, 0, 0))

#теперь мы добавляем класс для отображения в ренпае


class StarDisplay(renpy.Displayable):
def __init__(self, *args, **kwargs):
super(StarDisplay, self).__init__(*args, **kwargs)
self.stars = [Star() for x in range(TOTAL_STARS)]

def render(self, width, height, st, at):


"""Вызывается, когда renpy нужно получить изображение для
отображения"""
#сделайте экран для рисования

522
2018 Ren’Py

screen = renpy.Render(SCREEN_WIDTH, SCREEN_HEIGHT)


canvas = screen.canvas()
#закрасиим все в черный и добавим звезды
canvas.rect((0,0,0), pygame.Rect(0, 0, SCREEN_WIDTH,
SCREEN_HEIGHT))
for star in self.stars:
star.draw(canvas)
star.update()
# просто нарисовать один раз, если не достаточно хорошо. Скажите
Renpy вызвать эту функцию как можно скорее
renpy.redraw(self, 0)
# теперь мы просто должны вернуть этот рендер
return screen

def visit(self):
"""Эта функция должна вернуть все displayables.
У нас их нет, так что просто верните пустой список"""
return []

Вы можете увидеть , что оригинальный класс Star мы использовали почти


неизменным, и большая часть функций за пределами этого класса теперь
перемещены в класс StarDisplay. Некоторые функции были удалены;

Обратите внимание , что мы должны были сделать пару дополнительных вещей.


Мы должны были вызвать рендер области, а затем и на холсте , которые создают
области. Для того, чтобы получить реальную Pygame поверхность, необходимо
вызвать $ canvas.get_surface (), но я пошел легкиv путем в этом руководстве.
Цвета пришлось превратились в кортежи (Pygame чуть менее разборчивы). кроме
того , что остальная часть коды очень похожа.

Следующий фрагмент головоломки — нужно сказать Renpy, что этот код — на


самом деле дисплей и мы хотим использовать его для фона нашей игры. Теперь
вернемся к файлу script.rpy. Измените его как на нижнем примере:

# нам нужно displayable привязать к экрану


screen star_screen:
add StarDisplay()

label start:
# теперь нам нужно добавить экран в фон проекта
show screen star_screen
"Тут начнется звездопад"

Вот такой у вас получится результат

https://pp.userapi.com/c834103/v834103718/10ef1e/1I_6PsZdNbY.jpg

Как вы могли заметить версия Renpy медленнее , чем оригинальный Python. Это связано
со многими факторами, главным из которых , что Renpy делает другие вещи в фоновом
режиме (например, наложение текста)

523
2018 Ren’Py

КАК СДЕЛАТЬ ОБРАТНУЮ СВЯЗЬ С БЕТАТЕСТЕРОМ

Идея заключается в том , что иногда вы хотите знать , какой выбор , тестеры , сделали во
время игры, и дать им легкий способ высказаться

Создайте экран где вы создаете кнопку


textbutton _("Generate Feedback") action Jump("generate_feedback_file")

Создайте отдельный файл и запишите измененный как вам нужно следующий код:
init python:
import pickle
with open(os.path.join(config.renpy_base, "feedback.txt"), "w") as
file:
pickle.dump(s, file)

# Эта часть объединяет всю информацию, которая будет сохранена в текстовом файле.
label generate_feedback_file:
$ feedback = str("Имя главного героя:" + mcs_name + " " + mcs_surname + ".\
n\ Они являются"
+ mcs_gender + ", и " + mc_he_or_she + " в " + mcs_city + " в " +
mcs_country + ".\n\ Игрок взял"
+ str(time_taken_to_choose_gender_in_minutes) + " минут и сек " +
str(time_taken_to_choose_gender_in_seconds) + " секунд, чтобы выбрать пол героя.\
n\ "
+ str(mcs_initial_feelings_about_the_first_invitation_to_japan) + ".\n\ "
+ what_did_the_mc_tell_dave_about_their_japanese_ability + ".")

# Если вы хотите показать игроку сообщение, подтверждающее, что эта функция


работает, сделайте это здесь.

$ create_feedback(feedback)
infodump "[feedback]"
return

# Не забудьте установить начальное состояние для переменных, чтобы избежать ошибок


позже.
# Не бойтесь имен переменных, которые легко читать.
# Назовите этот следующий ярлык в начале вашей игры.
label prepare_variables:
$ mcs_name = "undecided"
$ mcs_surname = ""
$ mcs_gender = "неопределенного пола"
$ mc_he_or_she = "этот человек"
$ mcs_city = "неизвестный город"
$ mcs_country = "неизвестная страна"
$ time_taken_to_choose_gender_in_minutes = 0
$ time_taken_to_choose_gender_in_seconds = 0
$ mcs_initial_feelings_about_the_first_invitation_to_japan = "Они еще не были

524
2018 Ren’Py

приглашены в Японию"
$ what_did_the_mc_tell_dave_about_their_japanese_ability = "Они еще не встретили
Дейва"

КАК ДОБАВИТЬ СТОРОННИЙ МОДУЛЬ В РЕНПАЙ


(SQLITE3 И BERKELEYDB)

http://greentarga.ucoz.ru/publ/a/primery_koda/dobavljaem_sqlite3_i_berkeleydb_v_renpy/5-1-0-
46

Скачать и установить python 2.7.10


(https://www.python.org/downloads/release/python-2710/)
Копируем:
C:\Program Files (x86)\Python\Python 2.7.10\Lib\sqlite3
C:\Program Files (x86)\Python\Python 2.7.10\DLLs\_sqlite3.pyd
C:\Program Files (x86)\Python\Python 2.7.10\DLLs\sqlite3.dll
В папку:
C:\Program Files (x86)\RenPy\renpy-*.**.**.*-sdk\lib\windows-i686\Lib

Чтобы проверить добавляем в начало script.py следующий код:


init:
python:
import sqlite3
conn = sqlite3.connect(config.basedir+'/example.db')
cur = conn.cursor()
cur.execute("insert into npc values ('snake', 'python')")
cur.execute("select npc_type, npc_name from npc where id='snake'")
result = cur.fetchone()

Пример работы с Sqlite3:


cur.execute("select * from airlines limit 5;")
results = cur.fetchall()
print results

Таким же не хитрым образом можно добавить и BerkeleyDB:


Копируем:
C:\Program Files (x86)\Python\Python 2.7.10\Lib\bsddb
C:\Program Files (x86)\Python\Python 2.7.10\DLLs\_bsddb.pyd
В папку:
C:\Program Files (x86)\RenPy\renpy-*.**.**.*-sdk\lib\windows-i686\Lib

525
2018 Ren’Py

Чтобы проверить добавляем в начало script.py следующий код:


init:
python:
import bsddb
db = bsddb.btopen(config.basedir+'/spam.db')

Пример работы с BerkeleyDB:


db['player'] = '123'
print db

СОЗДАЕМ ИНСТАЛЛЯТОР
Когда вы закончили свою демо, или проект. Вам потребуется создать
инсталлятор (дабы серьезней выглядело все, и не знающие ренпай
могли поиграть в ваш проект.)
1) Для этого, заходим в лаунчер ренпая,
2) Выбираем раздел «очистить постоянные данные». Дабы у игрока
сразу не было все открыто, и он ваш проект пропуском за 5 мин не
прошел.
3) Выбираем пункт «Построить дистрибьютор» И там выбираем что
вы хотите сделать(на виндовс или линукс и т.д) и программа
автоматом создаст ехе и т.д.
4) Выходим на папку проекта test(где вы построили дистрибьютор)
или какой вы создавали. Далее вы щелкаете правой кнопкой мыши на
ваш проект и выбираете создать архив(winrar), выскакивает окошко и
выделяете галкой Создать SFX-архив

526
2018 Ren’Py

5) Простейший инсталлятор у вас готов


Если вам нужно посложней, то просмотрите видео
https://vk.com/cyber_z_craft?w=wall-76362432_181

ПОРТИРУЕМ ПРОЕКТ НА АНДРОИД/АЙФОН

В новейших версиях ренпая (7 версия) Автоматизировали этот


процесс, что лаунчер автоматически закачивает необходимые файлы
(старики помнят как раньше мучались с ссылками на офф сайте ява
скачивать актуальную версию)

ПОРТИРУЕМ АНДРОИД

Что бы создать андроид порт вам потребуется зайти в лаунчер


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

527
2018 Ren’Py

Вам сначало потребуется установить Sdk После установки


выполните необходимые команды.
После установки вам потребуется нажать на кнопку Настроить

И спросит следующие вопросы:


Предложить назвать ваш проект
Как программно будет называться ваш проект
Предложит вам назвать имя проекта, для гугл плея (пишем на
английском например com.erexte.program )
Версию проекта
Версию кода
Вариант разрешения экрана (горизонтально, вертикально, автомат
меняться)
Для какой платформы (Neither – универсальный)
528
2018 Ren’Py

Спросит какой размер у вашего проекта и предупредит об


ограничениях.
Спросит на какую платформу андроида создать (4 самая стабильная)
Приложение будет соединяться с интернетом (если включать будете
просмотр рекламы то да)
Потом у вас разблокируются пункты Собрать Пакет – нажимаете на
него
У вас готово приложение андроид.

КАК УБРАТЬ ЛОГОТИП РЕНПАЯ НА АНДРОИДЕ

529
2018 Ren’Py

Вам потребуется зайти в папку где у вас находится лаунчер ренпая и найти папку

renpy-sdk_7.0/rapt/templates далее в этой папке находится изображение renpy-


presplash.png меняете его на свое изображение в таком же формате.

ПОРТИРУЕМ НА АЙФОН

В лаунчере ренпая нажимите на IOS. Потом вам необходимо будет выбрать папку, где у
вас будут собираться все айос- приложения(Выбрать директорию проектов).

Потом нажимаете на Создать проект xcode и у вас готово приложение для айфонов и
айпадов.

ПРОБЛЕМА ВСЕХ НАЧИНАЮЩИХ КОДИРОВЩИКОВ.

Нет художников
По этому поводу писал один человек https://vk.com/renpy?w=wall-
7553243_24357%2Fall и я с ним согласен.

530
2018 Ren’Py

У вас есть сценарий, но у вас нет художника, и вы начинаете его


бешено искать, звать и может быть, даже найдете, НО он на
следующий день может уйти. Поймите, вы начинающий программист,
вы не заработали себе репутацию, вы даже черновик не сделали
своего проекта, а вы уже ищите художника. Не спешите, сделайте
сначала черновик без спрайтов, если проект будет интересным,
быстро найдется художник, а если не найдется он сам, так у вас
будет, чем его заинтересовать. Согласитесь, намного интересней
звучит:
мы написали 1 и 2 главу но нам не хватает художника,
чем
ну мы сейчас начнем писать новеллку у нас есть сюжет, но мы не
пишем новеллу из-за того что художника нету….
Не ждите чуда, опыт в написании к вам просто так сам не придет.
Если вы не можете без визуализации тогда возьмите, какую-нибудь
анимешку, и вырежьте от туда персонажей, временно, пока не
найдется художник.
Плюс вы всегда можете нанять художника профессионального для
вашего проекта. Зачастую от этого вы выигрываете время, у вас
будут профессиональные рисунки, а не квакозябры которые рисуют
в 1 классе. https://vk.com/topic-7553243_33290860?post=5013
Есть еще такая штука как генератор персонажей https://vk.com/topic-
76362432_35593417
И такие вот сообщества https://vk.com/ayri_attic в которых вам помогут
собрать новелле ресурсы, которая в дальнейшем вам проще будет
найти художника(ибо художник будет иметь представление что
нарисовать)

КАК СДЕЛАТЬ ПЕРЕВОД ПРОЕКТА


НА ДРУГОЙ ЯЗЫК
Существует несколько способов перевести проект, я постараюсь их
всех привести.

531
2018 Ren’Py

1) КОСТЫЛЬНЫЙ

В основном применяется начинающими переводчиками-


программистами, или если проект наворочен в плане защиты и
навыков программиста не хватает разобрать чужой код, или
переводится чужой проект без разрешения автора.
Делается просто, Производится распаковка проекта(примеры ниже) и
декомпилируется.
И потом перевод происходит в оригин файлах сценария.
Плюсы:
1) Очень быстрая скорость перевода
2) Вы ничего не пропустите от старого языка(кнопки, экраны и т.д.)
Минус:
1) В основном для разработчика, что в проекте нет мульти перевода, и
пользователям приходится самостоятельно искать версию на свой
родной язык.
2) У программиста должна быть базовые знания по ренпаю, новичек
долго будет вникать.

2) ИСТИНЫЙ

Применяется разработчиками, опытными программистами и теми, кто


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

532
2018 Ren’Py

1) Время создания перевода несколько выше, так как в экранах и


кнопках нужно специально прописывать хештеги спец. что бы в
переводе отобразилось.
Опять же, если разработчик в начале озаботился этим, и специально
все отмечал то время создания перевода ограничены самим
переводчиком
2) Возможны пропуски слов в экранах, кнопках, переменных и т.д.
Но если программист внимательный, то в переводе будет отображен
100% перевод
Остальные способы я не вижу смысла их расписывать и описывать как
они делаются. Тех 2 способов хватает на все случаи жизни.

ГОТОВИМ ПРОЕКТ К ПЕРЕВОДУ

Что бы приступить к истинному переводу, вам потребуется подготовить ваш проект.

В автоматическом переводе отображается только текст диалога, и текст который


спрашивает пользователя вы уверены что хотите выйти из игры? и т.д.

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

Текстовые кнопки, текст, и название меток и любая другая текстовая информация пишут
хештег такой _(" ")

textbutton _("Текст кнопки") action Jump("start")


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

ГОТОВИМ КОД ДЛЯ СОЗДАНИЯ ПЕРЕВОДА

Посмотрите данную статью, не вижу смысла 10 раз повторять 1 и тоже

https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=43333

533
2018 Ren’Py

КАК ВСКРЫТЬ КОД ДРУГОГО


ПРОЕКТА, НАПИСАННОГО НА
РЕНПАЕ.
Существует куча способов, как вскрыть другие проекты. Я выделил 2
варианта, которые вскроют любой проект

1) ЧЕРЕЗ СПЕЦИАЛИЗИРОВАННУЮ ПРОГРАММУ QUEST


VIEWER

Нажимаете на файл> открыть архив и выбираете архив проекта.


Извлекаете все и готово.
Скачать здесь ее https://vk.com/wall-7553243_27645
Если у вас будет такая возможность поддержите автора за его
разработку. Вам мелочь, автору приятно.

2) ХАЙКЕРСКИЙ СПОСОБ

534
2018 Ren’Py

Гарантирует 100% извлечение любого архива. Спешу предупредить


всех тех кто собирается взломать чужие проекты.
Подумайте 7 раз, а нужно ли оно вам? На этом денег не заработать.
Так как взлом ЧУЖИХ проектов с целью заработка денег называется
воровством, и наказывается уголовной ответственностью

СТАТЬЯ 272. НЕПРАВОМЕРНЫЙ ДОСТУП К


КОМПЬЮТЕРНОЙ ИНФОРМАЦИИ

(в ред. Федерального закона от 07.12.2011 N 420-ФЗ)

(см. текст в предыдущей редакции)

1. Неправомерный доступ к охраняемой законом компьютерной информации, если


это деяние повлекло уничтожение, блокирование, модификацию либо копирование
компьютерной информации, -

наказывается штрафом в размере до двухсот тысяч рублей или в размере


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

2. То же деяние, причинившее крупный ущерб или совершенное из корыстной


заинтересованности, -

наказывается штрафом в размере от ста тысяч до трехсот тысяч рублей или в


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

(в ред. Федерального закона от 28.06.2014 N 195-ФЗ)

(см. текст в предыдущей редакции)

3. Деяния, предусмотренные частями первой или второй настоящей статьи,


совершенные группой лиц по предварительному сговору или организованной группой
либо лицом с использованием своего служебного положения, -

наказываются штрафом в размере до пятисот тысяч рублей или в размере


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

4. Деяния, предусмотренные частями первой, второй или третьей настоящей статьи,


если они повлекли тяжкие последствия или создали угрозу их наступления, -

535
2018 Ren’Py

наказываются лишением свободы на срок до семи лет.

Примечания. 1. Под компьютерной информацией понимаются сведения (сообщения,


данные), представленные в форме электрических сигналов, независимо от средств их
хранения, обработки и передачи.

2. Крупным ущербом в статьях настоящей главы признается ущерб, сумма которого


превышает один миллион рублей.

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

НАЧАЛО РАБОТЫ

Для начала вам необходимо будет скачать питон 2.7 зайдите на офф
сайт и скачайте 2.7 версию https://www.python.org/downloads/
Установите его в вашем компьюторе, что бы в путях не было русских
символов.
Далее вам понадобится скачать 2 специализированых модуля

UNRPA

Проверенная временем утилита для разархивирования *.rpa


файлов. Лично я рекомендую использовать следующую утилиту.
Инструкция по установке.
Скачиваем модуль https://github.com/Lattyware/unrpa
Распаковываем ее в папку где у вас установлен python 2.7
Далее, вам потребуется создать файл unrpa.bat
Потом нажимаете правую кнопку мыши и выбираете пункт изменить
файл и пропишите в нем следующее:
for %%a IN (*.rpa) DO python unrpa -m -p C:/hijack %%apause
Инструкция как с ним работать
Перенесите жертву(архив .rpa) в папку где установлен питон 2.7
Нажимаете на файл unrpa.bat
И у вас высветится консоль с описанием хода работы.

536
2018 Ren’Py

По окончании вам потребуется нажать любую клавишу, и открыть


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

UNRPYC

Скачать модуль https://github.com/CensoredUsername/unrpyc


Превосходная простая программа для декомпиляции *.rpyc файлов.
Разработчик обещает поддержку всех Renpy 6, но так как после 6.99.9
утилита не была особо тестирована, то при возникновении ошибок не
поленитесь написать ему на гит.
Все аналогично unrpa только создаете файл unrpyc.bat и в нем
запишите
for %%a IN (*.rpyc) DO python unrpyc.py %%apause
Работать и требование у него точно такие же, кидаете файлы rpyc
нажимаете на unrpyc.bat и получаете .rpy
Немного пред истории. Когда то мне один товарищ предложир
перевести новеллу Myth (психоделика, треш, кровь, и дофига бреда,
который в середине текста сходит на нет и превращается в очень
интересный проект, но к сожилению товарищ то забил на проект но не
суть)
И я столкнулся с такой проблемой что программа по извлечению, ни
другие способы на тот момент не могли извлечь архив не повредив
файлы, а так же декомпилировать зашифрованные файлы, ибо
они все получались поврежденными. Я тогда обратился к самому
опытному программисту который асу по переводам и хакингу -
Саше(Гардарик) https://vk.com/reneen за советом, как его вскрыть,
что бы можно было извлечь текст. Он тогда меня и познакомил с
этими модулями.

537
2018 Ren’Py

Казалось было все отлично, я все извлек, но при запуске exe файла
выходила ошибка.
Я опять к нему обратился, и тогда вместе помозговав стали смотреть
историю декомпиляции, и увидели что 1 файл не смог
распаковаться и пишет ошибку. Гардарик по быстрому написал
разработчику модуля и тот через 4 дня обновил модуль, и он смог
декомпилировать его без ошибок
И там столько накручено в Myth в качестве защиты, что нельзя
удалять папку python и ехе ибо потом не работал весь проект.

СОЗДАЕМ СВОЮ ТЕМУ ЛАУНЧЕРА РЕНПАЯ

https://www.renpy.org/doc/html/skins.html

Заходим в папку где у вас установлен ренпай, Находим папку launcher и заходим в нее.
Далее копируем папку theme и вставляем ее в папку game что в папке launcher

Запускаем ваш лаунчер и вот у вас такая милая тема. Если хотите свое изображение
вставить то поменяйте изображение theme_background.jpg в папке theme

СОЗДАЕМ СВОЮ ИКОНКУ ПРОЕКТА

538
2018 Ren’Py

Поменять иконку в файле и в окне:

а) создать иконку в виде png размером 256х256px


б) назвать, скажем, "renpy-icon.png" и положить в папку game
в) добавить в "options.rpy" вторую строку:
config.window_title = u"Название игры (можно по-русски)"
config.window_icon = "renpy-icon.png"
config.windows_icon = "renpy-icon.png"
г) положить в папку проекта (туда же, где лежит папка game, а не в
саму папку game) вашу иконку игры с именем icon.ico размером
256х256 (создать можно с помощью программы по ссылке ниже)
д) скомпилировать проект (создать дистрибутивы)
е) для андроид версии нужно файл "renpy-icon.png" размером 256х256
поместить в папку вашего ренпая: renpy-sdk/rapt/templates, после чего
можно собирать андроид-версию (см. пункт 39 ЧаВо)

поменять иконку в уже скомпилированной для windows игре:


а) скачать программу IcoFX и установить её:
https://yadi.sk/d/Z57a9Fp4dhxHe
б) вытащить из архива файл "название_игры.exe"
в) открыть нашу картинку renpy-icon.png с помощью скачанной
программы icoFX (поставить точки напротив "...32bits" и "256x256")
г) выбрать пункт меню File → Save As... → "icon.ico"
д) Tools → Resource Editor... → Open → название_игры.exe (из
пункта е) → Открыть
е) выбрать появившийся файл, станут активными кнопки над ним
ж) выбрать Change "↔"
з) выбрать нашу свежесозданную иконку "icon.exe"
и) нажать дискету (Save) → теперь у файла игры новая иконка, а не
эйлин с питоном
к) вернуть файл "название_игры.exe" в архив
готово!

ВТОРОЙ СПОСОБ ПРЕДПОЧТИТЕЛЬНЕЕ, так как иконки, созданные


самим renpy, virustotal с каких-то херов определяет, как трояны, а
значит, steam игру не пропустит.

пыс-пыс: на всякий случай поясню, что исполнимый файл можно


извлечь, просто распаковав архив, исправить его и запаковать заново.
например, с помощью winrar или встроенного упаковщика windows

539
2018 Ren’Py

КАК СОЗДАТЬ ОТДЕЛЬНЫЙ АРХИВ

Как создать отдельный архив для каждого типа файлов?


(заархивировать разные файлы в разные архивы)
Не буду вдаваться в теорию - она есть тут
https://www.renpy.org/doc/html/build.html
Просто опишу процесс в 2 коротких шага

1. В файле options.rpy вам нужно будет прописать названия архивов,


которые вы хотите создать. Например:
build.a("images", "all") #Вместо "images" может быть что
угодно.rchive
build.archive("sounds", "all")
2. Когда прописываем архивацию, делаем её следующим образом:
build.classify('game/**.png', 'images') #для изображений
build.classify('game/**.jpg', 'images')
build.classify('game/**.mp3', 'sounds') #для звуков
build.classify('game/**.ogg', 'sounds')
# Подробнее о знаках звёздочки и как его использовать - читайте по
ссылке выше.

Аналогичным образом можно создать отдельные архивы для скрипта,


для видеороликов и, вообще говоря, для всего, что будет душе угодно.
> ВАЖНО:
Это не спасёт вашу игру от декомпиляции, зато будет очень просто
делать для неё патчи, в которых вы можете отдельно добавить
изображения, поменять скрипт или изменить музыку. Пользователю
нужно будет просто скопировать файлы с заменой. =)

PS
1. Не забудьте, что при этом у вас НЕ должно быть строки
build.classify('game/**.**', 'archive')
2. Все расширения, что не указаны в build.clasifsy НЕ ВОЙДУТ в
архив
3. Не забудьте прописывать build classify('saves/**.**', None) , так как
там, помимо сейвов, хранятся постоянные переменные..

САЙТЫ

1) https://vk.com/renpy

540
2018 Ren’Py

Российское крупнейшее сообщество ренпая. Тут вам всегда смогут


подсказать ответ на вашу проблему(для новичка, ибо на многие мои
вопросы никто не хочет отвечать – не тот уровень знаний, или игнор
за книгу что пишу. В обсуждениях группы собраны полезные плюшки,
мини игры, статьи.
2) https://lemmasoft.renai.us/forums/
Англоязычный сайт посвященный по большей части ренпаю. Тут вы
можете найти музыку в ваши проекты, рисунки с лицензиями, коды,
плюшки, учебники, новости. Так же там сидит сам автор ренпая –
мистер Питон, дядя Муген и другие ветераны, которые развивают
ренпай с момента его основания. Найдутся ответы на все вопросы по
питону и ренпаю.
Что бы там зарегистрироваться нужно ответить на вопрос когда был
основан ренпай ответ 2004
3) https://vk.com/cyber_z_craft
Автор, пока единственного, видео-урока по ренпаю на русском языке
(и в этом же сообществе был записан данный учебник)
4) http://renpyfordummies.blogspot.ru/
Много всяких полезных Renpy-разработчику фишек и плюшек в одном
месте
5) http://anivisual.net/
Крупнейший русскоязычный сайт разработчиков и ценителей новел (и
слабо пока – jrpg)
6) http://ru.renpypedia.shoutwiki.com/wiki/Renpy_%D0%B4%D0%BB
%D1%8F_%D1%87%D0%B0%D0%B9%D0%BD%D0%B8%D0%BA
%D0%BE%D0%B2
Русская википедия по ренпаю. Обязательна к ознакомлению!
7) http://www.animeforum.ru/index.php?showtopic=61348
Форум на котором вы найдете записи самых первых первопроходцев
ренпая. Записи тех кто создавал сайт русской вики по ренпаю.
Увидите пост из самой первой новеллы написанная русскими на
движке ренпая. И просто форум для тех кто хочет увидеть как

541
2018 Ren’Py

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


тогдашних конкурентов **Scripter, Blade Engine, Novelty

8) http://dobrochan.com/vn/index.xhtml
Анонимный форум по визуальным новеллам
9) https://translate.google.com/translate?
depth=2&nv=1&rurl=translate.google.com&sl=ja&sp=nmt4&tl=ru&u=https://
www.freem.ne.jp/win/game/16349 - через гугл переводчик
https://www.freem.ne.jp/win/category/4/page-1 - оригинал сайт
Японская версия анивизуала
10) https://itch.io/games/genre-visual-novel
Английская версия анивизуала
11) https://vndb.org/v/all
Википедия по всем новеллам
12) https://vk.com/renpy?w=wall-7553243_5103
интервью с Питоном
13) https://m.habr.com/company/miip/blog/321460/
Игры не всегда должны развлекать
14) https://core-rpg.net/articles/analytics/genre/rpg-codex-state-of-rpg-
writing
В какой глубокой заднице находится повествование современных
ролевых игр и почему
15) https://yadi.sk/i/_aumiray3WMMMk
Пример технического задания для художника по фонам
16) https://yadi.sk/i/BB7KA6ry3UjohK
Корявый пример сценария
17) https://vk.com/cyber_z_craft?w=wall-98171527_25432
Переводчики-аферисты

542
2018 Ren’Py

18) http://app2top.ru/game_development/psihotipy-igrokov-za-chto-igroki-
gotovy-platit-95619.html
Психотипы игроков: за что игроки готовы платить?
19) http://www.gamedis.ru/?p=1919
Основные ошибки на кикстарте
20) https://stopgame.ru/blogs/topic/86850
Почему женщины в России не понимают видеоигр
21) https://vk.com/cyber_z_craft?w=wall-100803289_775
Как работать с художниками
22) https://dtf.ru/18645-virtualnye-otnosheniya-kak-zastavit-igroka-polyubit-
npc
как игрока заставить полюбить нпс
23) https://vk.com/cyber_z_craft?w=wall-76362432_1055
очень полезная книга, обязательно изучите ее
24) https://vk.com/cyber_z_craft?w=away-76362432_1033
Разработка кинетической новеллы

ОБЛАКА ДЛЯ ХРАНЕНИЯ ФАЙЛОВ

http://disk.yandex.ru/ - 10 ГБ бесплатно, можно увеличить участвуя в разных


акциях, скорость высокая, приложения для Windows, Android, iOS

http://drive.google.com/ - 15 ГБ бесплатно, скорость высокая, приложения для


Windows, Android, iOS

http://onedrive.live.com/about/ru-ru/ - 15 ГБ бесплатно, скорость высокая,


приложения для Windows, Android, iOS

http://mega.co.nz - 50 ГБ бесплатно, скорость высокая, приложения для Firefox,


Chrome, Android, iOS

543
2018 Ren’Py

http://cloud.mail.ru/ - 100 Гб бесплатно, скорость высокая, приложения для


Windows, Mac, Linux amd64, Linux i386, Android, iOS, Windows Phone

http://yunpan.360.cn/ - более 36 ТБ (36864 ГБ) бесплатно, после установки


приложения на Windows дают 10 ТБ, после установки приложения на Android или Apple
смартфон добавят ещё 26 ТБ, дальше размер можно увеличивать участвуя в ежедневной
бесплатной лотереи или выполняя разные задания, скорость небольшая, приложения для
Windows, Android, iOS
Тут http://4pda.ru/forum/index.php?showtopic=497106 русифицированный клиент, для
скачивания нужна регистрация на форуме.

http://yunio.com/ - 100 ГБ бесплатно + 100 МБ каждый день, приложения для


Windows, Android, iOS, Linux

http://adrive.com/ - 50 ГБ бесплатно

http://bitcasa.com/ - 20 ГБ бесплатно, приложения для Windows, Android, iOS, Linux

http://box.com/ - 20 ГБ бесплатно, максимальный размер файла 25 МБ

http://copy.com/ - 15 ГБ бесплатно, можно раскачать до 22 ГБ, приложения для


Windows, Android, iOS, Linux

http://mediafire.com/ - 10 ГБ бесплатно

http://mimedia.com/ - 10 ГБ бесплатно

http://cubby.com/ - от 5 до 25 ГБ бесплатно

http://asuswebstorage.com/ - 5 ГБ бесплатно

http://tresorit.com/ - 5 ГБ бесплатно, максимальный размер файла 0.5 ГБ

http://wuala.com/ - 5 ГБ бесплатно

http://idrive.com/ - 5 ГБ бесплатно

544
2018 Ren’Py

http://opendrive.com/ - 5 ГБ бесплатно, максимальный размер файла 100 МБ

http://dropbox.com/ - 2 ГБ бесплатно, можно раскачать до 48 ГБ, приложения для


Windows, Android, iOS

ВСЕМ СПАСИБО! ЧТО УДЕЛИЛИ МОЕМУ МАЛЕНЬКОМУ


УЧЕБНИКУ ВНИМАНИЕ.

545

Вам также может понравиться