Интерполяция по нескольким точкам

Обычная линейная интерполяция, но вместо двух точек на входе массив из Vector3. Таким образом можно плавно двигать объект по множеству точек.

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

/// <summary>
/// Move the object to the specified positions
/// </summary>
/// <param name="positions">Array of control points</param>
/// <param name="time">Time for each segment</param>
public IEnumerator Move(Vector3[] positions, float time) {
	for (var i = 0; i < positions.Length; i++) {
		var startPosition = transform.position;
		var t = 0f;
		while (t < 1) {
			t += Time.deltaTime / time;
			transform.position = Vector3.Lerp(startPosition, positions[i], t);
			yield return null;
		}
		transform.position = positions[i];
	}
}
...
Vector3[] positionsArray = { new Vector3 (10f, 10f, 0f), new Vector3 (20f, 20f, 0f), ... };
StartCoroutine (Move(positionsArray, 1f));

Выглядит это примерно так:

Простая интерполяция по точкам

Но, можно сгладить перемещение! Можно использовать Кривые Безье, но там надо дополнительно задавать промежуточные точки. Другой вариант интереснее — сплайн Кэтмулла-Рома (Catmull–Rom spline), он проходит по всем точкам и дополнительно ничего не надо указывать.

/// <summary>
/// Catmull-Rom spline interpolation
/// </summary>
public static Vector3 CatmullRom(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
	return 0.5f * (
		(2f * p1) +
		(-p0 + p2) * t +
		t * t * (2f * p0 - 5f * p1 + 4f * p2 - p3) +
		t * t * t * (-p0 + 3f * p1 - 3f * p2 + p3)
	);
}

/// <summary>
/// Move along a Catmull-Rom spline defined by the given positions
/// </summary>
/// <param name="positions">Array of control points</param>
/// <param name="time">Time to complete the spline</param>
public IEnumerator MoveSpline(Vector3[] positions, float time) {
	if (positions.Length < 2) {
		Debug.LogError("Requires at least 2 points for spline!");
		yield break;
	}
	for (var i = 0; i < positions.Length - 1; i++) {
		var p0 = (i == 0) ? positions[i] : positions[i - 1];
		var p1 = positions[i];
		var p2 = positions[i + 1];
		var p3 = (i + 2 < positions.Length) ? positions[i + 2] : positions[i + 1];
		var t = 0f;
		while (t < 1f) {
			t += Time.deltaTime / time;
			transform.localPosition = CatmullRom(p0, p1, p2, p3, t);
			yield return null;
		}
		transform.localPosition = p2;
	}
}

Вот как это выглядит, даже с корявым примером выше:

Интерполяция по точкам Catmull-Rom сплайн

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

Это если не хочется из-за одной функции тянуть большую библиотеку в проект 😁 А так, DOTween или любой другой твинер решает наверно все задачи связанные с перемещением объекта.

Нет комментариев

    Ваш комментарий