Как сделать так, чтобы движущийся объект плавно останавливался в конце пути?

8

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

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

  1. Я кодирую его для перемещения кратных целых значений тайлов мировых данных. Таким образом, если платформа не является стационарной, то она будет перемещаться как минимум на одну ширину плитки или высоту плитки.
  2. В пределах одной длины плитки я бы хотел, чтобы он ускорялся от остановки до заданной максимальной скорости.
  3. Достигнув расстояния в одну плитку, я бы хотел, чтобы он замедлился до остановки при заданной координате плитки, а затем повторил процесс в обратном порядке.

введите описание изображения здесь

Первые две части не так уж сложны, по сути, у меня проблемы с третьей частью. Мне бы хотелось, чтобы платформа остановилась точно на координате плитки, но, поскольку я работаю с ускорением, казалось бы, легко начать применять ускорение в противоположном направлении к значению, хранящему текущую скорость платформы, как только она достигнет длины одной плитки. расстояния (если предположить, что плитка перемещается более чем на одну длину плитки, но для простоты, давайте просто предположим, что это так) - но тогда возникает вопрос: каково будет правильное значение для увеличения ускорения для получения этого эффекта? Как бы я найти это значение?

TheBroodian
источник
1
У меня нет времени для полного ответа на данный момент, но посмотрите на это: red3d.com/cwr/steer/gdc99 , в частности, раздел «Прибытие». Подражайте этому поведению, чтобы замедлить остановку и поверните вспять, чтобы ускорить остановку.
MichaelHouse
Отмеченный. Это огромное количество ценной информации, которую вы только что просветили, сэр.
TheBroodian
Этот вид «требуемый_вместность = (clipped_speed / distance) * target_offset» имеет смысл, но не совсем. Как только я найду требуемый_скорость, вычесть это из текущей скорости объекта?
TheBroodian
Я использую его для обновления значения ускорения: acceleration = desired_velocity - currentVelocityзатем примените это ускорение, как обычно. Я создам ответ чуть позже, показывая, что я делаю.
MichaelHouse

Ответы:

5

Используя эти рулевые поведения в качестве руководства. Глядя на поступившее поведение:

введите описание изображения здесь

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

Мы можем создать функцию «приехать» примерно так:

arriveAtPoint(Vector2f position, Vector2f target) {
    float slowing_distance = 1;
    Vector2f target_offset = target - position;
    float distance = target_offset.length();
    float ramped_speed = currentVelocity * (distance / slowing_distance);
    float clipped_speed = Math.min(ramped_speed, currentVelocity);
    targetLinearVelocity = target_offset.scale(clipped_speed / distance);
    acceleration = targetLinearVelocity -linearVelocity;
}

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

MichaelHouse
источник
И просто для пояснения, линейная скорость - это скорость, с которой наш объект путешествовал бы после предыдущего обновления?
TheBroodian
Ваша фраза довольно странная. Но, linearVelocity == currentVelocity.
MichaelHouse
3
Я не согласен с этим подходом на том основании, что он слишком сложный. Это можно сделать с помощью простой анимации движения, используя уравнения движения ( формулы SUVAT ). Небольшая алгебра, и вы можете рассчитать входные данные, необходимые для точного достижения желаемой цели.
Эндрю Рассел
1
Было бы полезно уточнить это с ответом?
TheBroodian
@AndrewRussell Я тоже хотел бы увидеть этот ответ.
MichaelHouse
5

Взгляните на эту страницу: http://sol.gfxile.net/interpolation/index.html

Кажется, что вы хотите эффект, как сглаживание:

плавная графика

Если у вас есть самая левая точка, самая правая точка, которую должна достичь платформа, и время, которое она должна использовать для создания полной последовательности, что-то вроде этого может быть приемлемым:

кадр foreach:

float smoothstep(float t, int level = 1)
{
    float ret = t;
    for(int i = 0; i < level; ++i)
    {
        ret = pow(ret, 2) * (3 - 2 * ret);
    }
    return ret;
}

currentTime += deltaTime;
if(currentTime > fullTime) currentTime -= fullTime;
float halfTime = fullTime / 2.0;
float t = abs(currentTime - halfTime) / halfTime;
t = smoothstep(t, 1);
platformPosition = rightPoint * t + leftPoint * (1 - t);

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

Густаво Масиэль
источник
3

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

Вот ответ с некоторым кодом, основанным на проекте Xna Tweener, и видео, показывающее, как он работает ...

https://gamedev.stackexchange.com/a/26872/8390

[РЕДАКТИРОВАТЬ]

У вас должна быть последовательность клавиш, которая определяет движение платформы, например:

public class MovementKey
{
    public float Time = 0;
    public float Duration;
    public Vector2 Traslation;            // Traslation is relative to previous key
    public TweeningFunction Function;

    internal float GetRatio( float Elapsed )   
    {
        // Always return a value in [0..1] range
        //    0 .. Start position relative to accumulated traslations of previous keys
        //    1 .. Target relative position reached.. then should go to next key if avalaible
        return Function( Elapsed, 0, 1, Duration ); 
    }
}

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

public class Movement {

    List<MovementKey> Keys;

    public void Update( float Seconds)
    {

        float ratio;
        if (Playing) Elapsed += Seconds;

        while ( index!= Keys.Count - 1 && Elapsed > Keys[iKey + 1].Time )
        {
            Traslation += Keys[iKey].Traslation;  // Relative
            index++;
        }

       if ( index == Keys.Count - 1 && Elapsed > Keys[iKey].Time + Keys[iKey].Duration )
       {
          ratio = 1;
          if ( DoLoop )
          {
              Elapsed -= (Keys[index].Time + Keys[iKey].Duration);
              Index = 0;
              Traslation = Vector2.zero;
          }
       }
       else {                    
           ratio = Keys[index].GetRatio( Elapsed - Keys[index].Time );
       }

       Position = DefaultPosition + Traslation + ratio * Keys[index].Traslation;        
   }

«DefaultPosition» - это начальная позиция, «Traslation» накапливает движение нескольких ключей, и каждое изменение ключа относится к предыдущему ключу, поэтому при умножении его на коэффициент отношения [0..1] возвращается интерполированное относительное перемещение, пройденное чтобы получить этот ключ от предыдущего ключа ...

Здесь у вас есть другое видео, которое показывает движение платформы, определенное, как описано здесь ...

http://www.youtube.com/watch?v=ZPHjpB-ErnM&feature=player_detailpage#t=104s

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

Blau
источник
Спасибо, это полезно, хотя оно используется в том, что похоже на контекст анимации, я пытаюсь перевести это в своей голове на то, что было бы более контекстуальным для моей ситуации под рукой.
TheBroodian
Я потерялся. Я не могу понять, как связать это с моей нынешней ситуацией вообще. оо ;;
TheBroodian
У вас есть анимация ... вы пытаетесь анимировать с позиции позиции ...
Блау
Извините, причина, по которой у меня возникают трудности, заключается в том, что я пытаюсь загрузить эту идею и перевести ее в систему, которая работает в системе скорость = скорость * время, тогда как эта система просто подталкивает местоположение объекта процедурно (ничего плохого в этом нет, просто трудно найти правильный способ связать их).
TheBroodian