Frame-rate independance and Mario-style jumping

Started by
23 comments, last by Aardvajk 17 years, 4 months ago
Quote:Original post by Roof Top Pew Wee
As John Bolton suggests, a modified Euler implementation will fix all of your problems (it's what I used in my platformer as well):

position += velocity * deltaTime + acceleration * (deltaTime*deltaTime)/2.0f;
velocity += acceleration * deltaTime;

That should do it for ya.


This can also be rendered as:

float old_velocity = velocity;velocity += acceleration * deltaTime;position += deltaTime * (velocity + old_velocity) / 2.0f;

Advertisement
Hello everyone, and thanks! I was just toying around with the new XNA framework and was irritated how bad my motions where.. Reading this one, I've solved all of the problems (except the one that my notebook is quite slow when it comes to rendering, thus resulting in those big motion problems) with the help of this thread, really cool.

I'm somehow ashamed that I didn't got the idea myself.. i mean, we've learned that equation in school, didn't we?

But it's all so long ago...
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

Good grief. Fair few responses here since I looked last. Thanks very much to every body. I'll try out some of those formulas tonight and see what results I get in my test application.

I agree with the poster who suggested levels shouldn't be so accurate and should have a fudge factor. I was just finding a difference of 3 pixels over just +/- 10 fps with the basic Euler, which seemed quite high.

I'll test out John Bolton and Roof Top Pew Wee's improved formulas and see if they give better accuracy.

Thanks again.
A good article on the subject.
Quote:Original post by mattdev
A good article on the subject.


That looks like a fantastic article from the brief scan I just gave it. Thanks.
Just wanted to point out that any solution that supports a variable frame rate is going to feel more sloppy to control than a fixed time step, and control is critical to platformers to the point where a good player will know exactly what frame to jump at. Once that is lost, the game controls will suffer, even if the problem is very slight. Slowdown is even worse when the timestep is variable, the tiniest lag-warp will kill and frustrate your player.

The best solution is the one that it sounds like you have already implemented: keep your gameplay updates consistent at 30/60 fps.

Check out my new game Smash and Dash at:

http://www.smashanddashgame.com/

Quote:Original post by JBourrie
Just wanted to point out that any solution that supports a variable frame rate is going to feel more sloppy to control than a fixed time step, and control is critical to platformers to the point where a good player will know exactly what frame to jump at. Once that is lost, the game controls will suffer, even if the problem is very slight. Slowdown is even worse when the timestep is variable, the tiniest lag-warp will kill and frustrate your player.

The best solution is the one that it sounds like you have already implemented: keep your gameplay updates consistent at 30/60 fps.


Yep. I'm becoming inclined to agree. It would also vastly simplify the majority of the rest of the game, since motion and animation timings would no longer need to be modulated by the time delta.

The article mattdev posted looks like exactly the answer. Thanks to everyone for yet another informative and interesting set of responses.

[EDIT]

Based on that article, fixed timestep seems to work like a charm, as per the figures below. The first figure is the highest pixel attained and the second is the proportion of a second (in actual time) the entire jump took to execute. The lines represent the loop running with no Sleep() then with Sleep()s of 10, 20, 30, 40 and 50:

305, 0.664305, 0.662305, 0.656305, 0.666305, 0.681305, 0.664


Then the result with no Sleep(), but the time each frame divided by two (to simulate a 120 fps set up):

305, 0.664


Fantastic results and exactly what I wanted.

[Edited by - EasilyConfused on November 28, 2006 1:28:28 PM]
An hybrid solution that hasn't been mentioned yet and addresses JBourrie's concern with animation timing is updating the model at a fixed rate and drawing two kinds of frames: the important ones, one per model update, in which everything moves, and extra frames in which the sprites and other critical graphics remain still (to allow the player to count frames) while only elements whose movement is unimportant, like subtly animated textures or status text and icons, are animated and look as smooth as possible.

Omae Wa Mou Shindeiru

I really recommend that you use fixed timestep game logic. This will make your game deterministic.

Of course the frame rate may vary, therefore to achieve optimum smoothness, you should interpolate between the frames.

You can interpolate an animation variable by doing the weighted average of its current value and its previous timestep value, weighted by the amount of time which has passed since the last timestep.

Effectively, the animation state will always be exactly 1 tick behind the "real" physics. This is not a problem as the player probably won't notice this (set physics ticks to 1/20 s or faster).

I've implemented this and it really is the nicest way of doing it.

The trouble with variable-timestep is that you have to take it into account for all your timers etc, in the game as well as movement, rotation, animation etc, and it gets a little bit error prone, particularly when using floating point.

Mark
Got a new problem now though.

I've implemented fixed rate physics with independant rate rendering. Just a block bouncing round the screen.

It jitters. It jitters real bad.

markr - could you give me a bit more detail on this stuff about interpolating based on an average? I'm not sure what you mean exactly.

Does tihs mean calculating the actual position when I do the physics, then working out an interpolated position to actually draw an object when I render?

Wouldn't this mean that every object has to effectively carry two states around with it - its previous and its current?

[EDIT]
My test app is here.

My main loop code looks like this:

CResult CEngine::Cycle(){	static float Accumulator=0;	Accumulator+=Timer.Get(); // returns time since last called as proportion of second from 0.0f to 1.0f		while(Accumulator>=PhysicsDelta)		{		CResult R=CurrentMode()->Physics(); if(R!=rsOk) return R;		Accumulator-=PhysicsDelta;		}				Dev.BeginScene();	CResult R=CurrentMode()->Render(Dev,Qu); if(R!=rsOk) return R;	Dev.EndScene();	Dev.Present();	return rsOk;}


If anyone has time to download the exe, you notice every two or three seconds the block jitters really badly. I reckon that would look awful if it was a whole screen of a moving map and various objects.

Any ideas would be appreciated.

[EDIT]

I've just tried storing the old X and Y of the Block in the physics function before update, then passing the remainder of the accumulator into the Render function and doing:

CResult CGameMode::Render(float Time,CDevice &Dev,CQuadBuffer &Qu){	float Alpha=Time/PhysicsDelta;	float x=X*Alpha+Ox*(1.0f-Alpha);	float y=Y*Alpha+Oy*(1.0f-Alpha);	Dev.Clear(Col);	Qu.Begin();	Qu.Add(x,y,40,40,D3DFLOATRECT(),D3DCOLOR_ARGB(255,128,0,0));	Qu.End();		Dev.Draw(Qu);	return rsOk;}


That does actually make it a hell of a lot smoother, although I have no idea how this would apply to velocity varibles. Would I actually need to perform any alpha blending of velocities, or would it just literally be the positions like above?

Blimey. Surely you can write a Mario style platformer on a modern PC without all this complication?

[EDIT]

It would appear that velocity calculations do not need to be affected, just purely the position you render at each frame. Makes sense I guess.

So I guess I need to come up with a way of wrapping all this horrible maths into an object that all moving objects can contain. Might work.

[Edited by - EasilyConfused on November 29, 2006 2:42:58 PM]

This topic is closed to new replies.

Advertisement