あなたが数学をすれば、答えは実際には非常に簡単です。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の前にマイナスを追加する必要があります-turnAngle
。
一部を編集しました。距離の違いを指摘してくれた@ensに感謝します。
OPは、彼の銃には角度があると言ったので、ここで最初に説明します。
前の計算から、赤い線を青い線に合わせてどこに向けるかがすでにわかっています。だから、最初に青い線を目指して:
float turnAngle = angleBetweenTurretAndTarget - angleBetweenTurretAndGun;
turret.transform.Rotate(Vector3.up, turnAngle);
ここで異なる唯一の計算は、「Xプライム」(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」を見つけるには2つの方法があります。1つは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);
2番目の方法は回転方法です(この場合は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);
すべてを正しく行った場合、次のようなシーンが得られるはずです(unitypackageのリンク):
常に正の値が意味すること:
Zメソッドは負の値を与えることができます:
サンプルシーンについては、このリンクからunitypackageを取得してください。
シーンで使用したコードは次のとおりです(タレット上)。
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.
}
}
XとZを2D平面とする3D適応コード:
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.
}
}