Спрайты

Для поддержки отображения большого количества изображений одновременно Ren'Py поддерживает систему спрайтов. Эта система позволяет создавать спрайты, где каждый спрайт содержит displayable-объект. Затем можно изменять положение спрайтов на экране и их вертикальный порядок.

Если игнорировать производительность, система спрайтов концептуально схожа с Fixed(), оборачивающим Transform(). Спрайты гораздо быстрее, чем трансформации, но и менее гибкие. Большое улучшение производительности спрайтов заключается в том, что каждый displayable-объект отрисовывается только один раз за кадр, даже если этот displayable-объект используется многими спрайтами. Ограничение заключается в том, что спрайты позволяют изменять только их xoffset и yoffset, в отличие от множества свойств, которые есть у Transform.

Чтобы использовать систему спрайтов, создайте объект SpriteManager, а затем вызовите его метод create для создания новых частиц. По мере необходимости обновляйте поля xoffset, yoffset и zorder каждого спрайта, чтобы перемещать его по экрану. Предоставляя аргументы update и event для SpriteManager, вы можете заставить спрайты меняться со временем и реагировать на ввод пользователя.

Классы спрайтов

class Sprite

Этот класс представляет спрайт, управляемый SpriteManager. Он содержит поля, которые контролируют размещение спрайта на экране. Спрайты не следует создавать напрямую. Вместо этого их следует создавать, вызывая SpriteManager.create().

Поля объекта Sprite:

x, y

Координаты x и y верхнего левого угла спрайта относительно SpriteManager.

zorder

Целое число, которое используется для управления порядком этого спрайта относительно других спрайтов в SpriteManager. Чем больше число, тем ближе к зрителю находится спрайт.

events

Если True, то события передаются дочернему элементу. Если False (по умолчанию), дочерние элементы игнорируют события (и, следовательно, не тратят время на их обработку).

Методы объекта Sprite:

destroy()

Уничтожает этот спрайт, предотвращая его отображение и удаляя его из SpriteManager.

set_child(d)

Изменяет отображаемый объект, связанный с этим спрайтом, на d.

class SpriteManager(update=None, event=None, predict=None, ignore_time=False, animation=True, **properties)

Этот отображаемый объект управляет коллекцией спрайтов и отображает их с максимально возможной скоростью.

update

Если не None, это функция, которая вызывается каждый раз, когда спрайт отрисовывается этим менеджером спрайтов. Она вызывается с одним аргументом — временем в секундах с момента первого отображения этого менеджера спрайтов. Ожидается, что она вернет количество секунд до следующего вызова функции, и SpriteManager будет отрисован снова.

event

Если не None, это функция, которая вызывается при возникновении события. Она принимает следующие аргументы: * Объект события pygame. * Координата x события. * Координата y события. * Время с момента первого показа менеджера спрайтов. Если она возвращает не-None значение, взаимодействие завершается, и это значение возвращается.

predict

Если не None, это функция, которая возвращает список отображаемых объектов. Эти объекты предсказываются, когда предсказывается и сам менеджер спрайтов.

ignore_time

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

animation

Если True, то этот менеджер спрайтов использует временную шкалу анимации. Это предотвращает его сброс при повторном показе.

После однократной отрисовки (до вызова функции update), SpriteManagers имеют следующие поля:

width, height

Ширина и высота этого SpriteManager в пикселях.

SpriteManagers имеют следующие методы:

create(d)

Создает новый спрайт для отображаемого объекта d и добавляет его в этот SpriteManager.

redraw(delay=0)

Вызывает перерисовку этого SpriteManager через delay секунд.

SnowBlossom(d, count=10, border=50, xspeed=(20, 50), yspeed=(100, 200), start=0, fast=False, horizontal=False, distribution: Callable[[float, float], float] | str = 'linear', animation=False)

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

d

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

border

Размер рамки экрана. Спрайт считается находящимся на экране до тех пор, пока он не выйдет за рамку, что гарантирует, что спрайты не исчезают внезапно.

xspeed, yspeed

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

start

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

fast

Если true, частицы начинают движение из центра экрана, а не только с краев.

horizontal

Если true, частицы появляются с левой или правой стороны экрана, а не сверху или снизу.

distribution

Функция или имя встроенной функции распределения для определения начальной позиции частицы.

Если это строка, она должна быть одной из следующих: - linear: Значение имеет равные шансы оказаться в любой точке вдоль оси. - gaussian: Значение с большей вероятностью будет находиться ближе к центру и с меньшей — ближе к краям. - arcsine: Значение с большей вероятностью будет находиться ближе к краям и с меньшей — ближе к центру.

Если это функция, она должна принимать два float в качестве аргументов и возвращать float.

По умолчанию — linear.

animation

Если True, то этот SnowBlossom использует временную шкалу анимации. Это предотвращает его сброс при повторном показе.

Примеры спрайтов

Класс SnowBlossom — это простой в использовании способ размещения падающих объектов на экране.

image snow = SnowBlossom("snow.png", count=100)

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

init python:
    import math

    def repulsor_update(st):

        # If we don't know where the mouse is, give up.
        if repulsor_pos is None:
            return .01

        px, py = repulsor_pos

        # For each sprite...
        for i in repulsor_sprites:

            # Compute the vector between it and the mouse.
            vx = i.x - px
            vy = i.y - py

            # Get the vector length, normalize the vector.
            vl = math.hypot(vx, vy)
            if vl >= 150:
                continue

            # Compute the distance to move.
            distance = 3.0 * (150 - vl) / 150

            # Move
            i.x += distance * vx / vl
            i.y += distance * vy / vl

            # Ensure we stay on the screen.
            if i.x < 2:
                i.x = 2

            if i.x > repulsor.width - 2:
                i.x = repulsor.width - 2

            if i.y < 2:
                i.y = 2

            if i.y > repulsor.height - 2:
                i.y = repulsor.height - 2

        return .01

    # On an event, record the mouse position.
    def repulsor_event(ev, x, y, st):
        store.repulsor_pos = (x, y)


label repulsor_demo:

    python:
        # Create a sprite manager.
        repulsor = SpriteManager(update=repulsor_update, event=repulsor_event)
        repulsor_sprites = [ ]
        repulsor_pos = None

        # Ensure we only have one smile displayable.
        smile = Image("smile.png")

        # Add 400 sprites.
        for i in range(400):
            repulsor_sprites.append(repulsor.create(smile))

        # Position the 400 sprites.
        for i in repulsor_sprites:
            i.x = renpy.random.randint(2, 798)
            i.y = renpy.random.randint(2, 598)

        del smile
        del i

    # Add the repulsor to the screen.
    show expression repulsor as repulsor

    "..."

    hide repulsor

    # Clean up.
    python:
        del repulsor
        del repulsor_sprites
        del repulsor_pos