Eğer matematik yaparsanız cevap aslında oldukça kolaydır. Sabit bir Y mesafeniz ve değişken bir X mesafeniz var (Bkz. Resim 1). Z ve X arasındaki açıyı bulmanız ve taretinizi daha fazla döndürmeniz gerekir.
Adım 1 - Taret çizgisi (V) ile Y olan tabanca çizgisi (W) arasındaki mesafeyi alın (bu sabittir ancak hesaplanmasına zarar vermez). Taretten hedefe kadar olan mesafeyi alın (X).
Adım 2 - Y'yi X'e bölün ve sonra değerin Hiperbolik Sinüsünü elde edin
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.
Adım 3 - Tareti çok daha fazla çevirin (yukarıdan aşağıya doğru eksen etrafında, en çok yukarı eksen, ancak o kısmı sadece siz biliyorsunuz).
gameObject.transform.Rotate(Vector3.up, turnAngle);
Elbette bu durumda, saat yönünün tersine çevirmeniz gerekir, böylece dönüşün önüne bir eksi eklemeniz gerekebilir -turnAngle
.
Bazı parçalar düzenlendi. Mesafe farkını gösterdiği için @ens sayesinde.
OP silahının bir açısı olduğunu söyledi, işte başlıyoruz, önce resim, açıklama sonra:
Kırmızı çizgiyi mavi çizgiye göre nereye hedefleyeceğinizi önceki hesaplamadan zaten biliyoruz. İlk önce mavi çizgiyi hedeflemek:
float turnAngle = angleBetweenTurretAndTarget - angleBetweenTurretAndGun;
turret.transform.Rotate(Vector3.up, turnAngle);
Burada farklılık gösteren tek hesaplama, "X Prime" (X ')' nin hesaplanmasıdır çünkü tabanca ile taret arasındaki açı ("a" açısı) çizgiler arasındaki mesafeyi değiştirmiştir.
//(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);
Bu sonraki bölüm SADECE taret tabancalarını modüler yapıyorsanız gereklidir (yani kullanıcı taret üzerindeki tabancaları değiştirebilir ve farklı tabancaların farklı açıları vardır). Eğer bunu editörde yapıyorsanız, silah açısının tarete göre ne olduğunu zaten görebilirsiniz.
"A" açısını bulmak için iki yöntem vardır, biri transform.up yöntemidir:
float angleBetween = Vector3.Angle(turret.transform.up, gun.transform.up);
Yukarıdaki teknik 3B olarak hesaplanacaktır, bu nedenle 2B sonuç istiyorsanız, Z ekseninden kurtulmanız gerekir (yerçekiminin nerede olduğunu varsayarım, ama hiçbir şeyi değiştirmediyseniz, Unity'nin yukarı ya da aşağı olduğu Y ekseni, yani, yerçekimi Y ekseni üzerinde olduğundan, bir şeyleri değiştirmek zorunda kalabilirsiniz):
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);
İkincisi, rotasyon yöntemidir (bu durumda 2B olarak düşünüyorum):
double angleRadians = Mathf.Asin(turret.transform.rotation.z - gun.transform.rotation.z);
double angle = 2 * Mathf.Rad2Deg * angleRadians;
Yine, tüm bu kodlar size pozitif değerler verecektir, bu nedenle açıya bağlı olarak miktarı eklemeniz veya çıkarmanız gerekebilir (bunun için de hesaplamalar vardır, ancak bu derinlemesine gitmeyeceğim). Bu konuda başlamak için iyi bir yerVector2.Dot
Unity'deki yöntem .
Yaptıklarımızın ek açıklaması için son kod bloğu:
//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);
Her şeyi doğru yaptıysanız, böyle bir sahne elde etmelisiniz ( birliğin paketlenmesi için link ):
Ne demek istediğimi her zaman pozitif değerler:
Z yöntemi negatif değerler verebilir:
Örnek bir sahne için, bu bağlantıdan birliğin paketini alın .
İşte sahnede kullandığım kod (tarette):
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.
}
}
2B düzlem olarak X ve Z ile 3B uyarlanmış kod:
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.
}
}