renpy анимация в главном меню
Renpy анимация в главном меню
Способы создания Главного меню (MainMenu)
Есть множество способов создания главного меню.
Рассмотрим пару из них.
1. Меню со своим фоном и созданием контейнера с однообразными кнопками. Почти то же, что и стандартное Ren’Py меню.
2. С использованием метода «Горячих точек» (ImageMap). Но добавление точек происходит иначе.
Метод первый: Создание контейнера с кнопками.
Нужно 3 вещи:
1. Фон
2. Пустая кнопка
3. Пустая наведённая кнопка.
Фон устанавливается стандартно, в options.rpy.
А для создания кнопок нам желательно иметь 2 кнопки: обычную и наведённую (hover)
Обычная:
Наведённая:
Можно обойтись и одной кнопкой.
Заходим в screens.rpy и опускаемся до 174 строки, далее, если необходимо заменяем код.
200?’200px’:»+(this.scrollHeight+5)+’px’);»>
screen main_menu:
# Это заменяет другие меню.
tag menu
# Фон главного меню.
window:
style «mm_root»
#Непосредственно кнопки
has vbox
textbutton _(«Новая игра») action Start():
area(50,10,310,70)
background «but.png»
hover_background «but_hover.png»
textbutton _(«Загрузка») action ShowMenu(«load»):
area(50,10,310,70)
background «but.png»
. hover_background «but_hover.png»
textbutton _(«Настройки») action ShowMenu(«preferences»):
area(50,10,305,70)
background «but.png»
hover_background «but_hover.png»
textbutton _(«Справка») action Help():
area(50,10,305,70)
background «but.png»
hover_background «but_hover.png»
textbutton _(«Выход») action Quit(confirm=False):
area(50,10,300,70)
background «but.png»
hover_background «but_hover.png»
Второй метод: Использование «Горячих точек» (ImageMap)
Как и в обычном ImageMap, нам нужно иметь 2 изображения:
1.Фон
2.С отличающейся областью наведения/выделения.
1.
2.
200?’200px’:»+(this.scrollHeight+5)+’px’);»> screen main_menu:
imagemap:
ground «mmo.png»
hover «mmh.png»
alpha True
hotspot (262, 117, 497, 68) action Start()
hotspot (314, 196, 447, 32) action ShowMenu(«load»)
hotspot (314, 238, 445, 32) action ShowMenu(«preferences»)
hotspot (298, 278, 463, 32) action Help()
hotspot (270, 318, 490, 32) action Quit(confirm=False)
P.S.S. Ниже, стандартно на 218 строке, необходимо удалить/исключить из кода следующие строки:
9. В итоге получим что-то, вроде (262, 117, 497, 68). Их и необходимо вписать в координаты точки.
10. Повторяем действия 7, 8, 9 для остальных горячих точек.
Но здесь чего-то не хватает. Попробуем добавить летающие полоски, а также какой-нибудь движущейся туман.
200?’200px’:»+(this.scrollHeight+5)+’px’);»> screen main_menu:
imagemap:
#Добавляем круг, и заставляем его крутится по часовой стрелки.
add «mm/poe4.png» at RotoZoom(0, 360, 10, 50, 1, 1, rot_repeat=True, rot_anim_timebase=True,
opaque=False, xalign=-0.07, yalign=0.18)
#Добавляем туманы и всякие полосочки, и прописываем им путь движения.
add «mm/mut11.png» at Move((3.0, 1.0, 1.0, 1.0),
(-2.0, 1.0, 1.0, 1.0),
50.0, repeat=True, bounce=True, subpixel=True )
add «mm/mut10.png» at Move((-0.1, 1.0, 1.0, 1.0),
(3.0, 1.0, 1.0, 1.0), 20.0, repeat=True, subpixel=True )
add «mm/mut8.png» at Move((-0.1, 1.0, 1.0, 1.0),
(3.0, 1.0, 1.0, 1.0), 15.0, repeat=True, subpixel=True )
add «mm/mut9.png» at Move((-0.1, 1.0, 1.0, 1.0),
(3.0, 1.0, 1.0, 1.0), 20.0, repeat=True, subpixel=True )
add «mm/mut6.png» at Move((-0.1, 1.0, 1.0, 1.0),
(2.0, 1.0, 1.0, 1.0), 20.0, repeat=True, subpixel=True )
add «mm/mut5.png» at Move((2.0, 1.0, 1.0, 1.0),
(-0.1, 1.0, 1.0, 1.0), 20.0, repeat=True, subpixel=True )
add «mm/mut4.png» at Move((2.0, 1.0, 1.0, 1.0),
(-0.1, 1.0, 1.0, 1.0), 12.0, repeat=True, subpixel=True )
add «mm/mut3.png» at Move((-0.1, 1.0, 1.0, 1.0),
(1.15, 1.0, 1.0, 1.0), 13.0, repeat=True, subpixel=True )
add «mm/mut2.png» at Move((-0.1, 1.0, 1.0, 1.0),
(2.0, 1.0, 1.0, 1.0), 13.0, repeat=True, subpixel=True )
add «mm/mut1.png» at Move((4.0, 1.0, 1.0, 1.0),
(-0.1, 1.0, 1.0, 1.0), 30.0, repeat=True, subpixel=True )
ground «mmo.png»
hover «mmh.png»
alpha True
hotspot (262, 117, 497, 68) action Start()
hotspot (314, 196, 447, 32) action ShowMenu(«load»)
hotspot (314, 238, 445, 32) action ShowMenu(«preferences»)
hotspot (298, 278, 463, 32) action Help()
hotspot (270, 318, 490, 32) action Quit(confirm=False)
Скриншоты:
P.S.S.S. При использовании второго метода, после первого запуска проекта, в папке game, создастся папка cache. В ней находятся вырезанные выделенный области. Если у вас не абсолютно прямоугольные области, файл, лежащий в данной папке можно подредактировать, стерев в нём всю область, которая лишняя в горячей точки.
К примеру я стёр области с левой стороны «кнопок», ибо они у меня не идеально-прямоугольные. В итоге получилась не прямоугольная область.
Но если бы я не отредактировал файл, было бы примерно так:
И помните, встречают по одежке, не игнорируйте главное меню. Это практически первое, что видит игрок, и оно является лицом вашей визуальной новеллы. Так что, создайте поистине уникальное и прекрасное главное меню.
Lemma Soft Forums
Supporting creators of visual novels and story-based games since 2003.
Animated mainmenu background: how to do it?
Animated mainmenu background: how to do it?
#1 Post by zankizuna » Mon Jun 04, 2012 10:11 pm
Re: Animated mainmenu background: how to do it?
#2 Post by SundownKid » Mon Jun 04, 2012 11:40 pm
Re: Animated mainmenu background: how to do it?
#3 Post by Fade Lalique » Tue Jun 05, 2012 7:41 am
Re: Animated mainmenu background: how to do it?
#4 Post by Hijiri » Tue Jun 05, 2012 9:15 am
Re: Animated mainmenu background: how to do it?
#5 Post by nyaatrap » Tue Jun 05, 2012 10:26 am
Re: Animated mainmenu background: how to do it?
#6 Post by rinrin » Tue Jun 05, 2012 11:57 am
Re: Animated mainmenu background: how to do it?
#7 Post by TrickWithAKnife » Tue Jun 05, 2012 2:52 pm
The #renpy IRC channel is a great place to chat with other devs. Due to the nature of IRC and timezone differences, people probably won’t reply right away.
If you’d like to view or use any code from my VN PM me. All code is freely available without restriction, but also without warranty or (much) support.
Re: Animated mainmenu background: how to do it?
#8 Post by rinrin » Tue Jun 05, 2012 3:23 pm
Re: Animated mainmenu background: how to do it?
#9 Post by zankizuna » Wed Jun 06, 2012 10:45 am
Re: Animated mainmenu background: how to do it?
#10 Post by BlackRose4eva » Thu Jul 09, 2015 1:53 pm
I’ve also wanted to do this too and I’ve been looking at various threads in order to achieve this.
Renpy анимация в главном меню
Screens and screen language: вводная
Всегда приятно понимать, что именно делает та или иная строка кода, а не бездумно повторять их за учебником – поэтому попытаемся разобраться, как устроены экраны в Ren’Py, и как можно с ними работать.
Зачем мне все это, я просто хочу добавить в меню кнопку, которая делает «бип»!
Ну, сегодня вам хочется добавить только одну кнопку, завтра – поменять фон главного меню в зависимости от условий, послезавтра – добавить туда красивую анимированную вставку. Как говорится, дай человеку рыбу, и он будет сыт весь день, научи человека читать простой код создания экранов, и он будет с легкостью кастомизировать под себя любые игры.
Содержимое окна новеллы, написанной на Ren’Py, выводится по слоям. Стандартный набор слоев, который предоставляет Ren’Py: master (самый нижний), transient, screens, overlay (самый верхний). Каждый из них отвечает за определенный набор объектов, которые выводятся только на этом слое. Так, например, на слое master по умолчанию выводится все, что было вызвано с помощью операторов show/hide и scene – то есть, все спрайты, картинки, фоны и т.д.
Порядок слоев определяется внутри переменной config, может быть изменен и задает то, какие элементы будут расположены поверх каких. Так, например, когда вызывается экран внутриигрового меню, ваши фоны, спрайты и диалоги никуда не пропадают. Слой screens, на котором лежит меню, рисуется поверх слоя master, на котором лежат спрайты и прочая.
Вы можете создавать свои собственные слои и вставлять их в любое место в списке стандартных. Можно переопределить список слоев целиком, работая с атрибутом layers переменной config:
Что такое экраны? Зачем они нужны? Как их пощупать?
Объекты, которые мы видим на экране любой renpy-игры, называются общим термином displayables («то-что-можно-показывать»). Текст, статичная картинка, фреймы, кнопки – все это дисплейабл-объекты разных типов. Их можно бросать на слой в голом виде:
. а можно предварительно объединить экраном, если их нужно показывать и прятать сразу группой.
tl;dr: экраны – это контейнеры для объектов.
Где можно найти экран в Ren’Py? Везде. Если вы замечаете объединенные в группу объекты, скорее всего перед вами объект screen. Диалоговая коробка с текстом и портретом? Экран say. Главное меню? Экран main_menu. Маленькая менюшка перемотки и быстрого сохранения? Экран quick_menu внутри экрана say!
Если порядок отображения для экрана не задан в стилях, то выводятся они порядке очереди вызова – то, что вызвано последним, кладется на самый верх стопки.
Как вызывать/прятать экраны?
Для файла скрипта проще всего будет использовать оператор show с ключевым словом screen:
label start:
# показывает и прячет экран my_new_screen
show screen my_new_screen
hide screen my_new_screen
# показывает и прячет экран another_one с анимацией dissolve
show screen another_one
with dissolve
hide screen another_one
with dissolve
# показывает экран parametrized на слое my_layer вместо слоя screens, передавая в вызов параметры param_one и param_two
show screen parametrized(_layer = «my_layer», param_one = «test», param_two = False)
Из примера выше видно, что экраны можно вызывать с параметрами (которые потом используются внутри самого экрана, но об этом позже). Кроме того, есть набор т.н. ключевых слов – параметров, предусмотренных самим Ren’Py. Они начинаются с символа «_», и параметр _layer, который принимает имя слоя, на котором нужно отображать экран – один из таких.
Другой способ вызвать/прятать экран – с помощью питоновской функции renpy_show/renpy_hide.
# показывает и прячет экран my_screen
renpy.show_screen(«my_screen»)
renpy.hide_screen(«my_screen»)
# показывает экран another_one с анимацией dissolve
renpy.show_screen(«another_one»)
renpy.with_statement(dissolve)
# показывает экран parametrized на слое my_layer вместо слоя screens, передавая в вызов параметры param_one и param_two
renpy.show_screen(«parametrized», _layer = «my_layer», param_one = «test», param_two = False)
Третий способ – вызов/скрытие экрана через экшены Show/Hide. Использовать его следует строго в комбинации с кнопками любых видов (imagebutton, textbutton, button). Экшены выполняются по нажатию, наведению фокуса на кнопку и потере фокуса кнопкой.
В примере выше мы показываем экран my_screen по нажатию кнопки «Кнопка», используя анимацию dissolve и с параметром my_param. В отличие от предыдущих случаев для указания анимации нам не нужна дополнительная команда – за это отвечает встроенный в экшен Show параметр transition. При наведении курсора на кнопку мы показываем экран hover_screen, при отведении курсора – прячем его с анимацией dissolve.
Есть еще один способ напрямую вызывать экран. Оператор call – это два в одном, он отвечает и за вызов, и за скрытие экрана. Его поведение отличается от поведения пары show-hide. Экран, вызванный с помощью show (если он не модальный), не будет мешать прочим действиям игрока, и будет висеть в окне до тех пор, пока не встретится команда hide. Экран, вызванный с помощью call, приостановит смену слайдов, будет ждать взаимодействия с пользователем, и только тогда скроется. За взаимодействие считается, например, возвращение результата с помощью экшена Return(), или прыжок на метку с помощью Jump().
screen notification_screen:
frame:
vbox:
textbutton «Кнопка раз» action Jump(«sublabel»)
textbutton «Кнопка два» action Return()
label start:
call screen notification_screen
«Если ты видишь этот текст, то ты нажал кнопку два, чтобы скрыть окно.»
label sublabel:
«Если ты видишь этот текст, то ты нажал кнопку раз, чтобы прыгнуть на метку. Как побочный эффект, скрылось окно.»
От поведения модального окна, вызванного show, поведение окна, вызванного с помощью call, отличается тем же – модальное окно исчезнет только после прямой команды hide, тогда как called-окну достаточно конца взаимодействия.
У оператора call тоже есть python-аналог: renpy.call_screen()
Несмотря на то, что пишется в документации, with с call не работает (на момент написания тестировалось в версии 6.99.9).
Объявляют новый экран с помощью оператора screen.
Лирическое отступление: то, каким будет любой созданный объект, задается с помощью параметров и свойств.
Параметры – это то, без чего объект не может быть объектом (стул будет стулом, если у него есть ножки, сиденье и спинка). Свойства – это то, что отличает объект от других (стул может быть деревянный или пластиковый, сиденье – мягким или жестким. )
Отступление от лирического отступления: «Объект не может существовать без параметров? Но как же, ведь есть необязательные параметры!» Да, пользователю не обязательно их задавать (потому что у них есть некоторое значение по умолчанию), но для существования объекта они все еще обязательны.
Чтобы еще больше вас запутать контекстами: пользователь может приказать screen-объекту принимать свои собственные параметры!
Ладно, вернемся на рельсы, хватит лирических отступлений.
Для экрана my_screen, объявленного выше, my_screen (имя) – это значение параметра. Оператор screen принимает единственный параметр: имя экрана. Свойств у оператора screen пять:
modal: если это свойство установлено в True, экран будет модальным. Модальный экран блокирует действия пользователя с элементами вне этого экрана (за исключением стандартных хоткеев). Как пример – встроенный экран да/нет при сохранении, загрузке и выходе из игры у Ren’Py является модальным.
tag: задает экрану тег. Несколько разных экранов могут делить один и тот же тег на всех, и тогда при вызове любого из них по имени, закрываются все остальные, имеющие тот же тег. На примере внутриигрового меню: экраны настроек, сохранения, загрузки – это три разных экрана, имеющие один и тот же тег. Если мы вызовем экран настроек, потом из него вызовем экран сохранения, экран настроек спрячется автоматически.
zorder: отвечает за порядок расположения экранов на слое. Принимает числовые значения, чем больше число, тем выше положение экрана относительно других. По умолчанию у всех экранов zorder – 0.
variant: если кратко, то эта переменная указывает на тип устройства, к которому будет привязан этот экран (пк, планшеты, и т.д.) Подробнее можно почитать в мануале. https://www.renpy.org/doc/html/screens.html#screen-variants
style_prefix: задает префикс стилям всех дочерних объектов экрана, если у них не задан стиль на более глубоком уровне.
Работу с префиксами и суффиксами и стилизацию объектов в деталях разберем позже, это тема отдельного гайда.
Стоит помнить, что совсем не обязательно перечислять сразу все свойства при объявлении объекта. Можно ни одного, можно часть.
Язык работы с экранами включает в себя набор операторов, которые помогают управлять содержимым экрана.
Условный оператор if работает абсолютно так же, как if в прочих блоках. Если условие выполняется, заключенный в него блок тоже выполняется. Если нет – блок будет проигнорирован.
Условный оператор showif похож на оператор if: если условие соблюдено, то пользователь видит заключенный в это условие блок. Однако работает showif несколько иначе.
Во-первых, блок в ложном условии оператора showif полностью отработает и отрендерится, но будет скрыт, тогда как блок в ложном условии оператора if будет проигнорирован компилятором.
Вторая большая польза – и большое отличие showif в том, что как только условие выполнится, для блоков внутри этого условия сработает событие show (и, соответственно, когда условие станет ложным, для них сработает событие hide). Это удобно использовать в связке с ATL (трансформациями), которые умеют запускать анимацию по каждому триггеру событий show и hide.
Оператор showif триггерит три вида событий:
appear: срабатывает, если при первом вызове экрана условие истинно, сразу отображая дочерний блок.
show: срабатывает при каждом обращении условия из ложного в истинное
hide: срабатывает при каждом обращении условия из истинного в ложное
Оператор if при изменении истинности условий события не триггерит.
transform cd_transform:
xalign 0.5 yalign 0.5 alpha 0.0
screen countdown():
default n = 3
vbox:
textbutton «3» action SetScreenVariable(«n», 3)
textbutton «2» action SetScreenVariable(«n», 2)
textbutton «1» action SetScreenVariable(«n», 1)
textbutton «0» action SetScreenVariable(«n», 0)
showif n == 3:
text «Three» size 100 at cd_transform
elif n == 2:
text «Two» size 100 at cd_transform
elif n == 1:
text «One» size 100 at cd_transform
else:
text «Liftoff!» size 100 at cd_transform
label start:
call screen countdown
Оператор for – это итератор. С его помощью можно заставить определенный блок кода отработать несколько раз или последовательно пройти по массиву или словарю данных. Захотели мы, например, анимировать падающий снег, и для этого нам нужно вывести на экран сотню изображений снежинок. Оператор for в этом поможет.
Кроме повторения блоков, цикл for можно использовать для прохода по массивам и/или словарям с данными. Скажем, для создания экрана инвентаря – вывода списка того, что завалялось у героя в карманах:
screen inventory_screen:
frame:
has vbox
# в переменную i будет помещен элемент массива, соответствующий текущему шагу, начиная с самого первого элемента массива, заканчивая последним.
for i in inv_array:
text «[i]»
# в переменную id будет помещаться ключ текущего шага, в item – соответствующий этому ключу элемент
for id, item in inv_dict.items():
text «Объект [id]: [item]»
В примере выше inv_array – массив, inv_dict – словарь, их структура и работа с ними отличается. Словарь позволяет сделать привязку элементов к ключу. Перед тем, как запускать цикл по словарю, нужно превратить его в итерабельный объект, для этого используется метод .items(). Он возвращает массив пар (ключ, элемент), т.е., для нашего примера – массив: [ («001», «корзина»), («002», «картина»). ]. На каждом шаге цикл будет получать кортеж из двух переменных (tuple), соответственно, для хранения тоже нужно две переменных: id, item.
В отличие от массивов, словари – неупорядоченная структура. Элементы в словаре не будут держаться в том порядке, в каком вы их туда внесли. Если для вас это важно, придется дополнительно использовать сортировку.
Оператор default задает значение переменной по умолчанию. Это удобно, если внутри экрана мы используем некоторую переменную, которую можем не передать в качестве аргумента, или не объявить заранее. Если не использовать оператор default, и попытаться вызвать экран с несуществующей переменной, это вызовет ошибку.
screen my_screen:
default some_var = 42
frame:
text «Значение переменной: [some_var]. Переменная будет всегда определена, даже если ее не передали в качестве параметра и не объявили внутри экрана.»
Оператор on позволяет отслеживать срабатывание событий и при срабатывании выполнять заданные вами действия. В качестве параметра on принимает имя отслеживаемого события, одного из четырех допустимых:
show: срабатывает при каждом вызове экрана с помощью show или call, если этот или все экраны с таким же тегом до этого были скрыты.
hide: срабатывает при каждом скрытии экрана с помощью hide, если до этого был вызван этот или любой экран с таким же тегом.
replace: срабатывает если текущий экран подменяет экран с таким же тегом.
replaced: срабатывает, если текущий экран подменяется новым экраном с таким же тегом.
screen test_screen:
default text = «»
frame:
text «[text]»
on «show» action SetVariable(«text», «Сработало событие show»)
on «replace» action SetVariable(«text», «Сработало событие replace»)
Оператор use позволяет включать один экран внутрь другого. В качестве параметра принимает имя включаемого экрана. Включаемый экран унаследует все параметры, переданные родительскому.
Один и тот же экран можно включить в другой в нескольких экземплярах.
screen main_scr:
frame:
has vbox
for i in xrange(1,4):
use child_scr(i)
screen child_scr(i):
text «Экран [i]»
label start:
show screen main_scr
pause
У оператора use есть единственное свойство, id. Оно работает в том случае, если два экрана с одинаковым тегом включают в себя один и тот же дочерний экран. Если родительские экраны сменяют друг друга, то на дочернем это не сказывается, и он сохраняется в том состоянии, в котором был до подмены.
В примере ниже у дочернего экрана common есть анимированный элемент. Если подменить один родительский экран (s1) на другой (s2) до завершения анимации, анимация не будет прервана.
transform trf:
xpos 500
linear 5.0 xpos 0
screen common:
text «Test» at trf
screen s1:
tag s
use common id «common»
text «s1» ypos 100
screen s2:
tag s
use common id «common»
text «s2» ypos 100
label start:
show screen s1
pause
show screen s2
pause
return
Связка use и transclude: сквозное включение.
Оператор use можно использовать так: