Predicting target trail
Shoot moving target

Calculate
When shooting a moving target, we can't aim at the target's current position, because it takes some time for the bullet to reach its target. So we need to predict where will the target be at that time. To calculate this, we need to know three things: target's position, target's velocity and bullet speed.

Law of sines
Law of sines is an equation relating the lengths of the sides of a triangle (any shape) to the sines of its angles. According to this law, we can get the relationship between the angle α and the angle β, and thereby eliminate the uncertainty factor: time. Since we already know V1 and V2, the only thing we need to calculate is the angle B.

Angle β
We can use unity function Vector3.Angle( ) to calculate angle B easily.
​
Vector3 direction = gunPosition - targetPosition;
float angleB = Vector3.Angle(direction, targetVelocity);
​
So Angle α is clear now:
float AngleA =Mathf.Asin(Mathf.Sin(angleB * Mathf.PI / 180) * targetVelocity.magnitude / bulletSpeed) * 180 / Mathf.PI
​
It should be noted that the angle calculation in the Mathf method uses the angle in radian, while the methods in the Vector3 and Quaternion use the angles in degree , so the conversion is required.

Direction
Now we got the angle α, but we still need to know which direction it is. As shown in the figure above, the target may move clockwise or counterclockwise. To figure out that, we can use vector cross product.
In two-dimensional space, if VectorA × VectorB > 0 then Vector B is in the clockwise direction of Vector A.
VectorA(x1,y1) × VectorB(x2,y2) = x1*y2- x2*y1.
​

Code and demo
White line is target direction. Red line is predicting shoot direction.
​
Code of calculating:
public static float PredictShootAngle(Vector3 targetPosition,Vector3 thisPosition, Vector3 targetVelocity,float bulletSpeed)
{
Vector3 direction = targetPosition - thisPosition;
float angleB = 180 - Vector3.Angle(direction, targetVelocity);
if (direction.x * targetVelocity.z - direction.z * targetVelocity.x > 0)
return -Mathf.Asin(Mathf.Sin(angleB*Mathf.PI/180) * targetVelocity.magnitude / bulletSpeed) * 180 / Mathf.PI;
else
{
return Mathf.Asin(Mathf.Sin(angleB * Mathf.PI / 180) * targetVelocity.magnitude / bulletSpeed) * 180 / Mathf.PI;
}
}
​
Code of turret:
public override void Shoot()
{
Transform tar = PlayerManager.instance.player.transform;
float angle = CaculateHelper.PredictShootAngle(tar.position, transform.position, tar.GetComponent<CharacterStats>().GetCurrentVelocity(), 40);
transform.rotation = Quaternion.LookRotation(tar.position - transform.position, Vector3.up) * Quaternion.AngleAxis(angle * 3, Vector3.up);
eventHandler.RangedAttack();
}
eventHandler.RangedAttack();