Jawabannya sebenarnya cukup mudah jika Anda melakukan perhitungan. Anda memiliki jarak tetap Y dan jarak variabel X (Lihat Gambar 1). Anda perlu mengetahui sudut antara Z dan X dan memutar menara Anda lebih dari itu.
Langkah 1 - Dapatkan jarak antara garis menara (V) dan garis pistol (W) yang merupakan Y (ini konstan tetapi tidak ada salahnya untuk menghitung). Dapatkan jarak dari turet ke target (yaitu X).
Langkah 2 - Bagi Y dengan X dan kemudian dapatkan nilai Hyperbolic Sine
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.
Langkah 3 - Putar turret lebih dari itu (di sekitar sumbu yang bergerak dari atas ke bawah, kemungkinan besar sumbu atas tetapi hanya Anda yang dapat mengetahui bagian itu).
gameObject.transform.Rotate(Vector3.up, turnAngle);
Tentu saja dalam kasus ini, Anda perlu memutar berlawanan arah jarum jam sehingga Anda mungkin perlu menambahkan minus di depan turnAngle di sana, seperti pada -turnAngle
.
Mengedit beberapa bagian. Terima kasih kepada @ens untuk menunjukkan perbedaan jarak.
OP mengatakan senjatanya memiliki sudut jadi di sini kita pergi, gambar dulu, penjelasan nanti:
Kita sudah tahu dari perhitungan sebelumnya di mana mengarahkan garis merah sesuai dengan garis biru. Jadi membidik garis biru pertama:
float turnAngle = angleBetweenTurretAndTarget - angleBetweenTurretAndGun;
turret.transform.Rotate(Vector3.up, turnAngle);
Satu-satunya perhitungan yang berbeda di sini, adalah perhitungan "X Prime" (X ') karena sudut antara pistol dan turret (sudut "a") mengubah jarak antara garis.
//(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);
Bagian selanjutnya ini HANYA diperlukan jika Anda melakukan modular senjata meriam (yaitu pengguna dapat mengubah senjata pada menara dan senjata yang berbeda memiliki sudut pandang yang berbeda). Jika Anda melakukan ini di editor, Anda sudah bisa melihat apa sudut pistol sesuai dengan menara.
Ada dua metode untuk menemukan sudut "a", satu adalah metode transform.up:
float angleBetween = Vector3.Angle(turret.transform.up, gun.transform.up);
Teknik di atas akan menghitung dalam 3D, jadi jika Anda menginginkan hasil 2D, Anda harus menyingkirkan sumbu Z (itulah yang saya asumsikan di mana gravitasi berada, tetapi jika Anda tidak mengubah apa pun, di Unity itu sumbu Y yang naik atau turun, yaitu gravitasi ada di sumbu Y, jadi Anda mungkin harus mengubah keadaan):
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);
Cara kedua adalah metode rotasi (saya berpikir dalam 2D dalam kasus ini):
double angleRadians = Mathf.Asin(turret.transform.rotation.z - gun.transform.rotation.z);
double angle = 2 * Mathf.Rad2Deg * angleRadians;
Sekali lagi, semua kode ini akan memberi Anda nilai-nilai yang positif, jadi Anda mungkin harus menambah atau mengurangi jumlah tergantung pada sudut (ada perhitungan untuk itu juga, tapi saya tidak akan pergi yang mendalam). Tempat yang baik untuk memulai ini adalah Vector2.Dot
metode di Unity.
Blok kode terakhir untuk penjelasan tambahan tentang apa yang kami lakukan:
//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);
Jika Anda melakukan semuanya dengan benar, Anda harus mendapatkan adegan seperti ini ( tautan untuk paket unity ):
Yang saya maksud dengan selalu nilai positif:
Metode Z dapat memberikan nilai negatif:
Untuk contoh adegan, dapatkan paket unity dari tautan ini .
Berikut kode yang saya gunakan dalam adegan (di menara):
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.
}
}
Kode yang diadaptasi 3D dengan X dan Z sebagai bidang 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.
}
}