4
\$\begingroup\$

Well I have a simple 2D game where all positions are defined by and X and Y coordinate.

There are objects moving at a constant velocity. And a turret fires a bullet at the X and Y coordinates of the object. By the time the bullet goes to the desired area, the object has already moved.

So i need to adjust the X and Y target positions for the turret to shoot at taking into account the bullet speed and object speed.

Here's an image showing the problem.

enter image description here

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

I've done something similar in the past and I used a quadratic equation to find the time t where the two paths (target and bullet) intersect.

This is what it looks like when implemented using libGDXs classes;

 private static Vector2 sub(Vector2 lhs, Vector2 rhs) { return (new Vector2(lhs)).sub(rhs); } private static Vector2 calculateFireDirection(Vector2 targetPosition, Vector2 turretPosition, Vector2 targetVelocity, float bulletSpeed) { Vector2 turretToTarget = sub(targetPosition, turretPosition); float a = targetVelocity.x*targetVelocity.x + targetVelocity.y * targetVelocity.y - bulletSpeed*bulletSpeed; float b = 2.0f * targetVelocity.dot(turretToTarget); float p = -b / (2 * a); float q = (float)Math.sqrt((b * b) - 4 * a * (turretToTarget.x * turretToTarget.y + turretToTarget.y * turretToTarget.y)) / (2 * a); float t = Math.max(p - q, p + q); if (t > 0) { Vector2 tp = new Vector2(targetPosition); Vector2 tv = new Vector2(targetVelocity); Vector2 collisionPoint = tp.add(tv); return sub(collisionPoint, turretPosition); } else return null; // This means the collision will never happen (or happened before the shot was fired, which is nonsensical). } 

I the formulas from somewhere, but I can't remember where.

A full program sample program;

public class Program { private static Vector2 sub(Vector2 lhs, Vector2 rhs) { return (new Vector2(lhs)).sub(rhs); } private static Vector2 calculateFireDirection(Vector2 targetPosition, Vector2 turretPosition, Vector2 targetVelocity, float bulletSpeed) { Vector2 turretToTarget = sub(targetPosition, turretPosition); float a = targetVelocity.x*targetVelocity.x + targetVelocity.y * targetVelocity.y - bulletSpeed*bulletSpeed; float b = 2.0f * targetVelocity.dot(turretToTarget); float p = -b / (2 * a); float q = (float)Math.sqrt((b * b) - 4 * a * (turretToTarget.x * turretToTarget.y + turretToTarget.y * turretToTarget.y)) / (2 * a); float t = Math.max(p - q, p + q); if (t > 0) { Vector2 tp = new Vector2(targetPosition); Vector2 tv = new Vector2(targetVelocity); Vector2 collisionPoint = tp.add(tv); return sub(collisionPoint, turretPosition); } else return null; // This means the collision will never happen (or happened before the shot was fired, which is non-sensical). } private static void runSimulation(Vector2 targetPosition, Vector2 turretPosition, Vector2 targetVelocity, float bulletSpeed) { Vector2 direction = calculateFireDirection(targetPosition, turretPosition, targetVelocity, bulletSpeed); for(float t = 0; t < 10.0f; t += 0.1f) { Vector2 tsp = new Vector2(targetPosition); Vector2 tv = new Vector2(targetVelocity); Vector2 ssp = new Vector2(turretPosition); Vector2 sv = new Vector2(direction); Vector2 tp = tsp.add(tv.scl(t)); Vector2 sp = ssp.add(sv.scl(t)); float distance = sub(tp, sp).len(); System.out.println(String.format("At time %.2f; Target=(%.2f, %.2f), Bullet=(%.2f, %.2f) distance=%.4f", t, tp.x, tp.y, sp.x, sp.y, distance)); if (distance < 0.01f) { System.out.println("COLLISION!"); break; } } } public static void main(String[] args) { // Input Vector2 targetPosition = new Vector2(1, 10); Vector2 targetVelocity = new Vector2(1, -1); Vector2 turretPosition = new Vector2(0, 0); float bulletSpeed = 10.0f; runSimulation(targetPosition, turretPosition, targetVelocity, bulletSpeed); } } 

Gives the output;

At time 0,00; Target=(1,00, 10,00), Bullet=(0,00, 0,00) distance=10,0499 At time 0,10; Target=(1,10, 9,90), Bullet=(0,20, 0,90) distance=9,0449 At time 0,20; Target=(1,20, 9,80), Bullet=(0,40, 1,80) distance=8,0399 At time 0,30; Target=(1,30, 9,70), Bullet=(0,60, 2,70) distance=7,0349 At time 0,40; Target=(1,40, 9,60), Bullet=(0,80, 3,60) distance=6,0299 At time 0,50; Target=(1,50, 9,50), Bullet=(1,00, 4,50) distance=5,0249 At time 0,60; Target=(1,60, 9,40), Bullet=(1,20, 5,40) distance=4,0199 At time 0,70; Target=(1,70, 9,30), Bullet=(1,40, 6,30) distance=3,0150 At time 0,80; Target=(1,80, 9,20), Bullet=(1,60, 7,20) distance=2,0100 At time 0,90; Target=(1,90, 9,10), Bullet=(1,80, 8,10) distance=1,0050 At time 1,00; Target=(2,00, 9,00), Bullet=(2,00, 9,00) distance=0,0000 COLLISION! 
\$\endgroup\$
1
\$\begingroup\$

You're already part of the way there with recognising that your targets have a constant velocity - as well as the speed they are moving at, they're also moving in a specific direction (which is the difference between a speed and a velocity). If you know where the bullet is travelling (given its current location and velocity) you can calculate that after x time it'll be at a new location. Using a bit of basic maths with this, the position of the turret and the velocity of the bullets it fires, you can then calculate the position you want to be aiming at to hit after x time.

\$\endgroup\$
1

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.