Velocity Verlet Integration

Started by
7 comments, last by Fezziwig 11 years, 1 month ago

In a platformer game I'm making I'm going to use Verlet Integration, so in the player calculate function. At the moment I have it set up like this:


//// Velocity Verlet integration
lastAcceleration = avgAcceleration;
nextPosition.x += velocity.x * delta + ( 0.5 * lastAcceleration.x * delta * delta);
nextPosition.y += velocity.y * delta + ( 0.5 * lastAcceleration.y * delta * delta);


// Collision Detection - I wont put this in the sample code

// Move to new coords
position = nextPosition;

// Initialise Acceleration
newAcceleration.x = 0.0;
newAcceleration.y = 0.0;

// Gravity
if (!yCollision)
{
	double force = mass * -0.0001;
	newAcceleration.y = force * delta / mass;
}

// Air Resistance
velocity.x -= velocity.x * 0.01 * delta;

// Controls
if (key['W'] && yCollision)
{
	double force = mass * 0.05;
	newAcceleration.y = force / mass;
}

if (key['A'])
{
	double force = mass * -0.003;
	newAcceleration.x += force / mass;
	facingLeft = true;
}

if (key['D'])
{
	double force = mass * 0.003;
	newAcceleration.x += force / mass;
	facingLeft = false;
}

avgAcceleration.x = (lastAcceleration.x + newAcceleration.x) / 2.0;
avgAcceleration.y = (lastAcceleration.y + newAcceleration.y) / 2.0;
velocity.x += avgAcceleration.x * delta;
velocity.y += avgAcceleration.y * delta;
//// Velocity Verlet integration

However, The jumping still seems to be majorly affected by the frame rate. Have I set up the integration properly?

Advertisement

There are a couple of things that I would suggest to try. The first is to simplify the solver -- since it is not working the way you expect -- by removing the air resistance (my guess is that you're going to end up getting rid of it eventually anyway). Secondly, you don't want to store the acceleration over successive iterations. Gravity should be a constant source of acceleration and the acceleration due to, say, jumping should only be applied once.

-Josh

--www.physicaluncertainty.com
--linkedin
--irc.freenode.net#gdnet

I need the air resistance to slow the player down, else there is noting to stop it. Isn't the gravity constant in this? And technically The jump acceleration is only applied one, as after it's accelerated into the air once, yCollision is no longer true and it no longer accelerates.

I need the air resistance to slow the player down, else there is noting to stop it. Isn't the gravity constant in this? And technically The jump acceleration is only applied one, as after it's accelerated into the air once, yCollision is no longer true and it no longer accelerates.

In a platformer, I don't think you should need air resistance to slow you down. If you find it is necessary you are probably doing something wrong. This is part of the reason why you should remove it because it could be masking a larger problem with the way you are handling acceleration. You can always put it back in, but I would remove it to debug the problem.

As I said, you should not be storing the acceleration over successive iterations. Remove the averaging. The acceleration should be zero at the beginning of the iteration. The "memory" of the effect of the acceleration will naturally persist through the velocity.

-Josh

--www.physicaluncertainty.com
--linkedin
--irc.freenode.net#gdnet

Are you suggesting I get rid of the Verlet integration altogether?

Are you suggesting I get rid of the Verlet integration altogether?

No, what you are doing is not verlet integration.

[edit] I shouldn't say that, what I should say is that explicitly retaining the acceleration between iterations is not something you should be doing with any of the common integration schemes.

[edit + apology] Apparently I have not looked carefully enough at velocity verlet in a while and I am totally wrong. I see how it is retaining the acceleration from the previous time step, so clearly I need to familiarize myself with this material again. However, there is a difference between using the acceleration from the previous timestep and averaging the acceleration. When you average the acceleration you are essentially using information from all previous timesteps and I believe that is incorrect.

--www.physicaluncertainty.com
--linkedin
--irc.freenode.net#gdnet

When you average the acceleration you are essentially using information from all previous timesteps and I believe that is incorrect.

I don't understand. newAcceleration is the thing that's just been worked out, by my math, making half of the average from previous timesteps and half based on new calculations.

When you average the acceleration you are essentially using information from all previous timesteps and I believe that is incorrect.

I don't understand. newAcceleration is the thing that's just been worked out, by my math, making half of the average from previous timesteps and half based on new calculations.

Right, but it's from *all* previous timesteps and Verlet uses the acceleration from only the current and the previous timestep. The result will be that the effect of a force will persist for longer.

Let me put it into a mathematical form. If a_n is the acceleration at the nth timestep and there is only an effect due to gravity what you get is,

a(n) = (a(n-1) - g) / 2

Now suppose on the first iteration you have a force due to a jump, j, so the force is the sum of the jump and gravity. The acceleration of the next timestep will be

a(1) = (j - g) / 2

and after that, assuming only gravity each iteration,

a(2) = (j / 2 - g) / 2

a(3) = (j / 4 - g) / 2

a(4) = (j / 8 - g) / 2

etc, or,

a(n) = (j / 2^n - g) / 2

The effect of the jump on the first iteration will get become smaller and smaller each iteration, but it will continue to be present. And this is not what you want in the acceleration. Also, this simply adds the accelerations from different iterations without taking into account the timestep; If your delta is frame-rate dependent, then the situation becomes even messier. In general, if your are going to use multistep integration methods you should make sure that you are using a constant timestep.

If you want to allow delta to vary I would suggest you use something like semi-implicit Euler. Otherwise you are going to have to explicitly store the previous acceleration rather than the average to use velocity verlet.

-Josh

--www.physicaluncertainty.com
--linkedin
--irc.freenode.net#gdnet

Thanks, Josh.

After taking into account what you've said I seemed to have fixed the problem. :)

I have redesigned the system so it's much simpler but still uses Velocity Verlet integration and is frame rate independent.

The thing I missed with jumping is that because the force will be affected by the time delta but only for one frame, I need to divide the jumping force by the time delta.

-Rowan

This topic is closed to new replies.

Advertisement