Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm utilising some of NeHe's spring code, and after getting some pretty weird results I eventually realised the source of my error - my "dt" value in my Update function; the value that everything is multiplied against to speed up/slow down the calculations, hopefully based on frame rate. For example:

public void Update(GameTime gt) {
   float dt = gt.ElapsedGameTime.Milliseconds / 160.0f;
   velocity += (force / mass) * dt;
   position += velocity * dt;
}

160.0f seems to work pretty well for the player's update function, but for my spring simulation I need a value of about 3000, or I end up with my springs located at (NaN,NaN) pretty much instantly.

Why do bad values for this cause everything to go so crazy? I thought it would just slow down or speed up my simulation but it seems to cause some weird cascading failure.

Edit: Sorry, forgot to link to NeHe's post on this: http://nehe.gamedev.net/tutorial/introduction_to_physical_simulations/18005/

share|improve this question
1  
There is not nearly enough information here to provide a useful answer. What is GameTime? What values are getting passed in for dt (e.g., are they sane values)? Why are you using milliseconds instead of seconds, and what are the 160 or 3000 values supposed to be doing? Where are force and mass calculated? A result of NaN could be a few different things, but nothing in that code looks suspicious. –  Sean Middleditch Apr 20 '12 at 8:50
    
Sorry, this is XNA. GameTime is the construct that XNA uses to store stuff like total time elapsed and time elapsed since last tick. I'll upload my code so this seems clearer... hold on a sec. –  Crummy Apr 20 '12 at 9:17
    
XNA project in VS2010 here: dl.dropbox.com/u/695255/Grapple.zip –  Crummy Apr 20 '12 at 9:23
    
Like @seanmiddleditch pointed out, using milliseconds is a BAD idea. first of all, if you use springs with Explicit Euler, a set of values for the stiffness constant: Kmax = 300 and Dtmax = 0.005. Usually playing with values higher than these yields a disastrous explosion of particles :). Do switch that integration method, preferably to Implicit Euler.. or at least a Verlet one. –  teodron Apr 20 '12 at 9:26
    
Where does that division by 160.0f come from? Usually you'll want to have a dt value in seconds.. so it should be gt.ElapsedGameTime.Milliseconds * 0.001f –  bummzack Apr 20 '12 at 9:50

4 Answers 4

When you do position += velocity * dt you use the new value of velocity while a more accurate calculation should be using the average value for the whole elapsed frame duration. See this article I wrote about how this affects trajectory computation.

In your specific case, if force is a constant, using Verlet integration will give you the exact trajectory whatever the framerate. If Verlet integration is still not enough, because for instance you introduce friction, you can use a higher order integration method such as 4th order Runge-Kutta.

share|improve this answer
    
Force is a constant; it's basically the total of all the forces that act on an Entity between frames. I've updated my Update function but I still get an "exploding" spring. Am I missing something? public virtual void Update(GameTime gt) { float dt = (float)gt.ElapsedGameTime.TotalMilliseconds / 160.0f; Vector2 oldVelocity = velocity; velocity += (force / mass) * dt; position += (oldVelocity + velocity) * 0.5f * dt; } –  Crummy Apr 20 '12 at 10:12
    
Well if force changes at each frame it's no longer a constant :-) I believe you are experiencing instability because force depends on the updated velocities of other entities. You could try to reduce dt in the physics step by performing several iterations of the whole physics code (including entity updates) during a single frame. –  Sam Hocevar Apr 20 '12 at 10:25
    
hey @Sam, very glad I read that article. I came across the same issue here. Basicallly what I did was position += velocity * dt + acceleration * 0.5 * dt * dt; velocity += acceleration * dt; which is what you explain in your article. Its great to see someone bringing back some sanity into this issue, as I came across a lot of people too, who just repeated that flawed integration steps they read in the internet like a mantra without really thinking about it. So thanks for this :) –  Maik Semder Apr 20 '12 at 19:40

I think you are using gt.ElapsedGameTime.Milliseconds then you should be using gt.ElapsedGameTime.TotalMilliseconds. Not sure if that have some influence here, but it's a potential bug.

To increase precision (if that is the problem) you could switch to ElapsedGameTime.Ticks which is 100-ns intervals, and to double for fp intermediate calculations and see if it helps.

share|improve this answer
    
+1 for first paragraph. –  George Duckett Apr 20 '12 at 10:08

Well, that's Explicit Euler Integration, the easiest and dumbest integrator ever. It's prone to explode your simulation if Dt is either variable or large. What you could do is to switch to another one:

Verlet/Velocity Verlet

Midpoint Euler http://en.wikipedia.org/wiki/Semi-implicit_Euler_method

Implicit Euler http://www.physics.udel.edu/~jim/Ordinary%20Differential%20Equations/The%20Implicit%20Euler%20Method.pdf

Predictor Corrector methods

Runge Kutta.

Why use them (another gamedev post) These are a bit better, but not as easy to implement. You also might want to look at adaptive timestep methods.. which are quite related to your problem (e.g. variable frame-rate might induce jittery simulations).

share|improve this answer

I believe that your timestep should be calulcated as:

float dt = gt.ElapsedGameTime.Milliseconds / 1000.0f;

Since you want dt to be the delta time in seconds (so a dt of 1.0 would mean that 1 second passed).

If that doesn't work, then it's likely that the timer you are using to calculate ElapsedGameTime isn't accurate enough (a common problem with millisecond timers on Windows, which has a resolution of 16ms).

If the value of gt.ElapsedGameTime.Milliseconds is constantly 0 or 16 then you need a more precise timer.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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