Многослойные изображения (Layered Images)

Материал из Ren'Py Wiki
Перейти к навигации Перейти к поиску

Когда набор спрайтов достигает определенного уровня сложности, определение каждой возможной комбинации может вызвать трудности. Например, 4 спрайта с нарядами, 4 с прическами и 6 с эмоциями уже имеют 96 возможных комбинаций. Создание статических изображений для каждой возможной комбинации потребует много места на диске и времени на программирование.

Для решения этой проблемы в Ren'Py есть способ определения изображения, состоящего из нескольких слоёв (Для этого будем рассматривать слои, как слои в программе рисования, например как в Photoshop или GIMP, а не как слои, используемые в Ren'Py). Слои могут отображаться без каких-либо условий или могут выбираться по атрибутам, предоставленным изображению, или условиям, которые проверяются во время выполнения кода.

Чтобы упростить определение многослойных изображений, в Ren'Py есть оператор layeredimage, который вводит предметно-ориентированный язык, позволяющий определить многослойное изображение. Также существует объект LayeredImage(), который не является изображением, но может быть назначен оператору image и использоваться как таковой.

Определение многослойных изображений (Defining Layered Images)[править | править код]

Предметно-ориентированный язык для определения многослойного изображения состоит всего из нескольких операторов. Один из которых также является оператором скриптового языка для представления изображения, за которым следуют операторы для представления слоёв и групп слоёв.

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

layeredimage augustina:

    always:
        "augustina_base"

    group outfit:

        attribute dress:
            "augustina_outfit_dress"

        attribute jeans:
            "augustina_outfit_jeans"

    group eyes:

        attribute open default:
            "augustina_eyes_open"
            default True

        attribute wink:
            "augustina_eyes_wink"

    group eyebrows:

        attribute normal default:
            "augustina_eyebrows_normal"

        attribute oneup:
            "augustina_eyebrows_oneup"

    group mouth:

        pos (100, 100)

        attribute smile default:
            "augustina_mouth_smile"

        attribute happy:
            "augustina_mouth_happy"

    if evil:
        "augustina_glasses_evil"
    else:
        "augustina_glasses"

Это значительная часть скрипта, но она очень четко организованна. Ниже мы покажем, как её упростить.

Прежде всего, оператор layeredimage водит многослойное изображение с именем спрайта. Этот оператор является частью языка сценариев Ren'Py и выполняется во время инициализации.

Блок многослойного изображения может содержать операторы always, group и if. Оператор group может принимать атрибуты. Операторы always и if необходимо снабдить отображаемыми объектами, в то время как в оператор attribute может быть дополнительно поставлен один отображаемый объект. Всем операторам могут быть предоставлены свойства.

Оператор always объявляет слой, который всегда отображается, как фон спрайта.

Оператор group вводит группу атрибутов, в которой одновременно может отображаться только один из атрибутов. Таким образом, это многослойное изображение может иметь только один наряд и одну позицию для каждого глаза, брови и рта. Свойства, заданные группе, передаются атрибутам и группа может автоматически объявлять атрибуты.

Оператор attribute вводит слой, который отображается, если к изображению предоставлен атрибут. Например, "augustina_outfit_dress" отображается только в том случае, если указан атрибут "dress". Если задано ключевое слово default, атрибут отображается, если нет противоречащих атрибутов. В примере, приведённом выше, "augustina_eyes_open" отображается, если только не задан атрибут "wink".

Наконец, оператор if добавляет слой, который выбирает между отображаемыми объектами, используя оператор языка программирования Python. Он постоянно оценивается и первое условие, которое определяется как истинное, это то, которое отображается.

Свойства состоят из имени свойства и простого выражения, и могут быть заданы для каждого слоя. Некоторые свойства изменяют работу оператора. Если задано одно или несколько свойств преобразования, создаётся класс Transform(), который создаёт "обертку" для отображения. Свойству at может быть задано преобразование или список преобразований, которые также оборачивают отображаемый объект. Например, свойство pos в данном примере создаёт преобразование, которое перемещает верхний левый угол каждого изображения рта.

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

Группы и атрибуты могут появляться в многослойном изображении несколько раз, при этом все слои отображаются с атрибутом.

Использование многослойного изображения (Using an Layered Image)[править | править код]

Чтобы использовать эти (но не другие) многослойные изображения, переменной evil необходимо присвоить значение, например:

default evil = True

После этого многослойное изображение можно показать, как и любое другое изображение. Скорее всего, следует задать один из нарядов, но при этом Ren'Py не применит его, для отображения изображения наряда требуется:

show augustina jeans

Пока отображается спрайт, дополнительные атрибуты будут добавлены к уже показанным, при условии, что они не конфликтуют. Это относится ко всем версиям Ren'Py, когда отображаемое изображение не совпадает с тем, которое уже определено, что никогда не происходит с многослойным изображением. Так,

show augustina wink

активирует слои, связанные с атрибутом wink. Мы может остановить подмигивание с помощью:

show augustina open

Это открытие глаз конфликтует с подмигиванием. Или мы можем просто удалить атрибут wink, используя:

show augustina -wink

, чтобы отобразить слои с атрибутом open, так как это значение по умолчанию.


Также многослойные изображения можно использовать с оператором scene.

Автоматические атрибуты (Automatic Attributes)[править | править код]

Наш первый пример часто повторяется, когда речь идёт об именах атрибутов и отображаемых объектах, которые определяют атрибут. Чтобы избавить вас от лишней работы, Ren'Py может автоматически определять имя отображаемого объекта по имени изображения, имени группы и имени атрибута. Это делается путём объединения имён с подчеркиванием. При этом можно воспользоваться ещё одной особенностью атрибутов – можно добавить любые свойства в первую строку и полностью опустить блок.

Вот пример того, как это делается:

layeredimage augustina:

    always:
        "augustina_base"

    group outfit:
        attribute dress
        attribute jeans

    group eyes:
        attribute open default
        attribute wink

    group eyebrows:
        attribute normal default
        attribute oneup

    group mouth:
        pos (100, 100)
        attribute smile default
        attribute happy

    if evil:
        "augustina_glasses_evil"
    else:
        "augustina_glasses"

Этот пример эквивалентен первому, поскольку мы дали те же имена для отображаемых объектов, что и в первом примере. Например, атрибут dress в группе outfit использует "augustina_outfit_dress" для отображаемого объекта, который ссылается на изображение с таким именем.

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

Как и в случае с attribute, свойства можно поместить в первую строку группы, а блок опустить. Отображаемые объекты и свойства оператора always могут быть помещены в первую строку таким же образом.

Вот пример окончательной формы:

layeredimage augustina:

    always "augustina_base"

    group outfit auto

    group eyes auto:
        attribute open default

    group eyebrows auto:
        attribute normal default

    group mouth auto:
        pos (100, 100)
        attribute smile default

    if evil:
        "augustina_glasses_evil"
    else:
        "augustina_glasses"

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

Невозможно исключить отображаемые объекты из операторов always или if, поэтому это настолько коротко, насколько возможно, но с несколькими изображениями с собственными именами это можно использовать, чтобы определить тысячи или даже миллионы комбинаций слоёв.

Ссылка на оператор (Statement Reference)[править | править код]

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

◇ Оператор layeredimage[править | править код]

Оператор layeredimage – оператор на скриптовом языке Ren'Py, который вводит многослойное изображение. Он начинается с имени изображения и принимает блок, который может содержать атрибуты, группы и операторы if.


Layeredimage принимает следующие свойства:

image_format
Когда заданное изображение является строкой и это указывается, имя изображения интерполируется в image_format для создания файла изображения. Например, "sprites/eileen/{image}.png" будет искать изображение в подкаталоге спрайтов (это не используется автоматическими группами, которые ищут изображения, а не файлы изображений).
format_function
Функция, используемая вместо layeredimage.format_function для форматирования информации об изображении в отображаемом объекте.
Свойства преобразования
Если присутствуют, используются для создания Transform(), который применяется к отображаемому объекту.
at
Преобразование или список преобразований, которые применяются к многослойному изображению.


◇ Оператор attribute[править | править код]

Оператор attribute добавляет слой, который отображается, когда заданный атрибут используется для отображения изображения. Один и тот же атрибут может использоваться с несколькими слоями, причём все слои соответствуют отображаемому атрибуту (свойства if_all, if_any и if_not могут изменить это).

Атрибут принимает имя атрибута. Он также может принять два ключевых слова. Ключевое слово default указывает, что атрибут должен присутствовать по умолчанию, если ни один атрибут в его группе не конфликтует. Ключевое слово null не позволяет Ren'Py автоматически выполнять поиск отображаемого объекта, соответствующего этому атрибуту, что полезно для атрибута, предназначенного исключительно для использования с if_all, if_any или if_not.

Если отображаемый элемент отсутствует, он будет вычислен из имени слоя, группы, варианта группы и атрибута путём замены всех пробелов символами подчеркивания и использования символы подчеркивания для объединения всего. Поэтому, если у нас есть изображение с именем «augustina», группа «eyes» и атрибут «closed», будет использовано изображение «augustina_eyes_closed». Для этого используется функция форматирования многослойного изображения, по умолчанию используется layeredimage.format_function().

Если атрибут находится вне группы, он помещается в группу с тем же именем, но эта группа не используется для вычисления отображаемого имени. Таким образом, он будет искать «image_attribute», а не «image_attribute_attribute».


Оператор attribute принимает следующие свойства:

if_all
Строка или список строк с именами атрибутов. Если присутствует, этот слой отображается только при наличии всех названных атрибутов.
if_any
Строка или список строк с именами атрибутов. Если присутствует, этот слой отображается только при наличии какого-либо из названных атрибутов.
if_not
Строка или список строк с именами атрибутов. Если присутствует, этот слой отображается только в том случае, если нет ни одного из названных атрибутов.
Свойства преобразования
Если присутствуют, используются для создания преобразования, которое применяется к слою.
at
Преобразование или список преобразований, которые применяются к слою.


◇ Оператор group[править | править код]

Оператор group объединяет альтернативные слои. Когда атрибут находится внутри группы, включение любого из других атрибутов в эту группу является ошибкой. Но это нормально включить один и тот же атрибут дважды. Ключевое слово multiple снимает это ограничение.

Оператор group принимает имя. Имя используется не очень часто, но используется для генерации имён атрибутов по умолчанию внутри группы.

За именем может следовать ключевое слово auto. Если оно присутствует, после объявления каких-либо атрибутов в группе, Ren'Py отсканирует свой список изображений для поиска тех, которые соответствуют шаблону группы (см. ниже). Любые найденные изображения, не соответствующие объявленным атрибутам, добавляются в группу, как если бы они были объявлены с помощью оператора attribute.

Это может сопровождаться ключевым словом multiple. Если оно присутствует, можно выбрать более одного члена группы одновременно. Это полезно, чтобы группа автоматически определяла несколько атрибутов, которые не являются исключительными. Это противоречит тому, что ключевое слово по умолчанию присваивается одному из атрибутов.

Затем свойства могут быть объявлены в первой строке группы, и она может принять блок, содержащий свойства и атрибуты.


Существует два свойства, специфичных для групп:

variant
Если задано, то это должна быть строка. Если присутствует, добавляет вариантный элемент, который становится частью автоматически сгенерированных имён изображений и шаблона, используемого для поиска автоматически определенных атрибутов.
prefix
Если задано, это префикс, который объединяется с именами атрибутов, заданными вручную или автоматически. Поэтому, если префикс «leftarm» и имя атрибута «hip» встречаются, вместо них определяется атрибут «leftarm_hip».

Оператор group также принимает те же свойства, что и оператор attribute. Свойства, предоставленные группе, передаются атрибутам внутри группы, если они не переопределены тем же свойством самого атрибута.


Шаблон.
Используемый шаблон изображения состоит из:
  • имени изображения с пробелами, замененными символами подчеркивания.
  • имени группы.
  • имени варианта.
  • имени атрибута.

всё в сочетании с подчеркиванием. Например, если у нас есть многослойное изображение с именем «augustina work» и группа «eyes», это будет соответствовать изображениям, которые соответствуют шаблону augustina_work_eyes_attribute. При варианте цвета глаз blue, оно будет соответствовать шаблону augustina_work_eyes_blue_attribute.


◇ Оператор always[править | править код]

Оператор always объявляет слой, который всегда отображается. Он должен быть отображаемым объектом и может также принять свойства. Оба могут быть размещены на одной строке или внутри блока.


Оператор always принимает следующие свойства:

if_all
Строка или список строк с именами атрибутов. Если присутствует, этот слой отображается только при наличии всех названных атрибутов.
if_any
Строка или список строк с именами атрибутов. Если присутствует, этот слой отображается только при наличии какого-либо из названных атрибутов.
if_not
Строка или список строк с именами атрибутов. Если присутствует, этот слой отображается только в том случае, если нет ни одного из названных атрибутов.
Свойства преобразования
Если присутствуют, используются для создания преобразования, которое применяется к слою.
at
Преобразование или список преобразований, которые применяются к слою.


◇ Оператор if[править | править код]

Оператор if (или, точнее, оператор if-elif-else) позволяет указать одно или несколько условий, которые вычисляются во время выполнения кода. Каждое условие связано со слоем, причем первым истинным условием является то, которое отображается. Если условие не выполняется, слой else отображается, если он присутствует.

Более полный пример оператора if может выглядеть так:

if glasses == "evil":
    "augustina_glasses_evil"
elif glasses == "normal":
    "augustina_glasses"
else:
    "augustina_nose_mark"

Каждый слой должен иметь отображаемую информацию. Также могут быть заданы эти свойства:

if_all
Строка или список строк с именами атрибутов. Если присутствует, это условие учитывается, только если присутствуют все названные атрибуты.
if_any
Строка или список строк с именами атрибутов. Если присутствует, это условие учитывается, только если присутствует какой-либо из названных атрибутов.
if_not
Строка или список строк с именами атрибутов. Если присутствует, это условие учитывается, только если ни один из названных атрибутов не присутствует.
Свойства преобразования
Если присутствуют, используются для создания преобразования, которое применяется к слою.
at
Преобразование или список преобразований, которые применяются к слою.


Оператор if преобразуется в ConditionSwitch() при выполнении оператора layeredimage.


Если predict_all не соответствует истине, следует избегать изменения условия оператора if, когда многослойное изображение отображается или должно быть показано, так как это приведёт к непредсказуемой загрузке изображения. Он предназначен для использования в настройках персонажа, которые редко меняются.

Позы (Poses)[править | править код]

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

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

layeredimage augustina sitting:
    ...

layeredimage augustina standing:
    ...

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

layeredimage side eileen:
    ...

layeredimage side lucy:
    ...

Советы (Advice)[править | править код]

Используйте подчеркивания в именах изображений.
По умолчанию многослойные изображения Ren'Py используют подчеркивания для разделения разделов имён изображений. Может быть заманчиво использовать изображения с пробелами между разделами, но это может привести к проблемам в дальнейшем.
В Ren'Py есть правило: если вы показываете изображение с идентичным именем, что у ранее отображенного изображения, то оно появится вместо него. Это правило может обойти многослойное изображение, которое вы определили, и показать слой напрямую, что может привести к странным проблемам, как пара глаз, плавающих в пространстве.
Это больше не проблема, если у каждого слоя будет тег, отличный от основного изображения.


Обрезка слоёв совсем не обязательна.
Ren'Py оптимизирует изображения, обрезая их до ограничительной рамки непрозрачных пикселей перед загрузкой в оперативную память. В результате, при условии, что изображения прогнозируются должным образом, это, как правило, не улучшит производительность или размер изображения, чтобы обрезать изображения самостоятельно.

Язык программирования Python (Python)[править | править код]

Конечно, операторы layeredimage имеют эквиваленты в языке Python. Оператор group этого не делает – группа передаётся атрибуту, а функция auto может быть реализована с помощью renpy.list_images().


Attribute(group, attribute, image=None, default=False, **kwargs)
Используется для представления слоя LayeredImage, который управляется атрибутом. Один атрибут может управлять несколькими слоями, и в этом случае будут отображаться все слои, соответствующие этому атрибуту.
group
Строка, дающая группе атрибут, частью которого является. Это может быть None, и в этом случае создаётся группа с тем же именем, что и у атрибута.
attribute
Строка с именем атрибута.
image
Если принимает значение не None, это должен быть отображаемый объект, который отображается при отображении этого атрибута.
default
Если установлено значение True, а другой атрибут для группы не выбран, этот атрибут имеет значение.


Также известны следующие именованные аргументы:
at
Преобразование или список преобразований, которые применяются к изображению.
if_all
Атрибут или список атрибутов. Отображаемый объект отображается только если все они показываются.
if_any
Атрибут или список атрибутов. Если не пустой, отображаемый объект отображается только в том случае, если какой-либо из них показывается.
if_not
Атрибут или список атрибутов. Отображаемый объект отображается только в том случае, если ни один из них не показывается.


Другие именованные аргументы интерпретируются как свойства преобразования. Если они присутствуют, создается преобразование, которое переносит изображение. Например, pos=(100, 200) можно использовать для смещения изображения на 100 пикселей по горизонтали и 200 по вертикали.
Если параметр image опущен или отсутствует, а для LayeredImage задан параметр image_format, то image_format используется для создания имени файла изображения.


Condition(condition, image, **kwargs)
Используется для представления слоя LayeredImage, который управляется условием. Когда условие истинно, слой отображается. Иначе ничего не отображается.
condition
Это должна быть строка, задающая условие языка Python, которое определяет, отображается ли слой.
image
Если принимает значение не None, это должен быть отображаемый объект, который показывается, когда условие истинно.
if_all
Атрибут или список атрибутов. Условие оценивается, только если все они показаны.
if_any
Атрибут или список атрибутов. Если не пустой, условие оценивается, только если отображается какое-либо из них.
if_not
Атрибут или список атрибутов. Условие оценивается, только если ни одно из них не отображается.
at
Преобразование или список преобразований, которые применяются к изображению.


Другие именованные аргументы интерпретируются как свойства преобразования. Если они присутствуют, создается преобразование, которое переносит изображение. Например, pos=(100, 200) можно использовать для смещения изображения на 100 пикселей по горизонтали и 200 по вертикали.

LayeredImage(attributes, at=[], name=None, image_format=None, format_function=None, attribute_function=None, **kwargs)
Это подобный изображению объект, который, когда показан с надлежащим набором атрибутов, показывает отображаемый объект, созданный путём объединения вместе отображаемых элементов, связанных с этим атрибутом.
attributes
Это должен быть список объектов Attribute. Каждый объект Атрибут показывает отображаемый объект, который может отображаться или не отображаться как часть изображения. Элементы в этом списке расположены в обратном порядке, причём первый элемент находится дальше от зрителя, а последний - ближе всего.
at
Преобразование или список преобразований, которые применяются к отображаемому объекту после его параметризации.
name
Имя атрибута изображения. Это используется как часть имён компонентов изображения.
image_format
Когда заданное изображение является строкой и это указывается, имя изображения интерполируется в image_format для создания файла изображения. Например, "sprites/eileen/{image}.png" будет искать изображение в подкаталоге спрайтов (Это не используется автоматическими группами, которые ищут изображения, а не файлы изображений.)
format_function
Функция, которая используется вместо layeredimage.format_function для форматирования информации об изображении в отображаемую.
attribute_function
Если принимает значение не None, функция вызывается с набором атрибутов, предоставленных изображению, и возвращает набор атрибутов, используемых для выбора слоёв. Вызывается при определении отображаемых слоёв после выбора самого атрибута. Может использоваться для выражения сложных зависимостей между атрибутами или случайного выбора атрибутов.


Дополнительные ключевые слова аргументов передаются в Fixed, который создается для хранения слоя. Если явно не переопределены, xfit и yfit принимают значение True в Fixed, что означает, что он будет уменьшен до наименьшего размера, который соответствует всем изображениям слоев, которые он показывает.


LayeredImage не отображается, и его нельзя использовать во всех местах, где можно использовать отображение. Это связано с тем, что для этого необходимо указать имя изображения (обычно включая атрибуты изображения). Таким образом, он должен отображаться либо с помощью оператора scene, либо оператор show, или с помощью строки имени изображения, используемую в качестве отображаемого объекта.


layeredimage.format_function() – функция, которая используется для форматирования атрибутов и отображения внутри файлов изображений. Она представлена здесь, чтобы вы смогли увидеть, как она задокументирована, и аргументы, которые она принимает, если вы захотите представить для её замены свою собственную функцию format_function.

layeredimage.format_function(what, name, group, variant, attribute, image, image_format, **kwargs)
Вызывается для форматирования информации об атрибуте или условии в отображаемом объекте. Это может быть заменено разработчиком, но новая функция должна игнорировать неизвестные kwargs.
what
Строка, дающая описание форматируемой вещи, которая используется для создания лучших сообщений об ошибках.
name
Имя атрибута изображения.
group
Группа атрибута, принимает значение None, если не указано или является частью условия.
variant
Вариантный аргумент для группы или None, если он не указан.
attribute
Сам атрибут.
image
Либо отображаемый объект, либо строка.
image_format
Аргумент image_format объекта LayeredImage.


Если для image задано значение None, то name, group (если не None), variant (если не None) и attribute объединяются с символами подчеркивания для создания изображения, которое затем будет строкой.
Если image – строка, а image_format – не None, image форматируется в строку для получения окончательного отображаемого изображения.
Поэтому, если name – "eileen", group – "expression" и attribute – "happy", image будет установлено значение "eileen_expression_happy". Если image_format – "images/{image}.png", окончательное изображение, которое находит Ren'Py, находится в "images/eileen_expression_happy.png". Но обратите внимание, что он нашел бы то же самое изображение без аргумента format.

Проксирование многослойных изображений (Proxying Layered Images)[править | править код]

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

Объект LayeredImageProxy() делает это, беря одно многослойное изображение и дублируя его в другом месте. Например:

image dupe = LayeredImageProxy("augustina")

создаёт дубликат изображения, который может самостоятельно отображаться. Этот объект также принимает аргумент transform, что делает его полезным для позиционирования бокового изображения, например так:

image side augustina = LayeredImageProxy("augustina", Transform(crop=(0, 0, 362, 362), xoffset=-80))


LayeredImageProxy(name, transform=None)
Это подобный изображению объект, который передает атрибуты, переданные ему в другое многослойное изображение.
name
Строка, задающая имя многослойного изображения для этого прокси.
transform
Если задан, преобразование или список преобразований, которые применяются к изображению после его проксирования.

Источник[править | править код]

Статья "Layered Images" на английском языке.


На главную страницу Официальная документация движка Вернуться к началу статьи