Как обновить Unity GameObject, чтобы двигаться по кривой сплайна?
Добрый день,
Я пытаюсь реализовать GameObject в Unity, который перемещается по кубическому сплайну CatMull-Rom, учитывая 8 случайных значений с ограничениями. Я реализовал функцию, ComputePointOnCatmullRomCurve, которая возвращает точку на кубической кривой Катмулла-Рома (учитывая скалярное 'u' от 0 до 1 и сегмент_номер, который указывает, какие 4 пункта использовать для интерполяции).
У меня проблемы с реализацией функции обновления, чтобы GameObject мог двигаться плавно. В настоящее время я вызываю ComputePointOnCatmullRomCurve каждое обновление и каждый раз увеличиваю номер_сегмента. Положение GameObjects затем устанавливается на результат функции.
Однако это приводит к GameObject, который движется очень быстро. Я считаю, что моя функция "Обновление" неверна, но я не уверен в том, как перемещать GameObject относительно точек, которые выводятся функцией интерполяции.
Если кто-то сможет объяснить мне, что я делаю неправильно, или предоставить пример или ссылку на пример, это будет очень полезно!
Функция для вычисления точки на кривой:
Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
// TODO - compute and return a point as a Vector3
// Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
// Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
// etc...
Vector3 point = new Vector3();
float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
float c3 = ((u - 1f) * u * u) * 0.5f;
Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];
point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);
return point;
}
Функция обновления:
void Update () {
// TODO - use time to determine values for u and segment_number in this function call
// 0.5 Can be used as u
time += DT;
segCounter++;
Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
transform.position = temp;
}
Переменные:
const int NumberOfPoints = 8;
Vector3[] controlPoints;
const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;
const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;
float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;
Спасибо!
Matt
1 ответ
Вы делаете 2 ошибки в функции обновления.
Первая ошибка:
Вы увеличиваете индекс текущего сегмента в каждом кадре (segmentNumber
). Я предполагаю, что это должно быть сделано только тогда, когда объект завершит свое движение вдоль предыдущего сегмента сплайна.
Подсказка:
Для сплайновых кривых, определенных несколькими патчами, я обычно выражаю время (u
) В диапазоне [0,n]
где n
номер сегмента, определяющего кривую. Таким образом, вы можете получить индекс текущего патча (segmentNumber
) просто извлекая неотъемлемую часть из параметра. Что-то вроде:
int segmentNumber = Mathf.FloorToInt(u);
float segmentU = u - segmentNumber;
Вторая ошибка
Я не знаю, какова ваша переменная DT, но если вы не масштабируете ее по времени дельты кадра в другом месте, вам придется это сделать. В принципе, вы можете увеличить время следующим образом:
time += Time.deltaTime * speedAlongCurve;
Я надеюсь, что это помогает.