2
\$\begingroup\$

I'm developing a 2d fighting game, using time steps based on frames ie, each call to Update() of the game represents a frame so, no variable time at all.

My jump physics code doesn't need to consider delta time, since each Update() corresponds exactly to the next frame step. Here how it looks:

double gravity = 0.78;
double initialImpulse = -17.5;

Vector2 actualPosition;
double actualVerticalVelocity;

InitializeJump() {
    actualVerticalVelocity = initialImpulse;
}

Update() {
    actualPosition.Y += actualVerticalVelocity;

    actualVerticalVelocity += gravity;
}

It works great and results in a smooth arc. However, it's hard to determine the values for "gravity" and "initialImpulse" that will generate the jump that I want.

Do you know if it's possible to calculate the "gravity" and "initialImpulse", if the only known variable is the "desired time to reach max height" (in frames) and "desired max height"?

This question should lead to the answer I'm looking for, but its current answer does not fit my needs.

UPDATE:

As @MickLH figured me out, I was using an inefficient Euler integration. Here is the correct Update() code:

Update() {
    actualVerticalVelocity += gravity / 2;

    actualPosition.Y += actualVerticalVelocity;

    actualVerticalVelocity += gravity / 2;
}

Only the very first step of the Update() will change and will move the object by initialVelocity plus the half of the gravity, instead of the full gravity. Each step after the first will add the full gravity to the current velocity.

\$\endgroup\$
8
\$\begingroup\$

Short answer:

gravity = -2*desiredMaxHeight/(desiredTimeInTicks*desiredTimeInTicks)
impulse = 2*desiredMaxHeight/desiredTimeInTicks

Long answer: (pre-calculus required)

Define your jump function which is a simple integral over time:

  • yielding:

Now to find the peak of this function we solve for where the derivative equals zero:

  • simplified:

We have built a system of equations which:

  1. represent the relationship of t (time), h (height), impulse, and gravity
  2. constrain the height to its global maxima

The solution to this system yields the the variables you are interested in:

\$\endgroup\$
  • \$\begingroup\$ If I wish that in the 4th frame, the object reachs its higher height (2 pixels), the formulas that you guys presented shows Gravity = "-0.25" and InitialImpulse = "1". However, if I put that values in my jump code, that is the frame results: Frame 0: (Position.Y = 0) (Velocity = 0) | Frame 1: (P.Y = 1) (V = 1) | Frame 2: (P.Y = 1.75) (V = 0.75) | Frame 3: (P.Y = 2.25) (V = 0.50) | Frame 4: (P.Y = 2.50) (V = 0.25) | Frame 5: (P.Y = 2.50) (V = 0) Note that in the 4th frame the position isn't 2 like I wanted, instead is 2.5. I really need a precise formula. \$\endgroup\$ – Emir Lima Jan 8 '14 at 20:55
  • 2
    \$\begingroup\$ I'm afraid that's the "wrong the execution of the physics" you were afraid of... It's because you are using naive Euler integration. Read this article for more info and a quick fix: niksula.hut.fi/~hkankaan/Homepages/gravity.html \$\endgroup\$ – MickLH Jan 9 '14 at 1:32
  • \$\begingroup\$ Man, I don't believe! That's it!! I was really using a naive Euler integration... :P Applying that fix, the step by step results in precise values. Thank you very much! Now, I can configure my magic numbers in a more intuitive way! \$\endgroup\$ – Emir Lima Jan 9 '14 at 3:33
1
\$\begingroup\$

Like the work you've already done to get your character jumping and falling, you can derive gravity and initialImpulse using basic physics equations and algebra. First, the equations:

y1 = y0 + initialImpulse * t1 + 1/2 * gravity * t1 * t1
v1 = initialImpulse + gravity * t1

We'll try to find initialImpulse and gravity based on what we know. What we know is:

  • y0 is 0, since the character hasn't left the ground at time 0
  • y1 is your desired jump height, which I'll call 'h'
  • v1 is 0, since the character has to stop moving up when they reach height h
  • t1 is your desired jump-up time, which I'll call 't'

Plug these known values into the equations:

1. h = 0 + initialImpulse * t + 1/2 * gravity * t * t
2. 0 = initialImpulse + gravity * t

Solve equation 2 for initialImpulse:

3. initialImpulse = -gravity * t

...then replace initialImpulse in 1 with the right-hand side of 3:

4. h = -gravity * t * t + 1/2 * gravity * t * t

Solve for gravity:

5. h = -1/2 * gravity * t * t
6. gravity = -2 * h / (t * t)

That's one part down. Find the value of initialImpulse by replacing gravity in 3 with the right-hand side from 6:

7. initialImpulse = -(-2 * h / (t * t)) * t
8. initialImpulse = 2 * h / t

Side note: Check out the right-hand side at the end there, because it's useful in more than just this situation. It shows that the average velocity you wanted (to move upward to height 'h' over time 't') is half of the starting velocity. The general rule would be that a character who changes velocity linearly from v0 to v1 over time t will move at an average velocity of (v0 + v1) / 2 and travel t * (v0 + v1) / 2.

With that in your pocket, you could solve this same problem a little bit more concisely:

average_speed = initialImpulse / 2 = h / t
initialImpulse = 2 * h / t

gravity * t + initialImpulse = 0
gravity = -initialImpulse / t
gravity = -2 * h / (t * t)
\$\endgroup\$
  • \$\begingroup\$ I am really confused! Every formula that I test never results in precise values. I am starting to think that my algorithm is doing wrong the execution of the physics. \$\endgroup\$ – Emir Lima Jan 8 '14 at 23:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.