О прогресс-барах, интерполяции и программистах за спиной

Способы заполнить шкалу.

Привет. С вами Маргарита Шаповалова (aka KiraLinch), младший геймдизайнер студии игровой разработки OctoBox Interactive.

Освежила в памяти тему интерполяции и объяснила в заметке так, что сама ещё раз поняла. Немного теории и, конечно же, практическое применение на примере Sky Unlimited Inc.

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

О прогресс-барах, интерполяции и программистах за спиной

То, что выглядит как анимация, не всегда является таковой

Задача: улучшить обратную связь, сделав заполнение прогресс-баров более плавным в прототипе Sky Unlimited Inc. Это должно помочь игроку визуально лучше фиксировать изменения параметров.

Вариант 1 — не вариант: анимация

«Ну, конечно! Можно просто сделать анимацию, ведь я умею это делать. Это легко и быстро», – подумала я и сделала. А потом подумала еще раз.

Красиво

А как теперь сделать так, чтобы анимация отражала те изменения, которые испытывает параметр?

О прогресс-барах, интерполяции и программистах за спиной

Путём простых размышлений я пришла к трём вариантам:

  • никак;
  • с помощью чего-то, чего я пока не знаю;
  • другим способом.

С размышлениями и вариантами я пошла к своему гуру. И гуру молвил: «Вспомни, как двигались стулья».

Вариант 2 — вариант: Lerp

Какими способами я только не двигала стулья в Unreal. Но сила мысли и Lerp, кажется, были ответом на мой вопрос.

Lerp — это сленговое в среде программистов обозначение линейной интерполяции.

У вас есть два разных узла A и B. Представьте, что они соединены прямой линией. С шагом Alpha от точки A находится точка A1, которая показывает, насколько далеко по соединительной линии вы находитесь между узлами A и B.

Затем точка A становится точкой A1, и теперь уже новая A1 определяется с тем же шагом Alpha на меньшем отрезке. Так происходит до тех пор, пока вы асимптотически не приблизитесь к точке B, то есть A всегда стремится к B, но никогда не достигает ее фактически.

О прогресс-барах, интерполяции и программистах за спиной

Пример из прототипа

Текущее значение параметра «Эффективность» равное 0,3 подаётся на вход A. После действия игрока, по внутренней логике, число меняется и становится равным 0,4. Новое значение параметра подаётся на вход B.

Устанавливаем Alpha, равное 0,1, это 10% от отрезка между A и B.

В итоге Lerp возвращает значения, равные всем промежуточным значениям между A и B c Alpha 0,1 и асимптотически достигает B.

Функция, обновляющая прогресс с помощью Lerp
Функция, обновляющая прогресс с помощью Lerp
Блюпринт, использующий функцию
Блюпринт, использующий функцию

Вот так это выглядит в итоге с Lerp с Alpha=0,1.

Видно же, что к конечному положению прогресс-бар как бы замедляется по сравнению с началом?

Казалось, всё. Задача выполнена: всё работает хорошо, красиво, но...

Вариант 3 — вариант: FInterp To

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

В тот момент, когда я уже всё доделала с помощью Lerp, появился программист и говорит: «А чего не FInterp To?»

И показывает мне ещё один вариант решения поставленной задачи с помощью FInterp To Constant.

Функция, обновляющая прогресс с помощью FInterp To
Функция, обновляющая прогресс с помощью FInterp To

FInterp To Constant – это тоже интерполяция, но при заданной скорости и времени и до константы. То есть в независимости от того, какое расстояние от текущего положения к заданному предстоит преодолеть, это будет сделано с одинаковой скоростью и за одно и то же время, и гарантировано достигнет заданного значения. В отличие от FInterp To и Lerp, которые всегда приблизительно находятся возле конечной точки.

Пример из прототипа

Текущее значение параметра Эффективность равное 0,3 подаётся на вход Current. После действия игрока по внутренней логике число меняется и становится равным 0,4. Новое значение параметра «Эффективность» подаётся на вход Target.

Устанавливаем скорость 0,25, а Delta Time берётся из Event Tick, и равна одному тику.

Блюпринт, использующий функцию
Блюпринт, использующий функцию

Так это выглядит с FInterp To Constant

Итог

Теперь сравним, чем же визуально отличаются друг от друга два типа интерполяции: Lerp и FInterp To.

С Lerp изменение прогресс-бара замедляется к конечной точке. Что выглядит естественно.

Lerp

А с FInterp To прогресс-бар заполняется равномерно и приходит к конечной точке.

FInterp To Constant

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

Я выбрала Lerp, потому что мне нравится его естественное движение.

Привет. Я – гауссовское распределение и я нормальное. Я создаю впечатление естественности
Привет. Я – гауссовское распределение и я нормальное. Я создаю впечатление естественности

P. S. Если вы разбираетесь в матане или программировании лучше меня, у вас есть более правильное и чёткое объяснение тех тем, которых я сегодня коснулась — пожалуйста, напишите мне. Буду рада узнать что-то новое и дополнить материал.

Спасибо!

Найти меня можно

3030
20 комментариев

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

Lerp по тику плох тем, что он не компенсирует частоту кадров. У людей в с FPS 120 этот переход будет в 4 раза быстрее чем у людей с FPS 30. Хорошо если вы делаете это для однопользовательской игры, или в части которая не влияет на мультиплеер. (FInterp как раз для этого требудет Delta)

10
Ответить

лучше уж тогда Action и UI подписать на изменение параметра.
Ну и можно ж сделать шаг, ака Time.deltatime в Юнити, что по идее должно скомпенсировать разность фпс, в анриале должно быть так же.
ну и вообще функций кривых много, и под каждые визуальные задачи можно найти свой изинг анимации вот как пример.
http://easings.net/ru

4
Ответить

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

2
Ответить

Эти проблемы решается через СОП и линейную интерполяцию на основе дельты времени

Ответить

Плюшевое гауссово распределение - это супер! :)

2
Ответить

Привет. Спасибо за текст. Чутка отредактировали и перетащили в Gamedev. Если что-то поправить захотите — пишите.

1
Ответить

Спасибо большое)

Ответить