당신이 수학을하면 대답은 실제로 아주 쉽습니다. 고정 거리는 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);
여기서 다른 유일한 계산은 건과 포탑 사이의 각도 (각 "a")가 선 사이의 거리를 변경했기 때문에 "X Prime"(X ')의 계산입니다.
//(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);
모든 것을 올바르게했다면 다음과 같은 장면이 나타납니다 ( 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.
}
}