2
\$\begingroup\$

I am working on a physics engine that uses basic Euler integration to compute forces. So, here is the thing:

function applyForce (rigidbody, force) { 
    rigidbody.forces.add(force);
}

function computeAcceleration (rigidbody) {
    rigidbody.acceleration = rigidbody.forces / mass; 
    rigidbody.velocity = rigidbody.velocity + rigidbody.acceleration * time.deltaTime;
}

// The forces are reset after each gameloop

So now imagine I want to apply a force to jump, I will use applyForce at the moment the player presses the jump button.

But: What happens is that the amount of movement depends on the gameloop speed, since the force is applied for a single frame. I feel like I missed something about how you should use forces, but I don't see how I should manage it properly.

In which cases should we use a force, considering this deltaTime issue? And also, what should I use instead?

\$\endgroup\$
3
\$\begingroup\$

It’s because, in general, jumping involves applying an impulse instead of a force.

You apply forces when the interaction is expected to last for at least some time. For instance, gravity is a force: it lasts more or less forever. Pushing a door is applying a force, too: you keep pushing while the door opens.

You apply impulses when the interaction should be more or less immediate. Jumping, or hitting a ball with a bat: this involves impulses. Everything happens in a very short timespan.

This is how you could modify your code in order to apply impulses in addition to forces:

function applyForce (rigidbody, force) { 
    rigidbody.forces.add(force); // This is still valid, but not for jumping
}

function applyImpulse (rigidbody, impulse) { 
    rigidbody.impulse.add(impulse);
}

function computeAcceleration (rigidbody) {
    rigidbody.acceleration = rigidbody.forces / mass; // This is still valid
    rigidbody.velocity = rigidbody.velocity
                       + rigidbody.impulses / mass
                       + rigidbody.acceleration * time.deltaTime;
}

Of course, as suggested by MickLH, you should probably use Verlet integration instead of Euler (by averaging the previous velocity and the new velocity), too. But the main problem you have is forces vs. impulses.

\$\endgroup\$
  • \$\begingroup\$ Impulses do seem like the correct way to go, although your example seems weird to me. Shouldn't the impulse just add to the current velocity? I tried this way but it gives results depending on time. What I did is just when an impulse is applied, add it to the velocity \$\endgroup\$ – Malharhak Jan 20 '14 at 19:01
  • 1
    \$\begingroup\$ Oh, you’re absolutely right. I wrote * deltaTime instead of / deltaTime, sorry for the confusion. Adding to the velocity is correct. \$\endgroup\$ – sam hocevar Jan 20 '14 at 19:36
  • \$\begingroup\$ Yep. And you added the mass, I initially forgot to take it into account in my original version of the impulses. Anyway this one is good and everything works well now. Thanks! \$\endgroup\$ – Malharhak Jan 20 '14 at 19:53
2
\$\begingroup\$

The fix is simple, integrate position in the middle of integrating velocity. (As in, add half of the force, update, then add the other half.)

Here is a more in-depth explanation: http://www.niksula.hut.fi/~hkankaan/Homepages/gravity.html

\$\endgroup\$
  • \$\begingroup\$ Oh that's a great answer thanks! I'll implement this now to see if it's better. \$\endgroup\$ – Malharhak Jan 20 '14 at 17:51
  • 1
    \$\begingroup\$ This fix is really good. It have allowed to me that I wrote a precise prediction for the jumps of my characters. \$\endgroup\$ – Emir Lima Jan 20 '14 at 20:07
  • \$\begingroup\$ The link is dead. Fix it . \$\endgroup\$ – jgallant Mar 1 at 14:31

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.