Pull to refresh

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

Game developmentUnity3D
Sandbox

Введение


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

Теория


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

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

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

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

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

где 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);

	}

Заключение


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

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

Пример реализации метода можно взять здесь.
Tags:unity3dunityразработка игрвекторыдвижениеинтерполяция
Hubs: Game development Unity3D
Total votes 12: ↑8 and ↓4 +4
Views22.2K

Popular right now

Unity3D Developer
from 110,000 ₽Game InsightRemote job
Unity разработчик
to 200,000 ₽HR BROСанкт-Петербург
Разработчик Unity
from 150,000 ₽ArcaniteRemote job
Unity3D Developer Middle+/Senior
from 2,400 to 4,000 $Red Rift, Inc.Remote job
Программист C#/C++ Unity3d / Computer vision / Senior dev
from 150,000 to 350,000 ₽New RealityМосква