Отображаемые объекты, определяемые автором
Самый сложный, но и самый мощный способ кастомизации поведения Ren'Py — это использование определяемого автором отображаемого объекта. Определяемый автором отображаемый объект может принимать произвольные события pygame. Он также может рендерить другие отображаемые объекты и размещать их в произвольных местах на экране. Это делает его подходящим для создания 2D-миниигр, которые невозможно выразить с помощью инструментов, предоставляемых Ren'Py. (Но также смотрите раздел sprites, который описывает более высокоуровневый способ достижения многих из тех же целей.)
Определяемые автором отображаемые объекты программируются полностью на Python, и мы настоятельно рекомендуем вам иметь достаточный уровень навыков объектно-ориентированного программирования на Python, прежде чем приступать к их созданию.
Пример
Вот пример отображаемого объекта, определённого автором. Этот отображаемый объект отрисовывает свой дочерний элемент с альфа-каналом, который определяется расстоянием указателя мыши от центра дочернего элемента.
init python:
import math
class Appearing(renpy.Displayable):
def __init__(self, child, opaque_distance, transparent_distance, **kwargs):
# Pass additional properties on to the renpy.Displayable
# constructor.
super(Appearing, self).__init__(**kwargs)
# The child.
self.child = renpy.displayable(child)
# The distance at which the child will become fully opaque, and
# where it will become fully transparent. The former must be less
# than the latter.
self.opaque_distance = opaque_distance
self.transparent_distance = transparent_distance
# The alpha channel of the child.
self.alpha = 0.0
# The width and height of us, and our child.
self.width = 0
self.height = 0
def render(self, width, height, st, at):
# Create a transform, that can adjust the alpha channel of the
# child.
t = Transform(child=self.child, alpha=self.alpha)
# Create a render from the child.
child_render = renpy.render(t, width, height, st, at)
# Get the size of the child.
self.width, self.height = child_render.get_size()
# Create the render we will return.
render = renpy.Render(self.width, self.height)
# Blit (draw) the child's render to our render.
render.blit(child_render, (0, 0))
# Return the render.
return render
def event(self, ev, x, y, st):
# Compute the distance between the center of this displayable and
# the mouse pointer. The mouse pointer is supplied in x and y,
# relative to the upper-left corner of the displayable.
distance = math.hypot(x - (self.width / 2), y - (self.height / 2))
# Base on the distance, figure out an alpha.
if distance <= self.opaque_distance:
alpha = 1.0
elif distance >= self.transparent_distance:
alpha = 0.0
else:
alpha = 1.0 - 1.0 * (distance - self.opaque_distance) / (self.transparent_distance - self.opaque_distance)
# If the alpha has changed, trigger a redraw event.
if alpha != self.alpha:
self.alpha = alpha
renpy.redraw(self, 0)
# Pass the event to our child.
return self.child.event(ev, x, y, st)
def visit(self):
return [ self.child ]
Чтобы использовать этот отображаемый объект, мы можем создать его экземпляр и добавить этот экземпляр на экран.
screen alpha_magic:
add Appearing("logo.png", 100, 200):
xalign 0.5
yalign 0.5
label start:
show screen alpha_magic
"Сможешь найти логотип?"
return
renpy.Displayable
Определяемый автором отображаемый объект создаётся путём наследования от класса renpy.Displayable. Он должен переопределять метод render и может переопределять и другие методы.
Объект displayable должен быть сериализуемым (pickleable), что означает, что он не может содержать ссылки на объекты, которые не могут быть сериализованы. В частности, объекты Render не могут храниться в определяемом автором отображаемом объекте.
Поскольку мы ожидаем, что вы будете переопределять методы класса displayable, мы будем представлять их с параметром self.
- class renpy.Displayable
Базовый класс для отображаемых объектов, определяемых автором.
- __init__(**properties)
Подкласс может переопределить конструктор, например, для добавления новых параметров. В этом случае он должен передать все неизвестные именованные аргументы в конструктор renpy.Displayable с помощью вызова:
super(MyDisplayable, self).__init__(**properties)
- render(self, width, height, st, at)
Подклассы должны переопределять этот метод, чтобы он возвращал объект
renpy.Render. Объект рендера определяет, что будет (если вообще будет) показано на экране.- width, height
Количество пространства, доступного этому отображаемому объекту, в пикселях.
- st
Число с плавающей точкой, временная база показа (shown timebase), в секундах. Отсчёт этой временной базы начинается, когда отображаемый объект впервые появляется на экране.
- at
Число с плавающей точкой, временная база анимации (animation timebase), в секундах. Отсчёт этой временной базы начинается, когда изображение с тем же тегом было показано без предварительного скрытия. (Когда отображаемый объект показывается без тега, это то же самое, что и временная база показа.)
Метод render вызывается, когда отображаемый объект показывается впервые. Он может быть вызван снова, если для этого объекта вызвана функция
renpy.redraw().
- event(self, ev, x, y, st)
Метод event вызывается для передачи события pygame в определяемый автором отображаемый объект. Если метод event возвращает значение, отличное от None, это значение возвращается как результат взаимодействия. Если метод event возвращает None, событие передаётся другим отображаемым объектам.
Чтобы проигнорировать событие, не возвращая None, вызовите исключение
renpy.IgnoreEvent.Метод event существует и у других отображаемых объектов, что позволяет передавать событие дальше.
- ev
- x, y
Координаты x и y события, относительно верхнего левого угла отображаемого объекта. Их следует использовать вместо информации о положении, содержащейся в объектах событий pygame.
- st
Число с плавающей точкой, временная база показа, в секундах.
Событие генерируется в начале каждого взаимодействия, и функция
renpy.timeout()может быть использована для вызова другого события.
- per_interact(self)
Этот метод вызывается в начале каждого взаимодействия. Он может использоваться для запуска перерисовки и, вероятно, должен использоваться для этого, если объект участвует в откате (rollback).
- visit(self)
Если у отображаемого объекта есть дочерние отображаемые объекты, этот метод следует переопределить, чтобы он возвращал список этих объектов. Это гарантирует, что методы per_interact дочерних объектов будут вызваны, а также позволяет предзагружать изображения, используемые этими объектами.
- place(self, dest, x, y, width, height, surf, main=True)
Этот метод размещает рендер (который должен принадлежать этому отображаемому объекту) внутри ограничивающей области. Возвращает кортеж (x, y), указывающий на место, куда был помещён отображаемый объект.
- dest
Если не None, surf будет скопирован (blit) на dest по вычисленным координатам.
- x, y, width, height
Ограничивающая область.
- surf
Рендер для размещения.
- main
Передаётся в Render.blit().
renpy.Render
Определяемые автором отображаемые объекты работают с объектами renpy.Render. Объекты Render возвращаются при вызове функции renpy.render() для отображаемого объекта. Определяемый автором отображаемый объект должен создавать объект Render, вызывая renpy.Render из своего метода render.
Поскольку объект рендера не предназначен для наследования, мы опустим неявный параметр self.
- class renpy.Render(width, height)
Создаёт новый объект Render.
- width, height
Ширина и высота объекта рендера, в пикселях.
- blit(source, pos, main=True)
Отрисовывает другой объект рендера внутри этого объекта рендера.
- source
Объект рендера для отрисовки.
- pos
Место для отрисовки. Это кортеж (x, y) с координатами в пикселях относительно верхнего левого угла целевого рендера.
- main
Аргумент, передаваемый только по ключу. Если true, source будет отображаться в инспекторе стилей.
- place(d, x=0, y=0, width=None, height=None, st=None, at=None, render=None, main=True)
Рендерит d, отображаемый объект, и размещает его в прямоугольнике, определённом x, y, width и height, используя стандартный алгоритм размещения Ren'Py. Возвращает кортеж (x, y), указывающий место, куда был помещён отображаемый объект. Позиция вычисляется вызовом метода Displayable.place().
- x, y, width, height
Прямоугольник для размещения. Если width или height равны None, используются ширина и высота этого рендера соответственно.
- st, at
Время, передаваемое в Render. Если None, по умолчанию используется время, переданное в метод render, вызывающий этот метод.
- render
Если не None, используется вместо рендеринга d.
- main
Как и для .blit().
- canvas()
Возвращает объект canvas. Объект canvas имеет методы, соответствующие функциям pygame.draw <http://www.pygame.org/docs/ref/draw.html>, с опущенным первым параметром (поверхностью).
В Ren'Py функции arc и ellipse не реализованы.
Объекты Canvas также имеют метод get_surface(), который возвращает pygame Surface, лежащую в основе canvas.
- get_size()
Возвращает кортеж (width, height), содержащий размер этого рендера.
- subsurface(rect)
Возвращает рендер, состоящий из прямоугольника, вырезанного из этого рендера.
- rect
Кортеж (x, y, width, height).
- zoom(xzoom, yzoom)
Устанавливает уровень масштабирования дочерних элементов этого отображаемого объекта по горизонтальной и вертикальной осям. Масштабируются только дочерние элементы — ширина, высота и координаты blit не масштабируются.
Следующие атрибуты и методы используются только когда включён рендеринг на основе моделей (model-based rendering):
- mesh
Это поле включает рендеринг на основе моделей для этого объекта Render. Если true:
Если установлено в True:
Все дочерние элементы этого отображаемого объекта рендерятся в текстуры.
С этим отображаемым объектом связывается меш (mesh) размером с первый дочерний элемент.
Создаётся модель с мешем, шейдерами, uniform-переменными и свойствами, связанными с этим объектом Render.
Затем модель будет отрисована за одну операцию.
- add_shader(shader)
Указывает, что часть шейдера shader будет использоваться при отрисовке этого Render или его дочерних элементов. Часть должна быть строкой или может быть строкой, начинающейся с "-", чтобы предотвратить отрисовку шейдера.
- add_uniform(name, value)
Устанавливает uniform-переменной name значение value при отрисовке этого Render или его дочерних элементов.
- add_property(name, value)
Устанавливает GL-свойству name значение value при отрисовке этого Render или одного из его дочерних элементов.
Вспомогательные функции и классы
- renpy.displayable(d: DisplayableLike, scope: dict[str, Any] | None = None) Displayable
Принимает d, который может быть отображаемым объектом или строкой. Если это строка, она преобразуется в отображаемый объект по обычным правилам.
- renpy.end_interaction(value)
Если value не None, немедленно завершает текущее взаимодействие, заставляя его вернуть value. Если value равен None, ничего не делает.
Может быть вызван из методов render и event созданного разработчиком отображаемого объекта.
- renpy.is_pixel_opaque(d, width, height, st, at, x, y)
Возвращает, является ли пиксель в точке (x, y) непрозрачным, когда этот отображаемый объект отрисовывается с помощью
renpy.render(d, width, height, st, at).
- renpy.load_image(im) 'renpy.display.render.Render'
Загружает манипулятор изображений im с использованием кэша изображений и возвращает объект render.
- renpy.load_rgba(data: bytes, size: tuple[int, int]) Any
Загружает данные изображения bytes в текстуру размером size и возвращает её.
- data
Должен быть байтовым объектом, содержащим данные изображения в порядке RGBA8888.
- renpy.load_surface(im) Surface
Загружает манипулятор изображений im с использованием кэша изображений и возвращает поверхность pygame (Surface).
- renpy.map_event(ev, keysym)
Возвращает true, если событие pygame ev соответствует keysym
- keysym
Одно из:
Имя привязки клавиши в
config.keymap.Код клавиши (keysym), как описано в разделе Настройка раскладки клавиатуры.
Список, содержащий один или несколько кодов клавиш.
- renpy.render(d, width, height, /, st, at)
Вызывает отрисовку отображаемого объекта и возвращает объект renpy.Render.
- d
Отображаемый объект для отрисовки.
- width, height
Ширина и высота, доступные для отрисовки отображаемого объекта.
- st, at
Временные базы показа и анимации.
Объекты Render, возвращаемые этой функцией, могут быть кэшированы, и их не следует изменять после получения.
- renpy.timeout(seconds)
Вызывает генерацию события до истечения seconds секунд. Это гарантирует вызов метода event у пользовательского отображаемого объекта.
- renpy.redraw(d, when)
Вызывает перерисовку отображаемого объекта
d(вызов его метода render) по истеченииwhenсекунд. Отображаемый объект может быть перерисован и раньше этого времени (например, при перерисовке дочернего элемента), в этом случае ожидающая перерисовка отменяется.
- exception renpy.IgnoreEvent
Это исключение, которое, если оно вызвано, заставляет Ren'Py проигнорировать событие. Чтобы вызвать его внутри метода event, напишите:
raise renpy.IgnoreEvent()