I saw this question: Predicting enemy position in order to have an object lead its target. My situation is a little different though.
My target moves, and the shooter moves. Also, the shooter's velocity is added to the bullets' velocities, i.e. bullets fired while sliding to the right will have a greater velocity toward the right.
What I'm trying to do is to get the enemy to be able to determine where they need to shoot in order to hit the player. Using the linked SO solution, unless the player and enemy are stationary, the velocity difference will cause a miss. How can I prevent that?
Here is the solution presented from the stack overflow answer. It boils down to solving a quadratic equation of the form:
a * sqr(x) + b * x + c == 0
Note that by sqr
I mean square, as opposed to square root. Use the following values:
a := sqr(target.velocityX) + sqr(target.velocityY) - sqr(projectile_speed)
b := 2 * (target.velocityX * (target.startX - cannon.X)
+ target.velocityY * (target.startY - cannon.Y))
c := sqr(target.startX - cannon.X) + sqr(target.startY - cannon.Y)
Now we can look at the discriminant to determine if we have a possible solution.
disc := sqr(b) - 4 * a * c
If the discriminant is less than 0, forget about hitting your target -- your projectile can never get there in time. Otherwise, look at two candidate solutions:
t1 := (-b + sqrt(disc)) / (2 * a)
t2 := (-b - sqrt(disc)) / (2 * a)
Note that if disc == 0 then t1 and t2 are equal.
Answer
Okay, let's put some sanity into this. I am afraid you are not making it easy at all, your code does not compile, is inconsistent with regards to variable names (playerVelocityX
becomes playerXvelocity
after a few lines? what is xVelocity
?) and is too verbose. It is basically impossible to debug lest you put considerable effort into it.
So, here are the things to fix:
Bullet speed
The bullet speed must be 30
, period. There is no need for the computations you are doing: the change of the frame of reference is precisely there to avoid the complexity. You only add the enemy's velocity after you found a solution, when you go back to the main reference frame.
Solution validity
You are not checking that the time
solution is positive.
Numerous coding errors
You are testing time1
and time2
but always using time1
in the results.
You do playerXvelocity - yVelocity
which is inconsistent.
You are doing / 2 * a
instead of / (2.f * a)
. This is the worst error and it's why everything is going wrong.
You compute shootx
and shooty
as the final position of the bullet, whereas what you are looking for is the velocity of the bullet.
Fixed code
float const bulletSpeed = 30.f;
/* Relative player position */
float const dx = playerX - enemyX;
float const dy = playerY - enemyY;
/* Relative player velocity */
float const vx = playerVelocityX - enemyVelocityX;
float const vy = playerVelocityY - enemyVelocityY;
float const a = vx * vx + vy * vy - bulletSpeed * bulletSpeed;
float const b = 2.f * (vx * dx + vy * dy);
float const c = dx * dx + dy * dy;
float const disc = b * b - 4.f * a * c;
shouldShoot = false;
if (disc >= 0.f)
{
float t0 = (-b - std::sqrt(disc)) / (2.f * a);
float t1 = (-b + std::sqrt(disc)) / (2.f * a);
/* If t0 is negative, or t1 is a better solution, use t1 */
if (t0 < 0.f || (t1 < t0 && t1 >= 0.f))
t0 = t1;
if (t0 >= 0.f)
{
/* Compute the ship's heading */
shootx = vx + dx / t0;
shooty = vy + dy / t0;
heading = std::atan2(shooty, shootx) * RAD2DEGREE;
/* Compute the bullet's velocity by adding the enemy's velocity */
bulletVelocityX = shootx + enemyVelocityX;
bulletVelocityY = shooty + enemyVelocityY;
shouldShoot = true;
}
}
No comments:
Post a Comment