Пружинистое движение (Springy movement)

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

Если вы хотите добавить немного пружинистости вашему Moves, следующий код – возможно то, что вы ищете. Код основан на затухании реакции на ступенчатом входном сигнале, которое постепенно уменьшает колебания. Я хочу предложить два различных способа сделать это – один простой и один более сложный, предоставляющий больше возможностей.

Springy movement.png

Общие сведения (General information)[править | править код]

В основном применяется формула x(t) = 1 - ℯ-ρtcos(μt), которая затем делится на коэффициент масштабирования. Формула принимает два параметра, которые можно использовать для настройки движения: ρ и μ.

Устранение сингулярности (Avoiding singularities)[править | править код]

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

ρ = cos(μ)

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

Что ρ делает (What ρ does)[править | править код]

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

Можно задать ρ отрицательное число, что означает увеличение колебаний, как если бы объект находился в резонансе. Я не знаю, почему вы хотели бы это сделать, но если вы этого хотите:

  • Если присвоить ρ достаточно большое значение: движение начнется более резко и подпрыгивание закончится быстрее.
  • Если присвоить ρ небольшое значение, но больше нуля: движение начнется более плавно и подпрыгиванию потребуется больше времени для прекращения (и, возможно, оно не завершится до окончания времени, что будет означать резкое окончание).
  • Если присвоить ρ нулевое или отрицательное значение: движение начнется плавно, но подпрыгивание станет больше или останется того же размера, а не уменьшится. Также под угрозой находится сингулярность.

Что μ делает (What μ does)[править | править код]

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

  • Если присвоить μ достаточно большое значение (положительное или отрицательное): движение начнется более внезапно и вы получите больше отскоков.
  • Если присвоить μ небольшое значение (положительное или отрицательное) или ноль: движение начнется более плавно и вы получите меньше отскоков (или вообще никаких).

Простая форма (Simple form)[править | править код]

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

import math

def springy_time_warp_real(x, rho, mu):
  return (1.0 - math.exp(-rho * x) * math.cos(mu * x)) / (1.0 - math.exp(-rho) * math.cos(mu))

springy_time_warp = renpy.curry(springy_time_warp_real)

И использовать её:

show eileen happy at Move(offscreenleft, center, 1.0, time_warp = springy_time_warp(rho = 5.0, mu = 15.0))

Оптимизация (Optimizing)[править | править код]

Если выбраны ρ и μ, которые вам нравятся, и вы не собираетесь их менять, можете немного упростить уравнение, чтобы получить увеличение скорости. Лучший способ сделать это - начать со следующего кода:

import math

rho = 5.0
mu = 15.0
scale_factor = 1.0 - math.exp(-rho) * math.cos(mu)

def springy_time_warp(x):
  return (1.0 - math.exp(-rho * x) * math.cos(mu * x)) / scale_factor

...

show eileen happy at Move(offscreenleft, center, 1.0, time_warp = springy_time_warp)

Используйте этот код во время разработки, чтобы точно настроить ρ и μ, пока не будете готовы к выпуску. Затем замените ρ и μ на выбранные вами значения, а scale_factor на 1 – ℯ–ρcos(μ).

Комплексная форма (Complex form)[править | править код]

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

class UnderdampedOscillationInterpolater(object):
   
    anchors = {
        'top' : 0.0,
        'center' : 0.5,
        'bottom' : 1.0,
        'left' : 0.0,
        'right' : 1.0,
        }
   
    def __init__(self, start, end, rho, mu):
       
        import math
       
        if len(start) != len(end):
            raise Exception("Начало и конец должны иметь одинаковое количество аргументов.")
       
        self.start = [ self.anchors.get(i, i) for i in start ]
        self.end = [ self.anchors.get(i, i) for i in end ]
        self.rho = rho
        self.mu = mu
        self.c = 1.0 - math.exp(-rho) * math.cos(mu)
   
    def __call__(self, t, sizes=(None, None, None, None)):
       
        import math
       
        t = (1.0 - math.exp(-self.rho * t) * math.cos(self.mu * t)) / self.c
       
        def interp(a, b, c):
           
            if c is not None and isinstance(a, float):
                a = int(a * c)
           
            if c is not None and isinstance(b, float):
                b = int(b * c)
           
            rv = (b - a) * t + a
           
            if isinstance(a, int) and isinstance(b, int):
                return int(rv)
            else:
                return rv
       
        return [ interp(a, b, c) for a, b, c in zip(self.start, self.end, sizes) ]

def Springy(startpos, endpos, time, rho, mu, child=None, repeat=False, bounce=False, anim_timebase=False, style='default', time_warp=None, **properties):
   
    return Motion(UnderdampedOscillationInterpolater(startpos, endpos, rho, mu), time, child, repeat=repeat, bounce=bounce, anim_timebase=anim_timebase, style=style, time_warp=time_warp, add_sizes=True, **properties

И используете вышеуказанный код с:

show eileen happy at Springy(offscreenleft, center, 1.0, 5.0, 15.0)

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

Статья "Springy movement" на английском языке


На главную страницу Книга рецептов Энциклопедии Ren'Py Книга рецептов Ren'Py Вернуться к началу статьи