Predicting the landing point of a ball
Recently I've gotten into answering questions on Stack Overflow, and sometimes I have a lot of fun answering a question.
For instance, the problem of naturally moving a computer player in a tennis game is a fairly interesting application of the kinematic equations for single particles.
This is fairly basic high school physics, but for some programmers this sort of math can be intimidating, so I'd like to try to explain this and make it easier!
First, let's outline the problem: You are making a tennis game and want to create a reasonably okay "AI" opponent. If you simply have the opponent try to position itself under the ball at all times, it might not be able to keep up very well. Ideally, you'd like to have the opponent look for where the ball will land, like a human player naturally would. But how can you program the opponent to know this information?
Solving this can be done in two steps:
Figure out when the ball will land
Figure out where the ball will be at that landing time
Figuring out when the ball will land is pretty straightforward, as it can be directly calculated from the distance between the ball and the ground, its current falling speed, and the strength of gravity.
For simplicity's sake, I'll be assuming that gravity is entirely vertical and the ground is located at Y=0.
The kinematic equations tell us that an object moving at speed V, and changing its speed at rate A, for duration T, will move a distance of V times T plus one half of A times T-squared.
We already know the distance we're covering, since it is the distance from the ball to the ground. We also know from our game settings the acceleration rate of gravity, and the current falling speed of the ball. The rest is a bit of algebra, which I've already plugged into Wolfram Alpha for you:
If you're programming this in C# for Unity3D, it would look like this:
float v = rigidbody.velocity.y;
float a = Physics.gravity.y;
float d = transform.position.y * -1;
float t = - (Mathf.Sqrt(2 * a * d + Mathf.Pow(v, 2)) + v) / a;
Now that we know when the ball will hit the ground, what do we do with this? We already know the Y-coordinate of the landing position... it's zero! What we need to do now is figure out the two lateral, or non-vertical, parts of the landing point.
Since gravity is entirely vertical, we know that the lateral part of the ball's speed will remain constant until it hits something. This makes it easy to predict the lateral position of the ball, since we know the current speed and the time until landing!
If we take the current speed of the ball, multiply that by the time until landing, and add it to the ball's current position, we'll know the lateral parts of the landing point.
In Unity, this part of the code would look like
impactPos = transform.position;
impactPos += rigidbody.velocity * t;
impactPos.y = 0;
In the example code, impactPos is a public Vector3 variable of the prediction script attached to the ball. If you wanted to use this to control a computer player, you would write a script that accesses this impactPos variable and moves towards that position.
Since the predictor is attached to the ball, the control component on the "catcher" character would be set up somewhat like this:
In this code, I've added an if-statement that checks whether the ball is on the same side of the "net" as the character, where I'm using the Z=0 line as the net. This makes it so that the character only attempts to catch the ball if isn't already headed towards the opponent's court.
Using Unity's built-in physics without any drag on the ball and bounciness set to 1 for all colliders, pitting two of these "catchers" against each other results in an automatic approximation of a two-player volleyball duel.
Since I've already given a screengrab of the catcher code, here's the code for the landing predictor! As you can see, it's actually pretty simple.