Die Antwort ist eigentlich ziemlich einfach, wenn Sie rechnen. Sie haben einen festen Abstand von Y und einen variablen Abstand von X (siehe Bild 1). Sie müssen den Winkel zwischen Z und X herausfinden und Ihren Revolver noch mehr drehen.
Schritt 1 - Ermitteln Sie den Abstand zwischen der Revolverlinie (V) und der Kanonenlinie (W), der Y ist (dies ist konstant, schadet aber nicht bei der Berechnung). Ermitteln Sie die Entfernung vom Turm zum Ziel (X).
Schritt 2 - Teilen Sie Y durch X und erhalten Sie dann den Hyperbelsinus des Werts
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.
Schritt 3 - Drehen Sie den Turm noch weiter (um die Achse, die von oben nach unten verläuft, höchstwahrscheinlich um die obere Achse, aber nur Sie können diesen Teil erkennen).
gameObject.transform.Rotate(Vector3.up, turnAngle);
In diesem Fall muss es natürlich gegen den Uhrzeigersinn gedreht werden, sodass möglicherweise ein Minus vor dem Drehwinkel hinzugefügt werden muss, wie in -turnAngle
.
Einige Teile bearbeitet. Vielen Dank an @ens für den Hinweis auf den Unterschied in der Entfernung.
Der OP sagte, seine Waffe hat einen Winkel, also gehen wir, Bild zuerst, Erklärung später:
Wir wissen bereits aus der vorherigen Berechnung, wohin die rote Linie mit der blauen Linie ausgerichtet werden soll. Also zuerst auf die blaue Linie zielen:
float turnAngle = angleBetweenTurretAndTarget - angleBetweenTurretAndGun;
turret.transform.Rotate(Vector3.up, turnAngle);
Die einzige Berechnung, die sich hier unterscheidet, ist die Berechnung von "X Prime" (X '), da der Winkel zwischen der Waffe und dem Turm (Winkel "a") den Abstand zwischen den Linien verändert hat.
//(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);
Dieser nächste Teil ist NUR erforderlich, wenn Sie die Revolverpistolen modular ausführen (dh der Benutzer kann die Pistolen auf einem Revolver wechseln und verschiedene Pistolen haben unterschiedliche Winkel). Wenn Sie dies im Editor tun, können Sie bereits sehen, welcher Schusswinkel dem Turm entspricht.
Es gibt zwei Methoden zum Ermitteln des Winkels "a", eine Methode ist die transform.up-Methode:
float angleBetween = Vector3.Angle(turret.transform.up, gun.transform.up);
Die obige Technik wird in 3D berechnet. Wenn Sie also ein 2D-Ergebnis erhalten möchten, müssen Sie die Z-Achse entfernen (ich gehe davon aus, dass dort, wo sich die Schwerkraft befindet, aber wenn Sie nichts geändert haben, ist in Unity die Y-Achse nach oben oder unten gerichtet). Das heißt, die Schwerkraft liegt auf der Y-Achse.
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);
Der zweite Weg ist die Rotationsmethode (ich denke in diesem Fall in 2D):
double angleRadians = Mathf.Asin(turret.transform.rotation.z - gun.transform.rotation.z);
double angle = 2 * Mathf.Rad2Deg * angleRadians;
Alle diese Codes geben Ihnen wiederum positive Werte, so dass Sie möglicherweise den Betrag abhängig vom Winkel addieren oder subtrahieren müssen (es gibt auch Berechnungen dafür, aber ich werde nicht weiter darauf eingehen). Ein guter Ausgangspunkt hierfür wäre die Vector2.Dot
Methode in Unity.
Letzter Codeblock für zusätzliche Erklärungen:
//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);
Wenn du alles richtig gemacht hast, solltest du eine Szene wie diese bekommen ( Link für das Unitypackage ):
Was ich mit immer positiven Werten meine:
Die Z-Methode kann negative Werte liefern:
Für eine Beispielszene erhalten Sie das Unity-Paket über diesen Link .
Hier ist der Code, den ich in der Szene verwendet habe (auf dem Turm):
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-angepasster Code mit X und Z als 2D-Ebene:
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.
}
}