Leading the Target
How do you compute where you have to aim to hit a moving target with a finite-speed projectile? This is a common question on gamedev.net's forums. This article presents a procedure to solve this problem and some variations thereof.
Plain-vanilla deflection
Let's assume the shooter can aim and shoot anywhere instantly, the target is moving at a constant velocity and the projectile will travel at a constant velocity too. We are given as inputs the target's current position, its velocity and the speed of our projectile. We'll use coordinates where the shooter is at the origin and has zero velocity.First-order correction
As mentioned before, if we naively aim at the target's current position, by the time the projectile gets there, the target will have moved. We can compute how long it will take for the projectile to get to the target's current position, compute where the target will be then and aim there instead.Position compute_first_order_correction(Position target_position, Vector target_velocity, float projectile_speed) { float t = distance(Origin, target_position) / projectile_speed; return target_position + t * target_velocity; } This simple piece of code is probably good enough in many cases (if the target is moving slowly compared to the projectile speed, if the target is moving perpendicularly to the shooter-to-target vector, or if we want to sometimes miss because a more precise solution would be detrimental to the fun of the game). Iterative approximation
For a more precise solution, you could iterate this first-order correction until it converges.Position iterative_approximation(Position target_position, Vector target_velocity, float projectile_speed) { float t = 0.0f; for (int iteration = 0; iteration < MAX_ITERATIONS; ++iteration) { float old_t = t; t = distance(Origin, target_position + t * target_velocity) / projectile_speed; if (t - old_t < EPSILON) break; } return target_position + t * target_velocity; } Computing the answer directly
In the iterative approximation, we would stop if we found a place where old_t and t match. This gives us an equation to solve: t = distance(Origin, target_position + t * target_velocity) / projectile_speed Let's do some computations to try to solve it. t = sqrt(dot_product(target_position + t * target_velocity, target_position + t * target_velocity)) / projectile_speed t^2 * projectile_speed^2 = dot_product(target_position + t * target_velocity, target_position + t * target_velocity) t^2 * projectile_speed^2 = dot_product(target_position, target_position) + 2 * t * dot_product(target_position, target_velocity) + t^2 * dot_product(target_velocity, target_velocity) This is a second-degree equation in t which we can easily solve, leading to the following code: // a*x^2 + b*x + c = 0 float first_positive_solution_of_quadratic_equation(float a, float b, float c) { float discriminant = b*b - 4.0f*a*c; if (discriminant < 0.0f) return -1.0f; // Indicate there is no solution float s = std::sqrt(discriminant); float x1 = (-b-s) / (2.0f*a); if (x1 > 0.0f) return x1; float x2 = (-b+s) / (2.0f*a); if (x2 > 0.0f) return x2; return -1.0f; // Indicate there is no positive solution } Position direct_solution(Position target_position, Vector target_velocity, float projectile_speed) { float a = dot_product(target_velocity, target_velocity) - projectile_speed * projectile_speed; float b = 2.0f * dot_product(target_position, target_velocity); float c = dot_product(target_position, target_position); float t = first_positive_solution_to_quadratic_equation(a, b, c); if (t <= 0.0f) return Origin; // Indicate we failed to find a solution return target_position + t * target_velocity; } The general case
There are many variations of the problem we could consider: Accelerating targets, accelerating projectiles, situations where it takes time to aim at a new direction... All of them can be solved following the same template. The things that could change can be encoded in two functions:- position_of_target_at(time)
- time_to_hit(position)
Conclusion
This article covered three methods to implement deflection in your games: First-order correction, iterative approximation and directly finding the solution. You'll need to use some judgement to decide which one to use. Hopefully this article gives you enough to make an informed decision.Article Update Log
30 Oct 2015: Initial release 4 Nov 2015: Minor fixesRelated Tutorials
A Day As A Game Designer
The fabled game designer. The man, the myth, the legend behind the game. An inspiration to young creatives who wish to …
Kai Wüest
So You Want to be a Game Developer?
Battletech tools developer Chris Eck describes his journey and advice for getting a job in the industry.
A Quick Guide to Gamification and Gamification Careers
If you find yourself slightly stumped over the ever-growing buzz around gamification, and unsure whether there is any o…
Sophie Jackson
Raph Koster's Postmortems: Una Carrera
This excerpt from Raph Koster's Postmortems is an adaptation from a speech he delivered at GameDay Peru in early 2015. …
Raph Koster
Negotiating Sign-On Bonuses in the Games Industry
A quick blurb on signing bonuses in the games industry and how to approach asking for one.
A LinkedIn Profile for Job Hunting and Networking
Marc Mencher is founder and CEO of GameRecruiter and author of Get in the Game!, an instructional book on building a ca…
Discussion