Como você está trabalhando apenas com física 2D (sem velocidade Z), esse problema pode ser bastante simplificado. A maneira mais fácil de fazer isso é parar de pensar nos movimentos de origem e destino em relação às coordenadas do mundo e apenas pensar no destino em movimento em relação à fonte (e manter a fonte estacionária).
Vector TargetInitialPosition = new Vector ( target.X - source.X ,
target.Y - source.Y );
Vector TargetApparentVelocity = new Vector( target.velocityX - source.velocityX ,
target.velocityY - source.velocityY );
Normalmente, a velocidade de uma bala seria muito maior que a velocidade do atirador, portanto, geralmente é assumido que a bala é independente, mas há ocasiões em que isso não é verdade, como disparar de um helicóptero ou avião de combate.
Então precisamos calcular a velocidade da bala:
// Your directional vector MUST be normalized...
Vector BulletVelocity = new Vector( source.directionX * Bullet::StaticSpeed + source.velocityX ,
source.directionY * Bullet::StaticSpeed + source.velocityY );
O problema que você está enfrentando é que o alvo se move quando a bala os atinge.
TargetPosition = TargetInitialPosition + TargetApparentVelocity * t
BulletPosition = BulletInitialPosition + BulletVelocity * t
= BulletVelocity * t
e resolva o TargetPosition == BulletPosition porque o marcador atingirá o alvo. Agora você tem três incógnitas e apenas duas equações. Podemos remover 't' usando a derivada de primeira ordem:
TargetInitialPosition + ( TargetApparentVelocity - BulletVelocity ) * t == 0
dV / dt = TargetApparentVelocity - BulletVelocity
Agora, para atingir o alvo, você desejaria dV/dt == -TargetInitialPosition * k
. A constante deve ser a mesma nas coordenadas X e Y e é o número de segundos que o marcador levará para atingir o alvo.
TargetApparentVelocity.X - BulletVelocity.X == k * -TargetInitialPosition.X
k = ( BulletVelocity.X - TargetApparentVelocity.X ) / TargetInitialPosition.X
----------------------
TargetApparentVelocity.Y - BulletVelocity.Y == k * -TargetInitialPosition.Y
k = ( BulletVelocity.Y - TargetApparentVelocity.Y ) / TargetInitialPosition.Y
torná-los iguais:
( BulletVelocity.X - TargetApparentVelocity.X ) / TargetInitialPosition.X
= ( BulletVelocity.Y - TargetApparentVelocity.Y ) / TargetInitialPosition.Y
ou para expandir as variáveis:
( source.directionX * Bullet::StaticSpeed + source.velocityX - target.velocityX + source.velocityX ) / ( target.X - source.X )
== ( source.directionY * Bullet::StaticSpeed + source.velocityY - target.velocityY + source.velocityY ) / ( target.Y - source.Y )
Então a álgebra fornece sua equação final:
source.directionY = ( target.velocityY * ( source.X - target.X ) - 2 * source.velocityY * ( source.X - target.X ) + ( Bullet::Speed * source.directionX + 2 * source.velocityX - target.velocityX ) * ( source.Y - target.Y ) ) / ( Bullet::Speed * ( source.X - target.X ) )
A próxima parte é confusa e você decide como deseja implementá-la no seu código, mas apenas substituímos isso e normalizamos o vetor.
sqrt( source.directionX ^ 2 + source.directionY ^ 2 ) == 1
Você acaba com uma equação com apenas um desconhecido (source.directionX) e pode resolvê-lo com directionX e substituí-lo novamente para obter directionY.
Eu não testei nenhum desses códigos e sinta-se à vontade para apontar quaisquer erros matemáticos que cometi, mas a teoria deve ser sólida :).
Boa sorte.