神刀安全网

Solving Ballistic Trajectories

A common problem in video games is to calculate the angle to launch a projectile to hit a target. It’s so common I’ve written code to solve it on literally every game I’ve ever worked on.

Each time this problem comes up I tend to grab a pen and pad to re-solve it from scratch. I’m tired of doing that. To save future-self some time I’m going to put the solution on the internet. I’m also going to share a twist that I often prefer for design purposes.

TL;DR

Want to skip the words and see the final result? Fine. I don’t blame you. Even if it makes me a little sad.

Source Code: GitHub
Demo: WebGL Unity Demo

Equations of Motion

The problem always starts the same. Given a launcher and a target, at what angle must the projectile launch to hit the target?

There are four basic equations of motion . Today we’ll only be using one of them.

Solving Ballistic Trajectories

In plain English, the final position EQUALS initial position PLUS velocity times time PLUS one-half acceleration times time-squared. This simple equation, a little algebra, and a few trigonometric identities is all we need.

Refresh

Here’s a quick refresh before we get started.

Solving Ballistic Trajectories

Given a projectile with fixed speed S and launch angle θ (theta) we can compute the x and y components of velocity. Or if we have S and can otherwise determine y then we can solve for θ and x.

We’ll be using some Algebra.

Solving Ballistic Trajectories

We’ll be making heavy use of the quadratic formula.

Solving Ballistic Trajectories

Range

For video games we probably want to know the maximum range of a projectile. AI needs to know how close to move. Players need clear visual indicators showing danger zones.

There is a very simple equation for maximum range on a flat surface. But we’re going to jump off the deep end and start with the generalized form.

Given a projectile with fixed speed (S) and gravity (G) what is it’s max range?

Solving Ballistic Trajectories
Solving Ballistic Trajectories
  1. Substitute known variables (y0, S, G) into our basic equation of motion.
  2. Apply quadratic formula. Ignore smaller term.
  3. Plug t back into x = S*cos θ*t and simplify.

Voila!

To determine maximum range use θ=45 degrees. If y0=0 and θ=45 then the big ugly formula reduces to S^2/G.

Demo

For testing and to provide visualizations I created a Unity demo. It involves teapots shooting teapots. Pew pew!

Demo: WebGL Unity Demo

The demo has a handful of sliders. Here we see the range indicator for a teapot turret. As speed goes up range goes up. As gravity goes up range goes down. Pretty simple.

Firing Angle to Hit Stationary Target

Now the fun part.

Given a projectile with fixed speed (S) and gravity (G) at what angle should it be fired to hit a stationary target?

Solving Ballistic Trajectories

Phew. We have two equations and two unknowns. Let’s break it down.

  1. First equation, two unknowns (t, θ)
  2. Second equation, two unknowns (t, θ)
  3. Solve (1) for t
  4. Plug (3) into (2)
  5. Trig substitution: sin θ/cosθ = tanθ
  6. Trig substitution: 1/(cos θ)^2 = 1 + (tan θ)^2
  7. Expand and rearrange
  8. Quadratic formula
  9. Multiply top/bottom by -S^2/x. Move S^4/x^2 into root
  10. Apply arctan to each side

Tada! This results in two angles. One low and one high. Here’s what it looks like in practice.

Visual Imperfection

Take a look at the gif above. When the teapot first starts shooting it looks pretty good. The high arc looks nice and pretty. The low arc feels crisp and efficient.

When range increases it doesn’t look so great. The low arc is almost flat. The high arc is comically high. This is the problem with a fixed speed projectile. It only looks good when the target is out the outskirts of its range.

What if there were a better way?

Lateral Speed

I often prefer to define projectile speed laterally. Only on the ground plane. I then explicitly define arc height. Which means vertical velocity and gravity become variable.

This has several advantages. First, it always looks good!

Second, it’s more intuitive for design. Designers don’t care about absolute speed. They care that a turret has a range of 20 meters and projectiles take 1 second to travel that distance. They shouldn’t need a graphic calculator to change balance numbers. Nor should artistic tweaks affect gameplay mechanics.

Third, it’s easier to hit a moving target. We’ll cover this in more detail in a bit.

Here’s what it looks like.

A high arc with short target distance looks pretty silly. If you use this method in your game you’ll want to decrease arc height when targets are close.

Solving with Lateral Speed

Given a projectile with lateral speed (S) and peak height (y_peak) what is velocity, gravity to hit a stationary target?

Solving Ballistic Trajectories
  1. Basic equation of motion
  2. Solve (1) for 2
  3. Define y_peak (user constant) to occur at (1/2)t
  4. Define y_end (target height) to occur at t
  5. Magic!
  6. More magic!
  7. Firing vector is (S, v.y) with gravitational acceleration g

Presto! Hey, wait a second. Magic? That’s cheating! Yes, but for a reason.

Steps (3) and (4) is another two equations with two unknowns. I’m lazy and don’t want to write it out. Plus I’d screw up and flip a sign. So I let a computer solve it for me.

More specifically, I used Wolfram Alpha . I recommend everyone have Wolfram in their toolbox. It’s quite handy.

Solving Ballistic Trajectories

If a+c == 2b then y0, y_peak, and y_end are collinear. Which means you’re firing in a straight line.

Lateral Speed with Moving Target

At this point we have two different trajectory solutions. But enemies do not tend to stay in place. They move around. We need to solve the trajectory to hit a moving target.

This is where lateral speed shines. By defining speed on the ground plane it’s super easy to solve for a moving target.

Solving Ballistic Trajectories
  1. Where X is the target position and V is target velocity
  2. Square both sides.
  3. Re-arrange into quadratic
  4. Apply quadratic formula

For steps 5 through 9 refer to the previous section.

It makes me giggle with glee. Pew pew pew!

Fixed Speed with Moving Target

What if we wanted to hit a moving target with a fixed speed projectile? Oh boy. This is a can of worms! You don’t even know.

I’ve never actually shipped this in my career. Generally speaking games don’t want pinpoint artillery. It’s not fun! Instead you ballpark the future position and aim at a random point nearby. When players think of artillery they think of dumb shells raining around. Not perfect, laser guided death.

Writing this blog post I found the solution to a fixed speed projectile and moving target isn’t readily found on the internet. I’ll caveat this by saying you probably don’t want to do this in your game. But I spent a lot of time working this out. And damnit I don’t want that time to be for naught!

Quartics

The reason you don’t want to do this is quartics. The answer fundamentally involves a quartic.

Solving Ballistic Trajectories

Quadrics have an easy, elegant solution through the quadratic formula. Cubics are solvable a few different ways. Quartics are a bitch .

Solving quartics is well beyond the scope of this article. To be honest it’s beyond the scope of my mathematics ability. Fortunately for us, Graphics Gems I from 1990 has code for solving quartics. It’s available here . I used this code for my demo. I can not speak to it’s accuracy or numerical stability. Proceed with extreme caution.

Method One

Alright then. Let’s solve it. What is the angle to fire a projectile with fixed speed at a moving target? This method comes from a 2007 blog post by James McNeill. With reinforcement Ryan Juckett .

Solving Ballistic Trajectories
  1. Where P is target position and V is target velocity
  2. Square both sides
  3. Re-arrange terms
  4. Calculate quartic coefficients and plug into SolveQuartic
  5. Use t to calculate target position then calculate trajectory to stationary point.

This works. The heavy lifting is in SolveQuartic. We then use the stationary target solver from earlier in the post.

Method 2

Before discovering method one I derived the solution a different way. It involves way, way more steps. But I find the end result more elegant. Plus I used like 8 pages of papers and I don’t want those trees to have sacrificed themselves in vain.

Solving Ballistic Trajectories

Holy crap. Thirty two steps!? It’s worse than it looks.

1–7; Declare variables.

8–11; Declare system of equations. Four equations, four unknowns – d, e, f, t.

12–15; Solve (8) for d. Multiply out d^2 for later.

16–19; Solve (10) for f. Multiply out f^2 for later.

20–24; Solve (9) for e. Multiply out e^2 for later.

25–27; Solve (11) for e^2. Substitute d^2 and f^2.

28–30; Set (27) equal to (24). Multiply by t^2 and arrange into quartic.

31; Plug coefficients into SolveQuartic.

32; Plug positive, real roots into (14), (18), (23) for d, e, f.

The code is quite short. There are more lines devoted to variable declaration than actual math! Aside from SolveQuartic of course.

Solving Ballistic Trajectories

That’s not so scary looking is it? It’s a little more complicated as there are multiple solutions. One for each positive, real root returned by SolveQuartic.

I feel method two is a little cleaner than method one. After solving the quartic you can plug t into three simple formulas. That’s better than calling a stationary target solver which does a bunch of work.

Warning

Code written for this test has not been battle tested. Nor has this post been peer reviewed. There are probably a handful typos, errors, and mishandled cases. If you find such a mistake please let me know. Discretely so no one knows my shame. :)

In the meantime treat this not as a finished solution but a solid starting point.

Creation Tools

I used a handful of tools in the creation of this post. Several of which were new to me.

Unity for the demo. 
Dropbox for hosting Unity WebGL build.
Paper , Affinity Designer , and MSPaint for images.
Arachnid Latex + MathJax for LaTeX formulas.
FFmpeg for turning sequential screenshots into a movie.
Gfycat for embedding movies.

LaTeX syntax is awful. Hideous and hard to learn. All LaTeX formulas can be found here . Here’s an example.

Solving Ballistic Trajectories

Here is my FFmpeg cmdline:

ffmpeg -f image2 -r 60 -i C:/temp/UnityCapture/0/shot%04d.png -c:v libx264 -pix_fmt yuv420p out.mp4

Conclusion

That just about does it. I spent way more time on this post than I expected. I solved a case I’d never solved before and I learned a few new tools. A worthwhile endeavor.

Nothing in this post is new or original. I tried to explain things thoroughly without being overly verbose. I feel pretty good having thorough descriptions all in one place. Hopefully this is helpful to a few folks out there.

Source Code: GitHub
Demo: WebGL Unity Demo

Thanks for reading.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Solving Ballistic Trajectories

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址