Пользователи · Новые посты · Правила форума · Поиск по форуму · · · Регистрация
  • Страница 1 из 1
  • 1
Форум о визуальных новеллах » Для разработчиков » Ren'Py » Помогите с созданием экрана (screen)
Помогите с созданием экрана (screen)

MH
Дата: Среда, 13 Декабря 2017, 00:55 | Сообщение # 1
Проверенный
Сообщений: 12
Награды: 0
Репутация: 0
Замечания: 0%
Привет.
Помогите, плиз, гуманитарию - в программировании почти не разбираюсь, и при создании новеллы столкнулся с трудностями. Суть проблемы такая - нужно создать экран, как на приложенной картинке используя свойства drag and drop - т.е. чтобы объекты можно перетаскивать.

Описание экрана:
1) Есть несколько условных объектов (1,2, 3...), которые можно перетаскивать по экрану.
2) Есть две неподвижных зоны, зона №1 и зона №2, куда эти объекты можно сбрасывать, после чего объекты должны пропадать, вернув некоторые переменные (ну, допустим. если сбросить объект 1 в зону 1, то переменная answer станет равной 42) не прерывая работу с экраном
3) Зона №3 - информационная - там выводятся сообщения о всех манипуляциях с объектами (допустим "объект 1 сброшен в зону №1") Также там должны выводиться сообщения, если просто кликнуть по объекту, но никуда его не тащить (пример "это объект 5 - переместите его в зону 1 или зону 2")
4) В правом нижнем углу отображается значение переменной, которая увеличивается или уменьшается в зависимости от того, какой объект куда сброшен. Условно говоря - это мана, она расходуется на операции с объектами, но может и возрастать, если нужный объект попадет в нужную зону.
5) в левом нижнем углу - кнопка возврата/выхода.

Собственно, в мануале по renpy есть код, позволяющий реализовать нечто подобное (пример с детективами):

Код
init python:

    def detective_dragged(drags, drop):

        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 "Ivy"
            child "ivy.png"
            droppable False
            dragged detective_dragged
            xpos 10 ypos 10
            
        if game:
            drag:
                drag_name "Zack"
                child "zack.png"
                droppable False
                dragged detective_dragged
                xpos 10 ypos 300

        # The cities they can go to.
        drag:
            drag_name "London"
            child "london.png"
            draggable False
            xpos 450 ypos 100
            
        if game:
                drag:
                    drag_name "Paris"
                    draggable False
                    child "paris.png"
                    xpos 450 ypos 300


Этот код худо бедно позволяет мне создать зоны №1 и №2 плюс перемещаемые drag-объекты, но с остальным полный провал. Когда читаю мануалы на английском, просто башка трещать начинает от всех этих функций.
Подскажите хотя бы примерно как должен выглядеть код, реализующий все пять пунктов.
Если лень писать весь код (я Вас понимаю...) подскажите хотя бы как сделать зону №3 и как сделать, чтобы переменным присваивались разные значения в зависимости от того, какой объект куда сброшен.
Помогите, плиз.
Прикрепления: 7152371.jpg(99.7 Kb)

Ikuku
Дата: Среда, 13 Декабря 2017, 14:14 | Сообщение # 2
Проверенный
Сообщений: 23
Награды: 2
Репутация: 80
Замечания: 0%
1. Первое, что нужно - это экран, который, во избежание ненужных кликов вне его, будем вызывать командой call. В этот экран мы запихнем все нужные зоны и кнопки.

Объекты - это draggable drag-объекты. Их можно таскать и бросать, но нельзя бросать на них. Неподвижные зоны 1 и 2 - это droppable drag-объекты. На них можно бросать, но их нельзя таскать. За это отвечают свойства draggable и droppable, которые мы установим в False для соответствующих зон.

2. Инфо-зона (№3) будет фреймом с текстом внутри. Нам от нее требуемтся только чтобы она выводила на экран содержимое переменной. Назовем эту переменную current_message, и зададим ей дефолтное значение оператором default.

3. Функции. Для объектов нам нужно два вида функций: срабатывание по клику и срабатывание по перетаскиванию и сбросу. Первая функция устанавливается в свойстве clicked drag-объекта. Вторая - в свойстве dropped.

От функции по клику нам пока требуется исключительно смена сообщения. Т.е. изменение значения переменной current_message в зависимости от кликнутого объекта. Т.е. внутри функции должно быть что-то вроде:

если кликнутый объект == объекту 1:
запихнуть в переменную current_message такой-то текст
иначе если кликнутый объект == объекту 2:
запихнуть в переменную current_message сякой-то текст

И так далее. Current_message нам доступна внутри функции (надо только объявить, что мы обращаемся именно к ней, с помощью оператора global). А что насчет "кликнутый объект"? А текущий кликнутый объект мы, по идее, должны были бы передать в виде параметра в функцию-обработчик клика, но! В свойство clicked мы должны положить такую функцию, которая не принимает параметров (так уж оно устроено). Так как сказать функции о том, на какой именно объект клацнули? Тут два способа. Один - с помощью curried-функций, это долго объяснять, можете сами почитать вот тут: https://lemmasoft.renai.us/forums/viewtopic.php?p=319388#p319388 (это тема!). Второй чуть проще для понимания: мы заводим глобальную переменнию currently_clicked, в которую будем класть идентификатор текущего объекта.

Итак, код (пока в ошметках, потом в конце будет целиком код проекта):
для curried-функции:
Код
def object_clicked(objId):
    global current_message

    if objId == 1:
        current_message = "Вы кликнули на объект %s" % objId
    if objId == 2:
        current_message = "Вы жмякнули на объект %s" % objId
    return None

curriedObjClicked = renpy.curry(object_clicked)

drag:
    drag_name "Айви"
    droppable False
    clicked curriedObjClicked(1)


Для комбо с SetVariable:
Код
def object_clicked():
    global current_message, objId

    if objId == 1:
        current_message = "Вы кликнули на объект %s" % objId
    if objId == 2:
        current_message = "Вы жмякнули на объект %s" % objId
    return None

drag:
    drag_name "Зак"
    droppable False
    clicked [ SetVariable("objId", 2), object_clicked ]

Во втором случае список функций/экшенов в свойстве clicked берется в квадратные скобки, а функция object_clicked там же вызывается без круглых скобок (это важно).

4. С кликом разобрались. Что с перетаскиванием и сбросом? Тут все проще, потому что функция внутри свойства dragged получает два параметра: объект, который бросили, и объект, в который бросили. То есть просто пишем функцию (код ниже).

Комментарии по коду:
drags[0].drag_name переводится как "возьми значение атрибута drag_name первого объекта в списке перетаскиваемых объектов" (он у нас единственный, мы таскаем объекты по одному). drags - это массив объектов, drags[0] берет из него первый элемент (нумерация списков/массивов идет с нуля)
drop.drag_name перевдится как "возьми значение атрибута drag_name объекта, на который уронили тягаемый объект". поскольку наша дроп-зона по сути своей - тоже draggable-объект, только с иными свойствами, его имя хранится в том же атрибуте.

Внутри if'ов можно задавать значения переменным по своему усмотрению и в зависимости от нужд: вычитать очки из общего числа очков маны, менять сообщения и менять значения других переменных, которые будут управлять отображением объектов на экране. Обратите внимание на условие вывода на экран объекта "Камень".

5. Кнопка возврата/выхода будет прятать наш экран экшеном Return.

Код тестового проекта:
Код
default current_message = ""
default mana_points = 42
default stones_left = 3

init python:
    def object_dragged(drags, drop):
        global current_message, mana_points, stones_left

        if not drop:
            return

        if drags[0].drag_name == "Атака" and drop.drag_name == "Враг":
            mana_points -= 10
            current_message = "Отличным ударом вы прожгли во враге дыру!"

        if drags[0].drag_name == "Атака" and drop.drag_name == "Герой":
            mana_points -= 10
            current_message = "Какое нелепое самоубийство!"
            # return True # этой командой мы можем закрыть окно и прыгнуть на метку конца игры, например!

        if drags[0].drag_name == "Камень":
            current_message = "Герой бросается камнями."
            stones_left -= 1

        if drags[0].drag_name == "Шутка":
            current_message = "Ого! Какой смешной, оказывается, %s!" % drop.drag_name.lower()

        renpy.restart_interaction()
        
        return None

    def object_clicked(objId):
        global current_message

        if objId == 1:
            current_message = "Вы кликнули на объект %s" % objId

        else:
            current_message = "Вы жмякнули на объект %s" % objId

        renpy.restart_interaction()
        return None

    curriedObjClicked = renpy.curry(object_clicked)

screen objects_screen:
    draggroup:
        xysize(1.0, 1.0)

        # Объект
        drag:
            drag_name "Атака"
            droppable False
            clicked curriedObjClicked(1)
            dragged object_dragged
            xalign .5 yalign .4

            label "Файербол" background "#000"

        # Объект
        if stones_left > 0:
            drag:
                drag_name "Камень"
                droppable False
                clicked curriedObjClicked(3)
                dragged object_dragged
                xalign .5 yalign .5

                label "Камень" background "#000"

        # Объект
        drag:
            drag_name "Шутка"
            droppable False
            clicked curriedObjClicked(2)
            dragged object_dragged
            xalign .5 yalign .3

            label "Шутеечка за триста" background "#000"

        # Зона слева
        drag:
            drag_name "Враг"
            draggable False

            frame:
                xysize(.3, .7)
                background "#000"
                text "Кинуть во врага"

        # Зона справа
        drag:
            drag_name "Герой"
            draggable False
            xalign 1.0
            
            frame:
                xysize(.3, .7)
                background "#000"
                text "Наложить на себя"

    # Третья зона, контейнер для сообщений
    frame:
        xysize(.7, .3)
        xalign .5
        yalign 1.0
        background "#000"

        text current_message xalign .5

    # кнопка выхода
    textbutton "Выход" action Return xalign .1 yalign .9

    # Индикаторы
    vbox:
        xalign .9 yalign .9
        label "Очки маны: %s" % mana_points
        label "Камней в карманах: %s" % stones_left

label start:
    call screen objects_screen

    "Конец!"

MH
Дата: Среда, 13 Декабря 2017, 15:08 | Сообщение # 3
Проверенный
Сообщений: 12
Награды: 0
Репутация: 0
Замечания: 0%
Огромное спасибо за помощь с кодом! И отдельная благодарность - за развёрнутое описание реализации всех функций. Теперь чуть лучше понимаю, как оно должно работать.
Ещё раз спасибо love Ушел разбираться)

sergey0804
Дата: Суббота, 10 Марта 2018, 22:14 | Сообщение # 4
Проверенный
Сообщений: 5
Награды: 0
Репутация: 0
Замечания: 0%
Помогите пожалуйста куда вставить этот кусочек кода screen main_menu:
imagemap:
ground "mmo.png"
hover "mmh.png"
alpha True

hotspot (165, 206, 360, 85) action Start()
hotspot (762, 219, 360, 77) action ShowMenu("load")
hotspot (157, 314, 395, 94) action ShowMenu("preferences")
hotspot (156, 428, 346, 86) action Help()
hotspot (914, 517, 253, 97) action Quit(confirm=False)
а то не пойму. мой вк https://vk.com/sergey0804
Заранее спасибо)


Разработчик.

dmit
Дата: Воскресенье, 11 Марта 2018, 01:53 | Сообщение # 5
Проверенный
Сообщений: 118
Награды: 0
Репутация: 17
Замечания: 0%
Закомментированные строки можно просто удалить
Код
## Экран главного меню #########################################################
##
## Используется, чтобы показать главное меню после запуска игры.
##
## https://www.renpy.org/doc/html/screen_special.html#main-menu

screen main_menu():

    ## Этот тег гарантирует, что любой другой экран с тем же тегом будет
    ## заменять этот.
    tag menu

    style_prefix "main_menu"
    
    imagemap:
        ground "mmo.png"
        hover "mmh.png"
        alpha True
        
        hotspot (165, 206, 360, 85) action Start()
        hotspot (762, 219, 360, 77) action ShowMenu("load")
        hotspot (157, 314, 395, 94) action ShowMenu("preferences")
        hotspot (156, 428, 346, 86) action Help()
        hotspot (914, 517, 253, 97) action Quit(confirm=False)
        
#     add gui.main_menu_background

    ## Эта пустая рамка затеняет главное меню.
#    frame:
#         pass

    ## Оператор use включает отображение другого экрана в данном. Актуальное
    ## содержание главного меню находится на экране навигации.
#    use navigation

#    if gui.show_name:

#         vbox:
#             text "[config.name!t]":
#                 style "main_menu_title"

#             text "[config.version]":
#                 style "main_menu_version"


планета FOREVER!!!

Сообщение отредактировал dmit - Воскресенье, 11 Марта 2018, 01:54

sergey0804
Дата: Воскресенье, 11 Марта 2018, 11:52 | Сообщение # 6
Проверенный
Сообщений: 5
Награды: 0
Репутация: 0
Замечания: 0%
Цитата dmit ()
Закомментированные строки можно просто удалить
Код
## Экран главного меню #########################################################
##
## Используется, чтобы показать главное меню после запуска игры.
##
## https://www.renpy.org/doc/html/screen_special.html#main-menu

screen main_menu():

    ## Этот тег гарантирует, что любой другой экран с тем же тегом будет
    ## заменять этот.
    tag menu

    style_prefix "main_menu"
    
    imagemap:
        ground "mmo.png"
        hover "mmh.png"
        alpha True
        
        hotspot (165, 206, 360, 85) action Start()
        hotspot (762, 219, 360, 77) action ShowMenu("load")
        hotspot (157, 314, 395, 94) action ShowMenu("preferences")
        hotspot (156, 428, 346, 86) action Help()
        hotspot (914, 517, 253, 97) action Quit(confirm=False)
        
#     add gui.main_menu_background

    ## Эта пустая рамка затеняет главное меню.
#    frame:
#         pass

    ## Оператор use включает отображение другого экрана в данном. Актуальное
    ## содержание главного меню находится на экране навигации.
#    use navigation

#    if gui.show_name:

#         vbox:
#             text "[config.name!t]":
#                 style "main_menu_title"

#             text "[config.version]":
#                 style "main_menu_version"


выбило такую ошибку
Код
[code]
I'm sorry, but an uncaught exception occurred.

While loading <'Image' u'mmh.png'>:
IOError: Couldn't find file 'mmh.png'.

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_main_menu.rpym", line 28, in script
    python hide:
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\ast.py", line 848, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\python.py", line 1812, in py_exec_bytecode
    exec bytecode in globals, locals
  File "renpy/common/_layout/screen_main_menu.rpym", line 35, in <module>
    ui.interact()
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\ui.py", line 287, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\core.py", line 2624, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, **kwargs)
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\core.py", line 3098, in interact_core
    self.draw_screen(root_widget, fullscreen_video, (not fullscreen_video) or video_frame_drawn)
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\core.py", line 2038, in draw_screen
    renpy.config.screen_height,
  File "render.pyx", line 485, in renpy.display.render.render_screen
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\layout.py", line 711, in render
    surf = render(child, width, height, cst, cat)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\layout.py", line 711, in render
    surf = render(child, width, height, cst, cat)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\layout.py", line 711, in render
    surf = render(child, width, height, cst, cat)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\screen.py", line 639, in render
    child = renpy.display.render.render(self.child, w, h, st, at)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\layout.py", line 711, in render
    surf = render(child, width, height, cst, cat)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\layout.py", line 711, in render
    surf = render(child, width, height, cst, cat)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\layout.py", line 711, in render
    surf = render(child, width, height, cst, cat)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\behavior.py", line 715, in render
    rv = super(Button, self).render(width, height, st, at)
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\layout.py", line 1138, in render
    back = render(style.background, bw, bh, st, at)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\imagemap.py", line 50, in render
    cr = render(self.child, width, height, st, at)
  File "render.pyx", line 145, in renpy.display.render.render
  File "render.pyx", line 233, in renpy.display.render.render
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\im.py", line 580, in render
    return cache.get(self, render=True)
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\im.py", line 266, in get
    surf = image.load()
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\display\im.py", line 625, in load
    surf = renpy.display.pgrender.load_image(renpy.loader.load(self.filename), self.filename)
  File "C:\Users\Людмила\Desktop\Проект\renpy-6.99.14.1-sdk\renpy\loader.py", line 555, in load
    raise IOError("Couldn't find file '%s'." % name)
IOError: Couldn't find file 'mmh.png'.

Windows-8-6.2.9200
Ren'Py 6.99.14.1.3218
school 1.0
Sun Mar 11 11:50:50 2018


Разработчик.

sergey0804
Дата: Воскресенье, 11 Марта 2018, 12:04 | Сообщение # 7
Проверенный
Сообщений: 5
Награды: 0
Репутация: 0
Замечания: 0%
а всё исправил ошибку)

Разработчик.

dmit
Дата: Воскресенье, 11 Марта 2018, 15:21 | Сообщение # 8
Проверенный
Сообщений: 118
Награды: 0
Репутация: 17
Замечания: 0%
Не найден файл mmh.PNG . Куда его положил?

планета FOREVER!!!
Форум о визуальных новеллах » Для разработчиков » Ren'Py » Помогите с созданием экрана (screen)
  • Страница 1 из 1
  • 1
Поиск: