Vì bạn chỉ làm việc với vật lý 2D (không có vận tốc Z), vấn đề này có thể được đơn giản hóa rất nhiều. Cách dễ dàng để làm điều này là ngừng suy nghĩ về cả nguồn và mục tiêu di chuyển so với tọa độ thế giới và chỉ nghĩ về mục tiêu di chuyển so với nguồn (và giữ ổn định nguồn).
Vector TargetInitialPosition = new Vector ( target.X - source.X ,
target.Y - source.Y );
Vector TargetApparentVelocity = new Vector( target.velocityX - source.velocityX ,
target.velocityY - source.velocityY );
Thông thường, vận tốc của viên đạn sẽ cao hơn nhiều so với vận tốc của người bắn nên người ta thường cho rằng viên đạn là độc lập nhưng có những trường hợp không đúng, chẳng hạn như bắn ra từ trực thăng hoặc máy bay chiến đấu.
Sau đó, chúng ta cần tính toán vận tốc viên đạn:
// Your directional vector MUST be normalized...
Vector BulletVelocity = new Vector( source.directionX * Bullet::StaticSpeed + source.velocityX ,
source.directionY * Bullet::StaticSpeed + source.velocityY );
Vấn đề bạn gặp phải là mục tiêu đã di chuyển theo thời gian viên đạn chạm tới chúng.
TargetPosition = TargetInitialPosition + TargetApparentVelocity * t
BulletPosition = BulletInitialPosition + BulletVelocity * t
= BulletVelocity * t
và giải quyết cho TargetPocation == BulletPocation vì khi đó viên đạn sẽ bắn trúng mục tiêu. Bây giờ bạn có ba ẩn số và chỉ có hai phương trình. Chúng tôi có thể xóa 't' bằng cách lấy đạo hàm bậc nhất:
TargetInitialPosition + ( TargetApparentVelocity - BulletVelocity ) * t == 0
dV / dt = TargetApparentVelocity - BulletVelocity
Bây giờ để đạt được mục tiêu, bạn muốn dV/dt == -TargetInitialPosition * k
. Hằng số phải giống nhau ở tọa độ X và Y và là số giây mà viên đạn sẽ mất để bắn trúng mục tiêu.
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
làm cho chúng bằng nhau:
( BulletVelocity.X - TargetApparentVelocity.X ) / TargetInitialPosition.X
= ( BulletVelocity.Y - TargetApparentVelocity.Y ) / TargetInitialPosition.Y
hoặc để mở rộng các biến:
( 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 )
Sau đó đại số cung cấp cho bạn phương trình cuối cùng của bạn:
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 ) )
Phần tiếp theo rất lộn xộn và tùy thuộc vào cách bạn muốn triển khai nó trong mã của mình, nhưng chúng tôi chỉ thay thế điều này trong và bình thường hóa vectơ.
sqrt( source.directionX ^ 2 + source.directionY ^ 2 ) == 1
Bạn kết thúc với một phương trình chỉ với một ẩn số (source.directionX) và bạn có thể giải nó cho directionX sau đó thay thế trở lại để lấy hướngY.
Tôi đã không kiểm tra bất kỳ mã nào trong số này và cảm thấy thoải mái khi chỉ ra bất kỳ sai lầm toán học nào tôi đã thực hiện, nhưng lý thuyết nên là âm thanh :).
Chúc may mắn.