Как стать автором
Обновить

Движение объекта к точке в Unity3D

Время на прочтение 3 мин
Количество просмотров 30K

Введение


Предположим, что у нас есть объект, который должен двигаться к точке. Задачка-то простенькая, использовать интерполяцию, например. Но что, если наш объект может поворачиваться на случайный угол? Как тогда задать точку для интерполирования? Ведь наверняка наша условная вагонетка должна двигаться только по направлению своих колес. Соответственно либо тыльной, либо фронтальной стороной. С этой задачей нам поможет справиться векторная алгебра.

Теория


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

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

  • координаты начала вектора;
  • длина вектора;
  • угол наклона к осям координат.

Предположим, что все это мы знаем. Тогда задача сводится к простейшим формулам теоремы синусов.

$x/sin(α) = a/sin (90)$
$ x = a* sin(α)$
$y/sin (90 - α) = a/sin(90)$
$ y = a * sin (90 - α)$

где a — длина вектора, α — угол наклона к оси координат

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

Практика


Итак, нам известно:

  • где фронтальная и тыльная сторона объекта;
  • текущее положение объекта;
  • угол, на который повернулся объект.
  • расстояние, которое должен преодолеть объект.

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



И в unity это тоже работает. Для начала, нам нужно определить четверти в сцене. Создаем куб в начале координат, перемещаем его и смотрим, какие координаты отрицательные, а какие положительные. В примере видно, что обе координаты отрицательные, значит куб находится в третьей четверти.



Теперь можно приступать непосредственно к скрипту. На вход мы принимаем Transform исходного объекта после поворота и Transform пустышки, к которой в последствии будем двигаться. Пустышка изначально имеет координаты объекта. Далее определяем четверть, в которой находится фронт объекта. Так как тригонометрическая окружность ограничена от 0 до 360 градусов, то труда это не составляет. Определив четверть, вычисляем углы наклона для каждой координаты. Потом делаем проверку, чтобы наши углы имели правильный знак. После этого отправляем углы наклона в конечную формулу вычисления координат. И наконец, задаем новые координаты пустышке, к которой будем интерполировать.

void ChekingQuarterUp(Transform vectorAngle, ref Transform empty)
	{
		float zangle = 0;
		float xangle= 0;
		float zcoord = 0.0f;
		float xcoord = 0.0f;

		int normangle = Mathf.RoundToInt (vectorAngle.eulerAngles.y);

		if (normangle >= 0 && normangle <= 90) // 1-ая четверть
		{
			zangle = 90 - normangle;
			xangle = 0 - normangle;

			xangle = (xangle < 0) ? xangle * -1 : xangle;
			zangle = (zangle < 0) ? zangle * -1 : zangle;

		}

		if (normangle > 270 && normangle <= 360) // 2-ая четверть
		{
			xangle = 360 - normangle;
			zangle = 270 - normangle;


			xangle = (xangle > 0) ? xangle * -1 : xangle;
			zangle = (zangle < 0) ? zangle * -1 : zangle;


		}

		if (normangle > 180 && normangle <= 270) // 3-ая четверть
		{
			xangle = 180 - normangle;
			zangle = 270 - normangle;

			xangle = (xangle > 0) ? xangle * -1 : xangle;
			zangle = (zangle > 0) ? zangle * -1 : zangle;
		}

		if (normangle > 90 && normangle <= 180) // 4-ая четверть
		{
			zangle = 90 - normangle;
			xangle = 180 - normangle;

			zangle = (zangle > 0) ? zangle * -1 : zangle;
			xangle = (xangle < 0) ? xangle * -1 : xangle;

		}
			
		zcoord = path * Mathf.Sin (zangle *Mathf.PI/180);
		xcoord = path * Mathf.Sin (xangle * Mathf.PI/180);

		float newpathx = empty.position.x + xcoord;
		float newpathz = empty.position.z + zcoord;


		empty.position = new Vector3 (newpathx, empty.transform.position.y, newpathz);

	}

Заключение


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

Для движения «задом» нужно всего лишь диаметрально изменить знаки координат согласно четвертям. Если вы решили определять точку в трехмерном пространстве, то учитывайте, что «четвертей» там будет больше.

Пример реализации метода можно взять здесь.
Теги:
Хабы:
+4
Комментарии 6
Комментарии Комментарии 6

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн