Everlasting Summer

Everlasting Summer

46 个评价
Как создать меню
由 AkkuChan 制作
Приветствую в данном руководстве опытных и не очень мододелов. В данном руководстве написано, как создать собственное меню и дополнения к нему в своём моде.

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

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

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

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 одинаковы, то мы просто проигрываем необходимую нам песню из изначального массива.
Послесловие
Данное руководство было написано со скуки и чтобы скидывать его людям, которые не знают, как делать меню. Ранее была мысль сделать руководство, в котором бы рассказывалось о всяких разных фичах, функциях, способах, которые могут быть полезны мододелам. Например, Галерея изображений, Музыкальная комната, замена интерфейса, автообъявления изображений, звуковых файлов и так далее.
Если вам это интересно, пишите в комментариях, и я может быть их напишу и добавлю.

Если были совершены какие-нибудь ошибки в руководстве или у вас возникли проблемы при создании меню, пишите, помогу.
28 条留言
ffpk_catalog 5 月 4 日 上午 3:19 
Нашел решение!
Вместо команды: action Call("ps_lager", transition=dissolve)
Нужно писать: action Jump("ps_lager")
Никаких transition=dissolve писать нельзя, в команде Jump этого параметра нет!
При этом переход будет без всяких эффектов, но зато он будет, без ошибок!
ffpk_catalog 4 月 30 日 上午 10:09 
Я сделал textbutton всё, как вы сказали:
screen MENU_ProgSov:

tag menu

add "ProgSov/Menu_ProgSov.jpg" # добавляем наш фон

textbutton "Пробуждение лагеря":
xpos 580 ypos 330
text_idle_color "#ffffff" text_hover_color "#e1dd7d" text_size 28 text_font "ProgSov/comicz.ttf"
action Call("ps_lager", transition=dissolve)
Но если я нажимаю на пункт, то получаю трейсбек:

Exception: Arguments supplied, but parameter list not present
DeLzagate 3 月 22 日 下午 2:49 
*прописать параметры самого текста*
DeLzagate 3 月 22 日 下午 2:46 
Можно по подробнее, если не сложно? Я просто делал по гайду твоему же и мне после textbutton нужно прописать самого текста, что я и сделал. Но со шрифтом проблема. Если я напишу условно
textbutton "старт":
font_size 50
text_idle_color "#fff" text_hover_color "#5D5D5D"

и где то между этими параметрами впихну font, то я увижу failed:
u'font' is not a keyword argument or valid child for the textbutton statement.

По твоему ответу по идее должно быть все верно (если конечно под "text" ты имеешь ввиду textbutton),
но решил написать по другому, с мыслями что возможно это имеет значение.
textbutton "старт" font "путь":

но выдает тоже самое
AkkuChan  [作者] 3 月 18 日 下午 9:30 
Можно вручную каждому нужному элементу прописывать

text "текст" font "путь к шрифту"

либо сделать стиль с ним

style navigation_button_text:
font "путь к шрифту"

и задавать этот стиль нужным элементам

text "текст" style "navigation_button_text"
DeLzagate 3 月 18 日 上午 10:37 
А как шрифты добавлять, я либо не вижу этого в гайде, либо этого в гайде нет
Ризе 2024 年 1 月 10 日 上午 1:36 
спасибо большое, все действительно работает) сам бы никогда не додумался, сидел час голову ломал
Ризе 2024 年 1 月 2 日 上午 12:00 
спасибо большое за ответ, как буду дома проверю обязательно
AkkuChan  [作者] 2024 年 1 月 1 日 下午 11:58 
Ризе, музыку можно добавить перед вызовом самого экрана меню в лейбле (как и в обычном повествовании через play music), либо добавив в экран python-блок, в котором используешь метод renpy.music.play().

Например:

screen MENU:
python:
renpy.music.play("my_music.mp3", channel="music", loop=True, fadein=1.0)
Ризе 2024 年 1 月 1 日 上午 3:27 
как добавить музыку, не в музыкальной комнате, а с самого старта меню?