 alvaro

Member

8073

• Days Won

8

alvaro had the most liked content!

21497 Excellent

• Rank
Legend

• Role
Programmer
• Interests
Programming

Recent Profile Visitors

46384 profile views

• Jammer1

1. Where should we aim if we want to hit a moving target with a finite-speed projectile? This is one of the recurrent questions from beginner game developers. If we naively aim at the target's current position, by the time our projectile gets there the target will have moved, so we need to aim ahead of the target's current position. The technical name for the technique is "deflection", but most people use "leading the target". Wikipedia page here. There are several variations of the problem, where perhaps the projectile is a missile that needs to accelerate, or where the shooter is a turret that is currently aiming in some direction and needs time to aim somewhere else... We'll cover the simple case first, and then we'll present a general template for solving variations of the problem. 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