I'm playing a programming game in which script-controlled tanks drive around and try to shoot each other until only one side remains. Because of the way the steering works, the tanks often follow circular trajectories, so leading a shot in those circumstances is very useful.
I have developed an equation that seems to find a correct shot angle, but I can only solve it numerically. I was hoping that someone here could help me come up with a closed-form solution, or propose a different way of approaching the problem that might be better all around. Here's how my solution works:
Concept: If I fire at time 0, then the bullet can only hit if at some time $t$, the enemy and the bullet are equidistant from me. If I can find the value for $t$, then I can determine where the enemy will be at that time and from there I can compute the angle I should use for aiming.
In order to compute this, here's what I did:
- $\omega_0$ is the enemy's initial angle from the $x$ axis
- $\omega$ is the enemy's rate of turn, in radians per time
The enemy tank's velocity $\vec{v}(t)$ is given by $$ \begin{align} \vec{v}(t) &= \left|\vec{v}_0\right| \left(\cos\left(\omega_0 + \omega t\right) \hat{\imath} + \sin\left(\omega_0 + \omega t\right) \hat{\jmath}\right) \end{align} $$
The tank's position $\vec{e}(t)$ is given by $$ \begin{align} \vec{e}(t) &= \vec{e}_0 + |\vec{v}_0|\int_0^t \cos(\omega_0 + \omega t) \hat{\imath}\, dt + |\vec{v}_0| \int_0^t \sin(\omega_0 + \omega t) \hat{\jmath}\, dt \\ &= \vec{e}_0 + {|\vec{v}_0|\over \omega} \sin(\omega_0 + \omega t) \hat{\imath} -{|\vec{v}_0|\over \omega} \cos(\omega_0 + \omega t) \hat{\jmath} \\ \end{align} $$
The bullet's distance from me $b(t)$ is given by $$ b(t) = Qt $$
If my position is $\vec{p}$, then the tank's position relative to my position is $\vec{r}(t)$
$$ \begin{align} \vec{r}(t) &= \vec{e}(t) - \vec{p}\\ &= \vec{e}_0 - \vec{p} + {|\vec{v}_0|\over \omega} \sin(\omega_0 + \omega t) \hat{\imath} -{|\vec{v}_0|\over \omega} \cos(\omega_0 + \omega t) \hat{\jmath}\\ &= \left(e_{0.x} - p_x + {|\vec{v}_0|\over \omega} \sin(\omega_0 + \omega t)\right)\hat{\imath} + \left(e_{0.y} - p_y - {|\vec{v}_0|\over \omega} \cos(\omega_0 + \omega t)\right)\hat{\jmath}\\ \end{align} $$
So, what I want is to find a $t$ such that (recall $Q$ is the bullet's speed) $$ \begin{align} |\vec{r}(t)| &= Qt \\[6pt] \vec{r}(t)\cdot\vec{r}(t) &= Q^2 t^2\\ \left(e_{0.x} - p_x + {|\vec{v}_0|\over \omega} \sin(\omega_0 + \omega t)\right)^2 + \left(e_{0.y} - p_y - {|\vec{v}_0|\over \omega} \cos(\omega_0 + \omega t)\right)^2 &= Q^2 t^2\\ \end{align} $$
Let $$ \begin{align} A &= e_{0.x} - p_x\\ B &= e_{0.y} - p_y\\ \end{align} $$ then $$ \begin{align} \left(A + {|\vec{v}_0|\over \omega} \sin(\omega_0 + \omega t)\right)^2 + \left(B - {|\vec{v}_0|\over \omega} \cos(\omega_0 + \omega t)\right)^2 &= Q^2 t^2\\ A^2 + 2A{|\vec{v}_0|\over \omega} \sin(\omega_0 + \omega t) + \left({|\vec{v}_0|\over \omega}\right)^2 \sin^2(\omega_0 + \omega t) \qquad & \\ \qquad {}+ B^2 - 2B{|\vec{v}_0|\over \omega} \cos(\omega_0 + \omega t) + \left({|\vec{v}_0|\over \omega}\right)^2 \cos^2(\omega_0 + \omega t) &= Q^2 t^2 \\ \left({|\vec{v}_0|\over \omega}\right)^2 + A^2 + B^2 +2A{|\vec{v}_0|\over \omega}\cos(\omega_0 + \omega t) - 2B{|\vec{v}_0|\over \omega}\sin(\omega_0 + \omega t) &= Q^2t^2 \end{align} $$
I was unable to solve this, so I had to evaluate it numerically using bisection. Based on that and my basic testing, this seems to yield correct results. This is good enough for tank combat, but I want to know if there is a way to write a general solution, or maybe if there is a better way to approach this problem altogether. Is there a better way?
TL;DR: I don't think you can avoid numerical methods if you want an accurate solution, but you can get the answer by solving a simpler equation.
Let's consider just the distance from the point $\vec p$ from which you fired to the point $\vec e(t)$ where the tank is at time $t$.
Then in order for you to hit the tank at time $t$, $t$ needs to be a solution of the equation
$$ \lVert \vec e(t) - \vec p \rVert = Qt. \tag1 \label{eq:hit} $$
(You also need to aim in the right direction, but let's leave that problem for later.)
Let $C$ be the center of the circle traveled by the tank, with position vector $\vec c$. Let $E(t)$ and $P$ be the points described by the position vectors $\vec e(t)$ and $\vec p$.
Suppose that at the instant you fire, the points $E(t)$, $C$, and $P$ form a triangle with angle $\theta_0$ at vertex $E_0$ and that the angle is increasing at the rate $\omega$ as $E(t)$ moves around its circular path, so the angle at a time $t$ shortly after you fire is $\theta(t) = \theta_0 + \omega t$.
For convenience, let $R_0 = \lVert \vec e(t) - \vec c \rVert$ (which is constant) and let $r_0 = \lVert \vec p - \vec c \rVert$.
Then the law of cosines says
$$ \lVert \vec e(t) - \vec p \rVert^2 = R_0^2 + r_0^2 - 2 R_0 r_0 \cos(\theta(t)). $$
Use Equation \eqref{eq:hit} to replace the left-hand side with $Qt$ and replace $\theta(t)$ as we defined it earlier:
$$ Qt = R_0^2 + r_0^2 - 2 R_0 r_0 \cos(\theta_0 + \omega t). \tag2 \label{eq:t}$$
The functions we usually consider elementary are not sufficient to solve equations like this. A numerical solution seems like your best bet.
But if you solve for $t$ in Equation \eqref{eq:t}, you know where the enemy tank will be at that time, so you can simply aim in that direction.