Everlasting Summer

Everlasting Summer

44 ratings
Как создать меню
By AkkuChan
Приветствую в данном руководстве опытных и не очень мододелов. В данном руководстве написано, как создать собственное меню и дополнения к нему в своём моде.

Если вы хотите изучить основы мододелинга, то вам не сюда. Загляните в:

Также можете найти необходимую вам информацию в Паблике ВК:
- https://vk.com/myesmod
И документациях Ren'py:
- http://ru.renpypedia.shoutwiki.com/wiki/ (русскоязычная)
- https://www.renpy.org/doc/html/ (англоязычная)
   
Award
Favorite
Favorited
Unfavorite
Предисловие
Не хочется, чтобы данное руководство послужило толчком в появлении модов с меню, состоящим из кнопок "начать" и "выйти". Меню должно иметь практическую пользу, а не чтобы было. Это всё моё мнение, прислушиваться к нему или нет -- решать вам. Решил выговориться заранее. А теперь к руководству!

Руководство дополняется в свободное время, так что иногда некоторые разделы могут быть незаконченными некоторое время.
Плавное начало мода и появление меню в целом
Перед началом создания меню хотелось бы рассказать про плавный старт мода, т.е. плавное затухание меню выбора модов и плавное появление начала вашего мода.
Для этого вам надо всего-лишь начать мод с этих строк:

label NAME: scene bg black with dissolve # вызываем переход на всё, что сейчас на экране, а не только на фон # далее просто вызываем screen нашего меню call screen MENU with dissolve

Довольно простая вещь, однако многие её не используют.

Кстати, именно так и появляется ваше меню. NAME в label -- это то, что вы указывали в mods:

$ mods[NAME] = "Название"

С лейбла NAME и начинается ваш мод, этакая точка входа. С неё и перебрасывайте на меню.
А что насчёт собственного меню? Способ первый.
Меню можно сделать двумя способами. Либо через imagemap, либо через imagebutton. Ну, хотя можно сделать и так и так одновременно. Пойдём по порядку.

Imagemap

В Imagemap нам необходимо три картинки (можно и больше, об этом позже). Фон, неактивные кнопки и активные кнопки. (фон и неактивные кнопки при желании можно сделать одним изображением). Ренпай, при наведении на кнопку, будет "вырезать и вставлять" активную кнопку в местоположение неактивной.
Предположим, вы работаете в Photoshop'е и сделали эти самые картинки. Теперь нам нужны некоторые данные, записывайте их или запоминайте. Находим левый верхний угол вашей картинки, предположим, у меня это будет 256 по оси X и 72 по оси Y. Теперь вычисляем правый нижний угол, пусть у меня он будет 510 по X и по Y 121. Теперь мы вычитаем из них первые числа, т.е. 510-256=254 и 121-72=49. Записываем или запоминаем Левый верхний угол и разницу правого угла и левого. Т.е. (256, 72, 254, 49) (Именно так координаты и записываются в кнопку imagemap)

Но как обозначить кнопку в коде? За это у нас отвечает оператор hotspot.

screen MENU: tag menu imagemap: ground "background.jpg" idle "buttons_idle.png" hover "buttons_hover.png" hotspot (256, 72, 254, 49) action Call("START", transition=dissolve)
Теперь давайте разберёмся с вышенаписанным:
  • Мы создаем экран MENU (название заменить);
  • tag не дает нам накладывать части экранов друг на друга, то есть, если у нас есть два экрана с одним тегом, то при появлении, второй заменит первый. Также мы можем скрывать по тегу экраны;
  • ground -- это наш фон. Указываем в кавычках путь к изображению, к фону или просто пишем уже объявленное изображение (тоже в кавычках);
  • idle -- это наши неактивные кнопки, тоже указываем путь;
  • hover -- активные кнопки. Указываем путь;
  • hotspot -- наша кнопка, в скобках указываем координаты, которые получили ранее.

Но что же такое action? А это как раз таки действия, которые будет выполнять игра при нажатии на кнопку. Есть множество действий, но я распишу лишь некоторые в другом отделе (ибо action работает и в imagebutton и в imagemap), чтобы не повторяться.
А что насчёт собственного меню? Способ второй.
И вот мы добрались до второго способа, а именно imagebutton. Этот способ позволяет нам объявлять каждую кнопку отдельным изображением. Т.е. нам нужно как минимум по два изображения на кнопку, неактивная и активная. Давайте объявим её:

screen MENU: tag menu add "background.png" # добавляем наш фон imagebutton: # тут мы можем прописать как отдельно двумя строчками, так и одной
# Двумя это выглядит так:
idle "button_idle.png" hover "button_hover.png # а чтобы объявить одной строкой, нам надо, чтобы наши картинки оканчивались на _idle и _hover соответственно auto "button_%s" # Далее указываем позицию нашей кнопки, подробнее об этом в разделе Позиционирование xpos 256 ypos 72 action Call("START", transition=dissolve)

Заметили, что мы использовали add? Небольшое отступление, оператор add позволяет нам добавлять что-то на screen, например изображение.

В данном случае мы указываем только одну точку, нам не нужна длина и высота кнопки.
Главное преимущество этого метода -- возможность заменить кнопку, не меняя всё меню в фотошопе.

Про action будет наш следующий раздел.
Кстати про кнопки
Если в вашем меню кнопки -- это просто текст, то нет нужды для этого делать их изображениями, ведь можно использовать textbutton. Всё, что нам надо для этого, это шрифт, его размер в пикселях и положение. Положение текстовой кнопки работает так же, как и imagebutton.

textbutton "Здесь может быть ваша кнопка": xpos 256 ypos 72 text_idle_color "#fff" text_hover_color "#aaa" text_size 30 text_font "font.ttf" action Call("START", transition=dissolve)

textbutton, как и imagebutton, можно прописывать как блоком, так и в строку, кому как больше нравится. То есть:

textbutton "Здесь может быть ваша кнопка" xpos 256 ypos 72 text_idle_color "#fff" text_hover_color "#aaa" text_size 30 text_font "font.ttf" action Call("START", transition=dissolve)

Но блоком смотрится приятнее и читается понятнее.

Но ранее говорилось об ещё каких-то картинках для кнопок, так вот. Если в вашем меню, при переходе на другой экран, остаются элементы предыдущего, то можно использовать картинки selected_idle и selected_hover. Т.е., при нажатии на данную кнопку, эта кнопку останется выделенной, пока выполняемое ею действие активно. Если вы вызываете какой-то экран с данными операторами, то вместо Show нужно использовать ToggleScreen:

screen MENU: imagemap: ground "background.jpg" idle "buttons_idle.png" hover "buttons_hover.png" selected_idle "buttons_selected_idle.png" selected_hover "buttons_selected_hover.png" hotspot (256, 72, 512, 432) action ToggleScreen("GALLERY", transition=dissolve)

Но если вы хотите, чтобы несколько экранов были на экране, но нажимался только текущий, то пропишите в этом экране modal True.

screen GALLERY: tag menu modal True
Подробнее про action
Нам нужны кнопки, чтобы они что-то делали. Ниже я выписал одни из самых важных действий, которые понадобятся в каждом меню (или почти в каждом)

  • Call(label, *args) - завершает текущий оператор и вызывает label. В аргументах может принимать transition, т.е. каким будет переход от оператора к Лейблу.
  • Show(screen, *args) - приводит к отображению другого экрана. screen – строка, в которой указано имя экрана. Также принимает transition
  • Hide(screen, transition=None) - приводит к тому, что экран с именем screen будет скрыт, если он показан. Принимает transition.
  • Return() - возвращается к предыдущему действию. Крайне полезно, если ваше меню состоит из нескольких экранов. Этот оператор будет возвращать вас на предыдущий экран.
  • NullAction() - кнопка, которая ничего не делает. Думаю тут понятно.
  • With(transition) - оператор, который используется с другими операторами. Он задает плавность операторам, которые не принимают в себя transition. Например, Return(), MainMenu() и т.д.
  • MainMenu() - возвращает нас в главное меню, т.е. в меню Бесконечного лета.
  • Quit() - закрывает игру. Можем указать в скобках confirm=True, чтобы после нажания кнопки у нас вылезло окно подтверждения (ну та, где Юля сидит и спрашивает, хотим мы выйти или нет)

В action мы не ограничиваемся только одним действием, мы можем указать несколько через запятую. Они будут выполняться последовательно. Чтобы они выполнялись одновременно, мы просто берем все операторы в скобки, т.е.

action [MainMenu(), With(dissolve)]

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

Все они описаны в документации Ren'py: Тык[ru.renpypedia.shoutwiki.com]
Ещё немного про меню
В экранах мы можем прописывать не только imagemap, кнопки и так далее, мы также можем писпользовать таймер, python-блоки и условия.

default test_lv = None screen TEST: timer 2 action SetVariable("test_lv", True) python: renpy.pause(2, hard=True) if test_lv: imagebutton: auto "button_%s" xcenter 0.5 ycenter 0.5 action NullAction()

Таймер позволяет нам выполнить какое-либо действие через какое-то время, например через две секунды. Отсчёт начинается с момента появления экрана.
В python-блоке мы можем вызывать и прописывать какие-либо функции, будь то написанные вами или имеющиеся изначально из Ренпая и написанные кодером Бесконечного лета.
Ну с условием, думаю, всё понятно.
Позиционирование
Как же указывать положение нашей картинки/кнопки? А всё просто.
Сперва определимся, как мы указываем аргументы. Есть два способа, по пикселям и через десятичные числа, где 0.0 до 1.0 - границы нашего экрана.
Первый способ по пикселям мы указываем положение по X от 0 до 1920 на ПК (на телефонах это до 1280) и до 1080 по Y (720 на телефонах).
Второй - от 0.0 до 1.0 (можно и меньше/больше, но тогда изображение будет выходить за рамки). Этот метод лучше, ибо при портировании на телефоны, нам не нужно париться с положением кнопок, но и высчитать положение сложнее.
Ренпай сам определяет, какое вы ему указываете значение.
Если у позиции в начале стоит x или y, то оператор перемещает по соответствующей оси (указывается одно значение)

a и b -- ваши координаты

- pos(a, b), xpos a, ypos b. Изначально точка позиционирования изображения находится в верхнем левом углу изображения. Поэтому, при перемещении изображения с помощью pos, мы указываем положение именно верхнего левого угла. (например pos(0, 0) поставит изображение в левый верхний угол)

- center(), xcenter, ycenter Ренпай ставит точку позиционирования в центр изображения, т.е. вы переносите изображение за середину. (например center(0.5, 0.5) поставит изображение в центр)

Более подробно про позиционирование и ATL в целом Тут[www.renpy.org]
Галерея изображений. 1 Способ
Что же, вот и галерея изображений. Хотелось бы начать с того, что в Ренпае есть встроенная Галерея, с которой можно работать. И так же можно сделать простыми кнопками. Это всё одинаково просто.
Однако советую воздержаться от её использования, ибо с ней имеется ряд проблем, которые надо исправлять/учитывать.

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

# для создания галереи с фонами, которые открываются только после их просмотра,
# создаём постоянную переменную
default persistent.bg_1 = None # также для создания подобной галереи создаём переменную, в которую будет записываться текущий фон на экране,
# чтобы, нажав на фон, можно было его увеличить на весь экран. Если это не надо, то не пишем её
default img_now = None # и затем ставим её истинное значение после просмотра фона в сценарии label START: scene bg bg_1 $ persistent.bg_1 = True screen GALLERY(): tag menu add "background.jpg" imagebutton: if persistent.bg_1: idle "bg_1_prev" #внимание, данный фон у вас изначально в 1920х1080, следовательно, здесь он будет такого же размера. Сделайте изображение меньше и вызывайте его, но в переменную суйте фон 1920х1080. в моём случае это заранее уменьшенный фон с припиской _prev xpos 210 ypos 101 # заталкиваем в переменную название нашего фона. Если вам не надо, чтобы фон увеличивался на весь экран, просто убери строчку ниже action SetVariable("img_now", "bg bg_1"), Show("screen_img_now", transition=dissolve) # данный экран нам нужен, чтобы вызвать изображение кнопкой. Если нажать на фон, то он исчезнет
# если вам не надо, чтобы фон открывался на весь экран, просто уберите этот screen
screen screen_img_now: # делаем экран непрозрачным, чтобы случайно не тыкнуть что-нибудь ненужное modal True imagebutton: idle img_now xpos 0 ypos 0 action Hide("screen_img_now", transition=dissolve)
Галерея изображений. 2 способ
И так, вместо простых кнопок можно использовать встроенную Gallery().

default persistent.bg_1 = None # для создания галереи с помощью встроенной функции Галереи, создаем объект Галереи в init python блоке init python: bg = Gallery() # так же мы можем указать, с какой планостью будут раскрываться изображения на большой экран bg.transition = dissolve # теперь добавляем сами кнопки, добавляем изображения. В моём случае фоны bg.button("slot1") # slot1 -- название нашей кнопки. Название может быть произвольным bg.image("bg_1_prev") # Само изображение, которое будет кнопкой. Внимание, изображение не сжимается само, т.е. оно будет показываться в своём размере (как в предыдущем примере). bg.condition("persistent.bg_1") # указываем условие, при котором наш фон будет отображаться # подобное используем для каждой кнопки галереи. Либо делаем автообъявление. # теперь делаем экран самой галереи screen GALLERY(): tag menu add "background.jpg" # Добавляем кнопку на экран. В первых кавычках указываем название кнопки, созданное ранее. Затем фон, который будет отображаться при открытии (1920х1080). locked -- это то, что будет отображаться, пока кнопка недоступна. Ну и указываем положение кнопки. add bg.make_button("slot1", "bg bg_1", locked="lock.png", xpos=210, ypos=101)
Музыкальная комната
Теперь давайте разберемся с музыкальной комнатой, в которой мы можем слушать музыку.
Для удобства всего этого желательно добавлять всю музыку в массив или список, как это реализовано в оригинале БЛ (music_list["blow_with_the_fire"]. Массив music_list, "blow_with_the_fire" -- элемент массива, который хранит путь к песне.)

Объявлять их можно тупо как:
init python: my_music = dict(); my_music["music1"] = "music/music1.mp3" #или, например: music_list = dict() for mus in ["music1", "music2"]: my_music[mus] = "audio/music/" + mus + ".mp3"
Либо, что будет лучше и удобнее, делать автообъявление (об этом я когда-нибудь попозже расскажу в отдельном разделе Автообъявления)
Вообще, мы будем использовать ту же встроенную в Ренпай музыкальную комнату, в которой можно так же самому прописывать каждую строчку. Но зачастую, музыки намного больше, чем фонов, так что прописывать каждую строчку будет крайне муторно.

Предположим, у нас есть массив my_music. В нём есть несколько композиций. Нам нужно создать нашу MusicRoom.
#здесь мы задаём объект классу MusicRoom, в скобках которого можно указать плавность затухание и начала песни.
#далее делаем цикл, в котором добавляем в mr нашу музыку, которая всегда открыта.
init python: mus = MusicRoom(fadeout=0.5, fadein=0.5) for i in my_music: mr.add(my_music[i], always_unlocked = True) #далее создаём экран нашей музыкальной комнаты screen MusicRoom(): tag menu #vbox позволяет нам указывать элементы экрана сверху вниз, не указывая положение каждого. Так же можно и слева направо, только вместо vbox будет hbox. Просто указываем количество пикселей между элементами в spacing.
#далее указываем положение нашего vbox'a, (мы так же можем указать и границы, дойдя до которых, элемент перенесется. Для этого указываем либо как в hotspot, только area(a, b, c, d). Или указываем длину по ширине в xmaximum и ymaximum.
vbox: pos(500, 750) for i in my_music: spacing 5 textbutton i.replace("_", " ") text_idle_color "#aaa" text_hover_color "#ccc" text_size 30 action mus.Play(my_music[i]) #Далее нам цикл прописывает каждую кнопку. Т.е. нам не надо 20-30 песен прописывать самим. Т.к. элементы mus и my_music одинаковы, то мы просто проигрываем необходимую нам песню из изначального массива.
Послесловие
Данное руководство было написано со скуки и чтобы скидывать его людям, которые не знают, как делать меню. Ранее была мысль сделать руководство, в котором бы рассказывалось о всяких разных фичах, функциях, способах, которые могут быть полезны мододелам. Например, Галерея изображений, Музыкальная комната, замена интерфейса, автообъявления изображений, звуковых файлов и так далее.
Если вам это интересно, пишите в комментариях, и я может быть их напишу и добавлю.

Если были совершены какие-нибудь ошибки в руководстве или у вас возникли проблемы при создании меню, пишите, помогу.
23 Comments
Ризе 10 Jan @ 1:36am 
спасибо большое, все действительно работает) сам бы никогда не додумался, сидел час голову ломал
Ризе 2 Jan @ 12:00am 
спасибо большое за ответ, как буду дома проверю обязательно
AkkuChan  [author] 1 Jan @ 11:58pm 
Ризе, музыку можно добавить перед вызовом самого экрана меню в лейбле (как и в обычном повествовании через play music), либо добавив в экран python-блок, в котором используешь метод renpy.music.play().

Например:

screen MENU:
python:
renpy.music.play("my_music.mp3", channel="music", loop=True, fadein=1.0)
Ризе 1 Jan @ 3:27am 
как добавить музыку, не в музыкальной комнате, а с самого старта меню?
nineteen 2 Jul, 2023 @ 2:34pm 
да уж
SmUrFiK99 7 May, 2023 @ 4:45pm 
AkkuChan  [author] 5 May, 2023 @ 5:40am 
Проверь, отправляет ли тебя начальный лейбл на меню.
de_dust3 4 May, 2023 @ 1:43am 
После того как сделал всё максимально по инструкции меня просто кидает на пролог
Armastus 25 Apr, 2023 @ 11:19am 
Я сломаю тебе челюсть и вырву тебе гланды, подонок.
AkkuChan  [author] 25 Apr, 2023 @ 11:04am 
я