I frequently get asked when I exhibit Super Rude Bear Resurrection how I managed to get Unity's physics to actually feel good for a platformer, and I've been asked for help on that note. I'm concentrating on development so I don't really have time at the moment to go back to square one and walk through building everything from a character controller up, but I've decided henceforth to document everything physicsy as I continue development (which there should be a lot of, especially with all the planned boss battles).
I'm going to do a pretty quick tip this time, but I'll walk you through it carefully rather than just dumping you with a formula.
So, here's today's conundrum:
I'm just planning the iceworld levels of SRBR, and one of the first obstacles I wanted to add were snowman who lob snowballs at you.
However, I wanted the snowballs to:
So, if we're travelling in an arc we're obviously just doing normal projection dynamics. We're going to take the typical physicist "ignore air resistance" attitude in this case even though that's not true for most things in SRBR, because it would make for an insanely complicated problem, and I want something pretty.
If we're defining the velocity then the game will have to solve for the angle on its own. Now, because we're not using air resistance, we have linear acceleration, so we can use SUVAT equations, which you may or may not be familiar with, but they're a very useful thing to be intimately familiar with.
I'm going to briefly explain SUVAT so feel free to glaze over this part if you're already familiar with it.
If you aren’t aware, SUVAT stands for the 5 variables of linear acceleration: Displacement (from the Latin spatium), Initial velocity, Final velocity, Acceleration and Time, and there’s a set of 5 equations that go with this. Each one of them uses 4 of the 5 variables. So if you know any 3 variables and want to know a fourth, you can pick an equation and plug in the numbers to get the solution.
e.g. for
If you want to know the velocity of an object that starts moving at 3 tiles per second, after 5 seconds, given that it accelerates at 1.5 tile per second squared, you get:
Which is 10.5.
So, we only ever need 3 variables if we only want to find 1. Usually. However, we want to find the angle, so this is going to be slightly more complicated.
Now, the only equation we’re concerned with here is:
Because we know our displacement, acceleration and initial velocity, and thanks to how spacetime works, time in the x direction and time in the y direction are the same. (This is not actually true thanks to special relativity but thankfully we’re not working at relativistic speeds).
Now, displacement s and velocity u & v are both vector values, so they have a direction as well as a magnitude (which is the difference between displacement and distance).
What this means is.. we can break this into two equations. A horizontal one and a vertical one.
This is done with trigonometry. You should know trig. If you don’t, go look up SOHCAHTOA and Pythagoras’s Thereom right now and make sure you know them. You should be able to see that if you have your launch velocity along some line, if you break it down into components you get this:
Let’s consider the problem horizontally:
We don’t have air resistance, and it’s flying through the air so there’s no friction. There is nothing slowing the snowball down in the x direction, so there is no horizontal acceleration.
So let’s list our relevant variables:
(the horizontal distance)
(The x component of velocity)
(We’re just calling t t, because time is the same everywhere in our game).
So, as we know:
And therefore:
Okay, so now we know what the time is at any point. Let’s look in the important direction now: vertical.
(vertical displacement)
(gravitational acceleration, negative because it points down)
Alright, so let’s get our equation:
Okay, so now we have a conundrum. We’re trying to solve for theta, but we have a whole bunch of trigonometric functions and we need to get it on its own.
This is the point where you need to know trigonometric identities. It really helps to know these, there’s 3 I would particularly recommend knowing that tend to allow you to solve pretty much any equation analytically, but in this case we’re going to use the following:
So, we can get everything in terms of tan(x), which is exactly what we need.
And this.. is a quadratic equation. Which means if we put it equal to 0 we can get a solution. Let’s define:
To make things easier on the eyes. And let’s move everything to one side of the equals.
Now, I like to get rid of the coefficient of the τ term because that’s the type of person I am, so I’m dividing everything by .
This gives us:
If you don’t know where that gx^2 on the top came from, it’s because gx^2/gx^2 = 1, I just wanted to reduce it to one term by having a consistent denominator.
Okay so now we know the generic solution to the quadratic equation is:
(Where a is the coefficient of the τ² term, b is the coefficient of the τ term and c is the constant). So a is 1 for us. You can thank me later.
So we know that τ is equal to:
Ultimate pro tip for this step: When you divide by 2a in the quadratic formula, you can absorb the 2 into the square root, and divide everything by 4 instead, so you get something really neat. Note I also divided and multipled the middle term by g so everything has the same denominator. That way everything plugs into each other really simply. And you might notice as well, that the denominator outside the root is gx, and the denominator inside the root is g²x². In other words, we can yank that out of the square root, and end up with this:
Nice and elegant. Now, notice that this has two solutions. One will be on the "way up" and one on the way down. So if my snowman throws a snowball up at you, he could throw it such that it strikes you on its first path, or throw it super high so it goes above you and lands on you. I prefer the low route so I'm taking the minus value.
So! Code time.
//float v is predefined in the class float x = target.transform.position.x  transform.position.x; float y = target.transform.position.y  transform.position.y; float g = rigidbody2D.gravityScale * 10f; float dis = Mathf.Pow(v, 4)  2 * v * v * g * y  g * g * x * x; //If the discriminant is less than 0, that means the projectile can't reach the //target as the square root of a negative number is imaginary. //So we need to account for that. if(dis>0){ float plusminus = Mathf.Sqrt(dis); float dividend = v*v  plusminus; //For once we actually don't want atan2  it'd mess with our results. float theta = Mathf.Atan(dividend/(g*x)); //Instead we just flip the vector if the target is on the left rigidbody2D.velocity = new Vector2((x > 0 ? 1 : 1) * v * Mathf.Cos(theta), (x > 0 ? 1 : 1) * v * Mathf.Sin(theta)); } else{ //Whatever you want to do here if the target can't be reached. //You could do something cool here like an angle for an "attempted" shot. }
And there we go, we've now set our rigidbody2D to always hit a target* as long as there's nothing in the way.
In the case that the target is moving at a fixed velocity, thanks to Galilean relativity you can simply add/subtract the target's velocity to the value of v before the calculation of theta, and then revert to the original value of v for the assignment of rigidbody2D.velocity.
*NB, the larger your timestep, the larger the error, and the longer your projectile is in flight, the more the error will blow up (especially if using the Euler Method). There's nothing simple you can do about that really, but it's not been a problem in my experience for this case.
Here's what it looks like in action (click for video).
Have fun!
Originally posted at my dev blog.
Bojan Lovrovic 
15 Jul 2014 at 9:13 am PST

Things get slightly more difficult if you use air resistance force (drag) that is proportional to velocity (note that this is only a simplification of an actual physics model in which drag is proportional to squared velocity). You end up having this equation:
m*a = m*g  c*v where: m  mass of the body (scalar) a  current acceleration (vector) g  acceleration due to gravity (vector) c  some constant that affects how powerfull the drag will be (scalar) This is a simple nonhomogeneous linear secondorder differential equation and here is the solution: p(t) = c1 + c2*exp(c*t/m) + t*g*m/c Where p(t) is a position (vector) as a function of time. The only thing that is left to do is calculate c1 and c2 which are also both vectors. c2 = m*v(0)/c c1 = p(0)  c2 Where p(0) is initial position vector and v(0) is initial velocity vector. Here is the code example: //gravity float gx = 0; float gy = 9.81; float gz = 0; //mass float m = 1; //drag coefficient float c = 1; //initial velocity float v0x = 25; float v0y = 0; float v0z = 0; //initial position float p0x = 0; float p0y = 3; float p0z = 0; float c2x = m*v0x/c; float c2y = m*v0y/c; float c2z = m*v0z/c; float c1x = p0x  c2x; float c1y = p0y  c2y; float c1z = p0z  c2z; // in update method you should use something like this myObject.updatePosition( c1x + c2x*math.exp(c*gameTime/m) + gameTime*gx*m/c, c1y + c2y*math.exp(c*gameTime/m) + gameTime*gy*m/c, c1z + c2z*math.exp(c*gameTime/m) + gameTime*gz*m/c); Hope this turns out to be useful to someone :) 




ultra brite 
here is a little something I came up with years ago that still serves me well:
inline vec3 ballisticLaunchSpeed(const vec3& origin, const vec3& destination, const vec3& gravity, float duration) { return (destinationorigin)/duration(gravity*duration)/2; } useful to have an object jump from A to B in a fixed time, if you don't need a specific angle or velocity. 




David Erosa 
Great article! A few weeks ago I had the same problem (solving the angle for a ball to reach a target) but I had neither the time nor the patience to find out how to do it properly. Now I'll study your article, as I get lost from the "Solving the Quadratic" part.
Thanks for the writing! 






Jeff Postma 
This was awesome, thanks for taking the time to put this together and break down the math. Physics is awesome.


