Форум Anivisual закрыт. Вы не можете создавать новые темы или писать ответы. Форум будет работать в режиме архива.
Пользователи · Поиск по форуму · · · Регистрация

Форум о визуальных новеллах » Для разработчиков » Ren'Py » Помощь по Ren'Py (Вопрос\Ответ)
Помощь по Ren'Py (Вопрос\Ответ)

Admin

#1
Сюда пользователи сайта могут писать вопросы о тех или иных функциях движка Ren'Py, а мы попытаемся на них ответить:)

Ikuku

#452
Увы, не все так просто -_- Тут сразу две проблемы. Одна - поменьше, легко решаемая: экшен Hide, очевидно, не умеет в экраны на слоях, отличных от слоя screen. Поэтому надо будет написать свою экшен-функцию, а в ней уже использовать скрытие с указанием слоя: renpy.hide_screen("name", layer = "mylayer") (да-да, без нижнего подчеркивания, в show_screen с ним, в hide - внезапно без него)
Код
python init:
    def MyHidey():
  renpy.hide_screen("name", layer="mylayer")

Вторая проблема в том, что HideInterface, судя по проведенным тестам, по окончанию user interaсtion восстановит не только интерфейс, но и свежескрытый экран тоже. То ли из-за того, что открыли мы экран в одном контексте, скрыли в другом, потом вернулись в прежний и HideInterface вернул все как было, то ли хз. Пока в голову не идет, как обойти эту проблему красиво, в общем, костыльное решение - прятать руками все открытые слои, поочередно, без HideInterface, и потом так же открывать обратно.
Сообщение отредактировал Ikuku - Вторник, 14/Ноя/2017, 16:46

AngelGrove

#454
Попытался я через функцию скрыть слой, но в итоге - ошибка cry



Ты будешь моим братиком?

dmit

#455
Вы не правильно вызываете функцию MyHidey. ей нужен хотя бы 1 аргумент.
action [Hide("inventory_screen", MyHidey), Return()]
наверно:
action [MyHidey("inventory_screen", "mylayer"), Return()]
Сообщение отредактировал dmit - Четверг, 16/Ноя/2017, 17:30
планета FOREVER!!!      Unkenbro team

Ikuku

#456
AngelGrove, первое, что вам нужно сделать - внести две правки в экшены кнопок:

Код
textbutton "Инвентарь" action [MyShown, HideInterface()]
textbutton "" action [MyHidey, Return()]


Пояснения по синтаксису:
1. Show("XXX") и Hide("XXX") - это экшены ренпи. Внутри их скобок - параметры, которые они принимают. Если вы пишете кастомную функцию, то не добавляете ее в скобки к Show, а либо заменяете Show на нее, либо просто добавляете в список после запятой. В вашем случае - заменяете.

2. Если Return() и, скажем, HideInterface() мы пишем со скобками, то кастомные экшены - без. Потому что (если вдаваться в детали) на самом деле наш кастомный экшен - не экшен, а функция. В свою очередь, цитируя доки: "экшен (кнопки) может быть функцией, которая не принимает аргументов". Т.е. функция без скобок (=не принимающая аргументы) - экшен.

MyHidey(tag, layer="...") - функция.
MyHidey - функция, которую можно использовать как экшен.

3. Код:
Код
def MyShown():
    renpy.show_screen("inventory_screen", _layer="mylayer")
def MyHidey(tag, layer=None):
    renpy.hide_screen("name", layer="mylayer")

правим на:
Код
def MyShown():
    renpy.show_screen("inventory_screen", _layer="mylayer")
def MyHidey():
    renpy.hide_screen("inventory_screen", layer="mylayer")

В вашем конкретном случае если слой и название экрана вы напрямую указываете внутри функции, то вам не нужно передавать их в нее в виде параметров.

В таком виде код должен перестать выбрасывать ошибку. При этом остается проблема с тем, что HideInterface вернет свежескрытый экран на место, и его придется еще раз скрывать кнопкой. Эту проблему надо решать дополнительно, я пока не знаю, как.

AngelGrove

#457
Ikuku, спасибо за столь подробный разбор. Всё получилось! (Если не считать проблему с двойным кликом по кнопке). Пытался найти решение проблемы с двойным нажиманием, но так и не нашел (даже на японских сайтах нет ответа) и это печально...
Ты будешь моим братиком?

Ikuku

#458
AngelGrove, дальнейшее включает мои догадки о причине проблем, я могу ошибаться.

Первая мысль была: отказаться от HideInterface() и вручную прятать все открытые экраны при показе инвентаря, и показывать их, когда его закрываем. Т.е. примерно так:
Код
def ShowInventory():
    renpy.show_screen("inventory_screen")

    renpy.hide_screen("inventory_button")
    _window_hide() # аналог оператора window hide
    renpy.restart_interaction() # для перерисовки окна игры

def HideInventory():
    renpy.hide_screen("inventory_screen")

    renpy.show_screen("inventory_button")
    _window_show() # аналог оператора window show
    renpy.restart_interaction() # для перерисовки окна игры

Вроде все должно было работать, но всплыли нюансы, касающиеся окна say. Во-первых, в скрипте надо было где-то в самом начале сделать window show, чтобы то, что выше, начало работать, во-вторых, у окна say тоже оказались проблемы с контекстом - вышеописанные функции его (окно) прячут - но почему-то не показывают. причем сама по себе структура (внутри старого скрипта):
Код
"test 123"
$ _window_hide()
pause
$ _window_show()
pause
"test 123"

точно так же как и
Код
"test 123"
$ ShowInventory()
pause
$ HideInventory()
pause
"test 123"

отрабатывает нормально (т.е. когда окно say прячется и вызывается из одного и того же контекста).

На этом этапе задача свелась к тому, чтобы не нарушать контекст, в котором работает инвентарь. И чисто технически можно сделать ужасно хитрый трюк: вынести работу с инвентарем в отдельный лэйбл, который мы будем вызывать по необходимости с помощью call inventory_label, и в нем - в одном и том же контексте! - и прятать/открывать окна.

Не могу сказать, что это прямо чистенько-аккуратно, но это работает. Вот базовый код, дополняйте/режьте/переназывайте переменные под свои нужды как угодно:
Код
init -1 python:
    # Показывает инвентарь
    def ShowInventory():
        renpy.show_screen("inventory_screen")

        renpy.hide_screen("inventory_button")
        _window_hide() # аналог оператора window hide
        renpy.restart_interaction() # для перерисовки окна игры

    # Прячет инвентарь
    def HideInventory():
        renpy.hide_screen("inventory_screen")

        renpy.show_screen("inventory_button")
        _window_show() # аналог оператора window show
        renpy.restart_interaction() # для перерисовки окна игры

    # нет прямого способа экшеном вызвать call на метку, поэтому пилим кастомный
    def CustomCall():
        renpy.call("inventory_label")

screen inventory_button:
    frame:
        xalign .5
        textbutton "Инвентарь" action CustomCall

#Экран инвентаря
screen inventory_screen:
    modal True
    frame:
        xalign .3
        textbutton "Закрыть" action Return()

label start:
    window show # эта строка нужна, чтобы _window_hide и _window_show работали
    show screen inventory_button

    "Testing inventory."
    "Lalala."

    return

label inventory_label:
    "Hi! You're inside the inventory label!"
    $ ShowInventory()
    pause
    $ HideInventory()

    return

Как он работает, пошагово:

1. При нажатии кнопки "Инвентарь" кастомный экшен вызывает служебную метку, создавая для нее новый контекст.
2. В этом контексте прямо из самой метки запускается функция "ShowInventory", которая прячет ненужные окна и показывает нужные. Лэйбл ставится на паузу (ожидаем ввод), чтобы следующая функция не закрыла инвентарь раньше времени. Окно инвентаря модальное, т.е. любые действия вне его блокируются.
3. По нажатию кнопки "закрыть", мы просто имитируем user interaction, "прожимая" паузу внутри лэйбла, скрипт идет на следующий шаг, встречает на нем функцию HideInventory, закрывает ненужные окна и открывает нужные.
4. return возвращает нас из служебной метки ровно на то место в предыдущем контексте, откуда мы ушли в инвентарь (это дает нам воможность открывать инвентарь когда вздумается, не заботясь тем, что мы забудем, куда возвращаться).

(P.S. служебная метка для работы с инвентарем одна-единственная на любое его открытие в любой момент времени, создавать по метке на каждое открытие не нужно.)
Сообщение отредактировал Ikuku - Пятница, 17/Ноя/2017, 01:04

AngelGrove

#460
И это опять я T.T Сегодня у меня очередной вопрос и даже не знаю, можно ли это реализовать...

Суть в том, что у меня есть некая комната с предметами - на предметы можно нажимать и по идеи, там должно выводиться сообщение, а затем должно возвращаться к тому, что было до нажатия на предмет. Я сделал сообщение через новый лейбл и прикрепил его к предмету, затем в лейбле, из которого я нажал на кнопку, задал условие с Return (мол если сделан прыжок на лейбл с сообщением, то выполнять Return). Всё получается, но после вывода сообщения возвращается к началу лейбла... bad
Ты будешь моим братиком?

Ikuku

#462
Реализовать можно. Детали реализации зависят от постановки задачи. Попробуйте вызывать метку с мыслями не jump'ом, а через call, потому что return с возвращением в случайное место потока работает именно с call.

В качестве примера, мы в свое время делали так:
1. Создается специальный лейбл-карта, в котором будет только "интерактивная" зона, т.е. экран с активными предметами. Закольцовываем этот лейбл любым способом (чтобы все клики не на интерактивные зоны оставляли игрока внутри лэйбла).
Код
label room_interaction:
    show screen room_interaction_screen
    pause

    jump room_interaction # это плохой способ закольцевать лейбл, потому что он добавляет "пустые" шаги в rollback, просто в качестве простой демонстрации

2. На каждую интерактивную зону вешается экшен, который переводит на соответствующий лейбл с мыслями/сообщениями. В конце этого лейбла вешается jump обратно на лейбл-карту.
Код
textbutton "Я - интерактивный объект, жмакни меня!" action Jump("object_1")

label object_1:
    hero "Я даже не хочу говорить, что думаю насчет интерактивного объекта №1!"
    jump room_interaction

3. Вывод дальше по сюжету игры из лейбла room_interaction делается по ситуации.

sa36801

#463
Доброго времени суток! Только начал осваивать RENPY, в голове бардак, много вопросов...
Подскажите, как реализовать скроллинг большого изображения, к примеру клавишами или мышью (перетаскивая зажатием кнопки, еще лучше - подводя курсор к краю экрана).

mrWebster

#464
sa36801, в Ренпи есть функция, которая считывает положение мыши, и функции, регистрирующие нажатие клавиш. Попробуйте создать экран, у которого будет своя раскладка клавиш, чтобы он, в нужный момент, двигал изображение. Это общая идея реализации такого функционала, подробнее, увы, пока не могу расписать.
Добро пожаловать во Мрак!

dmit

#465
sa36801, все довольно просто если Вас удовлетворит стандартный порт просмотра:
Код
screen edgescroll_viewport_screen():

    viewport:
        xalign 0.5 ypos 50 xysize (700, 300)

        edgescroll (150, 500) # параметр задающий прокрутку содержимого при достижении края
        mousewheel True
        arrowkeys True

        add "bg band"

Пример взят из обучающей программы :)
Сообщение отредактировал dmit - Суббота, 02/Дек/2017, 11:46
планета FOREVER!!!      Unkenbro team
Форум о визуальных новеллах » Для разработчиков » Ren'Py » Помощь по Ren'Py (Вопрос\Ответ)
Поиск: