Ответ на самом деле довольно прост, если вы делаете математику. У вас есть фиксированное расстояние Y и переменное расстояние X (см. Рисунок 1). Вам нужно выяснить угол между Z и X и еще больше повернуть турель.
Шаг 1 - Получите расстояние между линией револьверной башни (V) и линией ружья (W), которая равна Y (она постоянна, но не мешает вычислять). Получите расстояние от башни до цели (то есть X).
Шаг 2 - Разделите Y на X, а затем получите гиперболический синус значения
double turnRadians = Mathf.Asin(Y/X);
double angle = Mathf.Rad2Deg * turnRadians;
//where B is the red dot, A is a point on the X line and C is a point on the Z line.
Шаг 3 - Поверните турель намного больше (вокруг оси, идущей сверху вниз, скорее всего вверх, но эту часть может знать только вы).
gameObject.transform.Rotate(Vector3.up, turnAngle);
Конечно, в этом случае вам нужно, чтобы он вращался против часовой стрелки, поэтому вам может понадобиться добавить минус перед поворотом там, как в -turnAngle
.
Отредактировал некоторые части. Спасибо @ens за указание на разницу в расстоянии.
ОП сказал, что у его пистолета есть угол, поэтому мы идем, сначала изображение, потом объяснение:
Мы уже знаем из предыдущего расчета, куда направить красную линию по синей линии. Итак, нацеливаясь сначала на синюю линию:
float turnAngle = angleBetweenTurretAndTarget - angleBetweenTurretAndGun;
turret.transform.Rotate(Vector3.up, turnAngle);
Единственное вычисление, которое здесь отличается, это вычисление «X Prime» (X '), поскольку угол между пистолетом и револьверной головкой (угол «a») изменил расстояние между линиями.
//(this part had a mistake of using previous code inside new variable names, YPrime and Y are shown as X' and X in the 2nd picture.
float YPrime = Cos(a)*Y; //this part is what @ens is doing in his answer
double turnRadians = Mathf.Asin(YPrime/X);
double angle = Mathf.Rad2Deg * turnRadians;
turret.transform.Rotate(Vector3.up, angle);
Эта следующая часть ТОЛЬКО необходима, если вы делаете модульные орудия с револьверной головкой (т. Е. Пользователь может менять орудия на револьверной головке, и разные пушки имеют разные углы). Если вы делаете это в редакторе, вы уже можете видеть, какой угол наклона пистолета соответствует башне.
Есть два метода для нахождения угла "a", один из них - метод transform.up:
float angleBetween = Vector3.Angle(turret.transform.up, gun.transform.up);
Выше техника будет рассчитывать в 3D, поэтому, если вы хотите 2D-результат, вам нужно избавиться от оси Z (это то, что я предполагаю, где гравитация, но если вы ничего не изменили, в Unity это ось Y вверх или вниз, т.е. гравитация находится на оси Y, поэтому вам, возможно, придется изменить положение вещей):
Vector2 turretVector = new Vector2(turret.transform.up.x, turret.transform.up.y);
Vector2 gunVector = new Vector2(gun.transform.up.x, gun.transform.up.y);
float angleBetween = Vector2.Angle(turretVector, gunVector);
Второй способ - это метод поворота (в данном случае я думаю о 2D):
double angleRadians = Mathf.Asin(turret.transform.rotation.z - gun.transform.rotation.z);
double angle = 2 * Mathf.Rad2Deg * angleRadians;
Опять же, все эти коды дадут вам положительные значения, поэтому вам, возможно, придется добавить или вычесть сумму в зависимости от угла (для этого тоже есть расчеты, но я не буду вдаваться в подробности). Хорошее место для начала это Vector2.Dot
метод в Unity.
Последний блок кода для дополнительного объяснения того, что мы делаем:
//turn turret towards target
turretTransform.up = targetTransform.position - turretTransform.position;
//adjust for gun angle
if (weaponTransform.localEulerAngles.z <180) //if the value is over 180 it's actually a negative for us
turretTransform.Rotate(Vector3.forward, 90 - b - a);
else
turretTransform.Rotate(Vector3.forward, 90 - b + a);
Если вы все сделали правильно, вы должны получить такую сцену ( ссылка на пакет UnityPack ):
Что я подразумеваю под всегда положительными значениями:
Метод Z может давать отрицательные значения:
Для примера сцены, получите пакет Unity по этой ссылке .
Вот код, который я использовал на сцене (на башне):
public class TurretAimCorrection : MonoBehaviour
{
public Transform targetTransform;
public Transform turretTransform;
public Transform weaponTransform;
private float f, d, x, y, h, b, a, weaponAngle, turnAngle;
private void Start()
{
TurnCorrection();
}
private void Update()
{
TurnCorrection();
}
void TurnCorrection()
{
//find distances and angles
d = Vector2.Distance(new Vector2(targetTransform.position.x, targetTransform.position.y), new Vector2(turretTransform.position.x, turretTransform.position.y));
x = Vector2.Distance(new Vector2(turretTransform.position.x, turretTransform.position.y), new Vector2(weaponTransform.position.x, weaponTransform.position.y));
weaponAngle = weaponTransform.localEulerAngles.z;
weaponAngle = weaponAngle * Mathf.Deg2Rad;
y = Mathf.Abs(Mathf.Cos(weaponAngle) * x);
b = Mathf.Rad2Deg * Mathf.Acos(y / d);
a = Mathf.Rad2Deg * Mathf.Acos(y / x);
//turn turret towards target
turretTransform.up = targetTransform.position - turretTransform.position;
//adjust for gun angle
if (weaponTransform.localEulerAngles.z < 180)
turretTransform.Rotate(Vector3.forward, 90 - b - a);
else
turretTransform.Rotate(Vector3.forward, 90 - b + a);
//Please leave this comment in the code. This code was made by
//http://gamedev.stackexchange.com/users/93538/john-hamilton a.k.a. CrazyIvanTR.
//This code is provided as is, with no guarantees. It has worked in local tests on Unity 5.5.0f3.
}
}
3D адаптированный код с X и Z в качестве 2D-плоскости:
public class TurretAimCorrection : MonoBehaviour
{
public Transform targetTransform; //drag target here
public Transform turretTransform; //drag turret base or turret top part here
public Transform weaponTransform; //drag the attached weapon here
private float d, x, y, b, a, weaponAngle, turnAngle;
private void Start()
{
TurnAdjustment();
}
private void Update()
{
TurnAdjustment();
}
void TurnAdjustment()
{
d = Vector2.Distance(new Vector2(targetTransform.position.x, targetTransform.position.z), new Vector2(turretTransform.position.x, turretTransform.position.z));
x = Vector2.Distance(new Vector2(turretTransform.position.x, turretTransform.position.z), new Vector2(weaponTransform.position.x, weaponTransform.position.z));
weaponAngle = weaponTransform.localEulerAngles.y;
weaponAngle = weaponAngle * Mathf.Deg2Rad;
y = Mathf.Abs(Mathf.Cos(weaponAngle) * x);
b = Mathf.Rad2Deg * Mathf.Acos(y / d);
a = Mathf.Rad2Deg * Mathf.Acos(y / x);
//turn turret towards target
turretTransform.forward = new Vector3(targetTransform.position.x, 0, targetTransform.position.z) - new Vector3(turretTransform.position.x, 0, turretTransform.position.z);
//adjust for gun angle
if (weaponTransform.localEulerAngles.y < 180)
turretTransform.Rotate(Vector3.up, - a +b-90);
else
turretTransform.Rotate(Vector3.up, + a+ b - 90);
//Please leave this comment in the code. This code was made by
//http://gamedev.stackexchange.com/users/93538/john-hamilton a.k.a. CrazyIvanTR.
//This code is provided as is, with no guarantees. It has worked in local tests on Unity 5.5.0f3.
}
}