# Making AI jump on a spot effectively

How to calculate, in 3D environment, the closest point, from which an AI character can jump onto a platform?

Setup

I have an initial velocity V(Vx,Vy,VZ) and a spot where the character stands still at S(Sx,Sy,Sz). What I'm trying to achieve is a successful jump on a spot E(Ex,Ey,Ez) where you have clicked on(only lower or higher spot, because I've in place a simple steering behavior for even terrains). There are no obstacles around.

I've implemented a formula that can make him jump in a precise way on a spot but you need to declare an angle: the problem arise when the selected spot is straight above your head. It' pretty lame that the char hang there and can reach a thing that is 1cm above is head. I'll share the code I'm using:

    Vector3 dir = target - transform.position;  // get target direction
float h = dir.y;  // get height difference
dir.y = 0;  // retain only the horizontal direction
float dist = dir.magnitude ;  // get horizontal distance
float a = angle * Mathf.Deg2Rad;  // convert angle to radians
dir.y = dist * Mathf.Tan(a);  // set dir to the elevation angle
dist += h / Mathf.Tan(a);  // correct for small height differences
// calculate the velocity magnitude
float vel = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 *a));
return vel * dir.normalized;


Ended up using the lowest angle (20 degree) and checking for collision on the trajectory. If found any increase the angle. Here some code (to improve the code maybe must stop the check at the highest point of the curve):

Vector3 BallisticVel(Vector3 target, float angle)
{
Vector3 dir = target - transform.position;  // get target direction
float h = dir.y;  // get height difference
dir.y = 0;  // retain only the horizontal direction
float dist = dir.magnitude ;  // get horizontal distance
float a = angle * Mathf.Deg2Rad;  // convert angle to radians
dir.y = dist * Mathf.Tan(a);  // set dir to the elevation angle
dist += h / Mathf.Tan(a);  // correct for small height differences
// calculate the velocity magnitude
float vel = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
return vel * dir.normalized;
}

Vector3 TrajectoryPoint(Vector3 startingPosition, Vector3 startingVelocity, float n )
{
float t = 1/60 ; // seconds per time step
Vector3 stepVelocity = t * startingVelocity; // m/s
Vector3 stepGravity = t * t * Physics.gravity; // m/s/s

return startingPosition + n * stepVelocity + 0.5f * (n*n+n) * stepGravity;
}

bool CheckTrajectory(Vector3 startingPosition,Vector3 target, float angle_jump)
{
Debug.Log("checking");
if(angle_jump < 80f)
{
Debug.Log("if");

Vector3 startingVelocity = BallisticVel(target, angle_jump);

for (int i = 0; i < 180; i++)
{
//Debug.Log(i);
Vector3 trajectoryPosition = TrajectoryPoint( startingPosition, startingVelocity, i );

if(Physics.Raycast(trajectoryPosition,Vector3.forward,safeDistance))
{
angle_jump += 10;
break; // restart loop with the new angle
}
else
continue;

}

return true;
JumpVelocity = BallisticVel(target, angle_jump);
}

return false;
}

• Hi, the question lacks detail about the level model. Are there any obstacles? Is the terrain smooth? What is the condition for making the jump? Some of us may have no idea what you are talking about and if you explain it better, we could help. – AturSams Sep 29 '12 at 21:39
• I actually wouldn't understand this after this question was edited :D. If my answer really solves your problem, then I'll edit the question to make more sense. – Markus von Broady Sep 30 '12 at 21:27

## 1 Answer

Your question is still missing the physics of your jumps. Does player's avatar accelerate when in air? Do jump physics simulate gravity well? That is the avatar's initial Vy is decelerated by 9.81 m/s every second? Still, I will present you a way how easily solve this mathematic problem.

1. Let's start with representing our problem. In this case we can do this in 2D! 2. Now let's assume a few things:
• we're using real physics (considering gravity, but not considering air friction etc.)
• you can still steer while in air, and therefore, you can easily avoid such situation: • this means we should only care about being near enough to be able to jump onto a platform; we want to find an outermost distance from our target, that we can jump through to it.
3. Let's analyze what happens, when we jump:
• we get initial speed Vy
• gravity makes this speed decrease by g m/s every second
• at some moment we reach the highest point and start to fall
• speed increases by g m/s until we fall on something
• all this time we're moving 'forward' by our initial velocity Vx
• moreover, all this time we're accelerating (because if we want to reach the platform from the furthest place possible, we need to hold UP key), increasing our Vx
• what we want to know is, how long have we been in air, and therefore, how much could we travel.
4. Time of the jump
• here's a nice article about jump math: How to Calculate the Jump Height From Acceleration
• time to reach top of our jump is: t = Vy/g (it's obvious, we need to lose our vertical speed completely)
• height of our jump is: h = Vyt + (gt²)/2 WARNING: this formula assumes your "g" is a negative number. if not, change the formula to: h = Vyt - (gt²)/2
• formula for time we will fall from there to the platform is: where d is h - platform.height (taken from Wikipedia:Equations for a falling body)
• sum both t, and we get a time of our jump.
5. Now we need to know how far the player will move during the jump. If he doesn't accelerate, this will be distance = Vx*t, but he does. So there's formula for that too: d = Vt + (1/2)at²
6. We found the max distance of the jump! You need to get to the platform to that distance or closer to be able to jump onto it - good luck!

And here's code:

var vertical_distance:Number = platform.height - ground.height;
var Vh:Number = Math.sqrt ( Vx*Vx + Vz*Vz );
var time_to_top:Number = Vy/GRAVITY;
var jump_height:Number = Vy*time_to_top - GRAVITY*time_to_top*time_to_top/2
if ( jump_height >= vertical_distance ) {
var falling_distance:Number = jump_height - vertical_distance;
var time_to_fall:Number = Math.sqrt ( 2 * falling_distance / GRAVITY );
var jump_time:Number = time_to_top + time_to_fall;
var jump_length = Vh*jump_time + .5 * ACCELERATION * jump_time * jump_time;
return jump_length;
} else throw error or something


Check out The Jumping Squareman minigame!

• Sir this is the most complete explanation I've got so far, I want to deeply thank you. Will try to implement this and report on this page if it works. Thanks again P.s. Yes the physic is implemented well and we use the earth gravity. . . – Pasquale Sada Sep 30 '12 at 21:03
• Added the code, and removed the circle idea, as what you really want is to move to a platform closer then jump_length distance from it. – Markus von Broady Sep 30 '12 at 21:25
• I was messing with the circle idea and there where some problems. Will try out this and let you know! thanks :D – Pasquale Sada Oct 1 '12 at 1:06
• before trying to find best place to jump onto a platform (that is a 2D rectangle) try this code with a point (where circle would work). If the solution works, I will add how to apply it to the rectangle. – Markus von Broady Oct 1 '12 at 6:49
• After few tries I ended up using raycast(very expensive but more reliable). The problem is that now must check some point on the trajectory for hits. It's better not try all points, 10 point well spaced are enough. Code still not working. . . – Pasquale Sada Oct 1 '12 at 11:17