Im trying to write an equation that’ll tell my enemies where to aim their bullets in order to hit the player’s spaceship.
The variables I’m working with are playerSpeed, bulletSpeed. So first, I determined the amount of time it takes for the bullet to reach the player: var time = Vector3.Distance(player, enemy) / bulletSpeed; Then, I determine the distance that the ship will travel in that time: var dist = time * playerSpeed; Then I can take variable dist and add it to the player’s position: var target : vector3 = player.transform.position + (player.transform.rotation * Vector3(0,0,dist) );
So far through, this equation seems a bit off. It tends to aim a little bit too ahead of the player.
Maybe there is some sort of trigonometry I have to use to get a really accurate equation? Hopefully someone here has already used an equation like this in a game. It seems a pretty common thing to need for AI aiming bullets.
Nice mathematical discussion on plotting an intercept here: Calculate Interception Course
Don’t have the time to actually whip off an algorithm for you, but hopefully you can figure it out. It’s for 2D (x,y), but I’m sure it can be expanded to 3D (x,y,z) easily.
this looks really helpful, but i dont know what ever language that is they’re using in that forum.
here is the code that looks like what i need:
1 Vector trans_p = (pos_p - pos_u);
2
3 double d_squared = trans_p.lengthSquared();
4 double target_dir = vel_u.normalized();
5 double y = dotProduct(trans_p, target_dir);
6 double speed_u_sq = vel_u.lengthSquared();
7 double speed_p_sq = speed_p * speed_p;
8 double i, i1, i2;
9
10 if (abs(speed_u_sq / speed_p_sq - 1.0) <= 0.001)
11 {
12 i1 = -1.0;
13 i2 = d_squared / (2 * y);
14 }
15 else
16 {
17 double speed_coeff = speed_p_sq / speed_u_sq - 1.0;
18 double delta = y * y + speed_coeff * d_squared;
19 if (delta < 0.0)
20 // no way we could intercept, the missile is too slow
21 do_whatever;
22 delta = std::sqrt(delta);
23 i1 = (-y + delta) / speed_coeff;
24 i2 = (-y - delta) / speed_coeff;
25 }
26
27 if ((i1 > 0.0) (i2 > 0.0))
28 i = (i1 > i2) ? i2 : i1;
29 else if (i1 > 0.0)
30 i = i1;
31 else if (i2 > 0.0)
32 i = i2;
33 else
34 do_whatever; // missile too slow to intercept
35
36 Vector intercept_pos = pos_u + target_dir * i;
the problem is that i can’t keep track of which of these variables are which. so far, i think pos_p is the ship position, and pos_u is the missile position. i need some help picking out the different steps in here. so far it seems:
find the difference between the position of the ship and enemy
square the vector (wouldn’t this turn x y and z positive though? what if we need it to be negative based on the position?)
then i think you normalize this vector
do something with dot products
could someone who knows this language help me out and see if I’m right so far? Even if I did read that right, this doesn’t get me very far yet.
One simple solution, although not very elegant and not perfect, may be to calculate it with more iterations:
Once you have calculated the position using the distance (player,enemy) calculate it again using the “new distance” (player, futurePosition).
3-4 Iterations should be enough to get a decent approximation.
I’m not sure it always converge to the right position tough
I used that trick (multiple iterations per frame) in a Robocode competition. I continued iterating until the “aiming error” was below an error threshold (max 10 iterations per frame) and it was very effective against certain bots, but I had some problem against bots that had a circular movement or a very chaotic (probably random) movement patterns.
Maybe:
Instead of considering our target moving, let’s consider the source position moving in the opposite direction and the target not moving, then we have to find the direction vector (with magnitude = speed of bullet) that summed to our speed vector gives a vector pointing to the target.
Each “pass” of a loop is called an iteration, so your for loop would have 4 iterations. Your code looks good, but a better way would be:
var lastPosition : Vector3;
var nextPosition : Vector3 = player.position;
var numIterations : int = 4;
var threshold : int = 0.1f; // a very small number
var distance : int = 0.2f; // a number greater than the threshold
for (var i : int = 0; (distance > threshold) (i < numIterations); i++)
{
var time : float = Vector3.Distance(bullet.transform.position, nextPosition) / bulletSpeed;
lastPosition = nextPosition;
nextPosition =
player.transform.position +
(player.transform.rotation * Vector3(0,0,time * playerSpeed));
distance = Vector3.Distance(lastPosition, nextPosition);
}
return nextPosition;
The function will try to find the player position with an error-margin lesser than the “threshold” value in the given number of iterations but it might be not possible, so you can adjust these values to decide what is more important for you: performance o precision. If you set a low “numIterations” value and a high “threshold” value, the function would be very fast but not too accurate. However, if you set a high “numIterations” value and a low “threshold” value, you would have a very high precision, but the function would be much slower.
I see. So very basically, your function is very much like mine, except variables distance and threshold prevent unity from calculating this function over and over again when the current result is within the threshold, aka close enough.
Yes, that would be the idea. However, you should also look the xomg’s post. I haven’t looked carefully the code posted in the wiki but it will probably be more efficient in almost all cases because it doesn’t have any loop.