[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Framerate Normalizer



My high-level advice is that the approach you are trying to use to achieving frame-rate independence is a math heavy and complex path to getting right, and the issue you are seeing here is just the first of many like it (and some worse). There is a much simpler approach, where all your simulation update code doesn't care at all about frame rate or time elapsed, but instead you call your simulation update routine the right amount of times for how much time has elapsed, and make up for the time lost by extra simulation updates by doing fewer draws.

--

anyways, to answer your question - the reason the behavior of the simulation doesn't scale with different framerates is because basically you are simulating non-linear equations with discrete numerical integration, and the method you are using for it (the Euler method) introduces error with a strong bias in one direction proportional to the size of your timestep (basically slower framerates or larger integration timesteps tend to underestimate the non-linear effects, i.e. slower framerate means the thrust has less effect in a way that accumulates over time).

in other words, you are trying to calculate motion that could explicitly be described like this:
   vel(time) = initial_vel + acceleration*time
   pos(time) = initial_pos + initial_vel*time + .5*acceleration*(time*time)
implicitly by repeated applications of:
   vel = vel  + acceleration*time_delta
   pos = pos + vel*time_delta
and basically n repeated applications of the lower math gives a different result to applying the upper math with time = n*time_delta. In particular the non-linear pos has a different result (while the linear vel would be the same in both cases)

If you want to read some of the huge body of stuff people have written and researched on the topic, you want to read up on "Euler Integration", "Euler Method" or "numerical integration", but this Wikipedia article should be a good start:
http://en.wikipedia.org/wiki/Euler_method

While you could try to use much better integration methods (like Runge-Kutta or something like that) which would let you support more widely varying timesteps with much less noticeable error, that kind of stuff is much harder to grok and use - especially when you start putting in more things to affect motion, like grappples or boosters, etc. etc.

Another possible solution that will work for things with very simple motion (like say this one object only moves based on one single acceleration - like either gravity or user control in space) is to write explicit equations for motion based on time to do the integration
What I mean is you could use the:
  pos(time) = initial_pos + initial_vel*time + .5*acceleration*(time*time)
equation, as long as it's sufficient to describe how your object behaves, and that approach will be very stable for differently sized integration steps.


On Sat, May 10, 2008 at 8:49 AM, Ian Mallett <geometrian@xxxxxxxxx> wrote:
Hello,
I have a game, written in pygame, but it now needs to support more framerates.
The movements of objects need to be at the same speed, regardless of the framerate.
Here is an old line:

self.thrust = 0.0075

Here is the new line.  The game was developed on my computer at 198 fps (IdealFPS), but now needs to be scaled to a lower one for use on alternate computers (TargetFPS).  The theory here is to multiply this rate by IdealFPS to give the distance moved in one second, then divide this difference by the number of frames in second there will really be. (TargetFPS).

self.thrust = (0.0075*IdealFPS)/TargetFPS

Unfortunately, this doesn't work--the movement doesn't scale properly.  Any ideas why?
Thanks,
Ian