Re: [pygame] Framerate Normalizer
I think I understand what you are saying, if I go with the fixed-time-steps method: I remove all 'delta's from my math, and I save alot of headaches. I instead call the physics update() more or less depending on the framerate? I need some clarification on the pseudo code: I put a couple of questions in the code: # (1) Is this the right way to implement the const-time-step? / what's wrong? # (2) Does this location of .time_left matter? ( ie: right after .draw() vs. right before first call of .update() vs right after Clock.tick() ? ) # (3) On howto make up time: Thanks for any fixes: # pseudo.py class Game(): """pseudo-code, my attempt at constant-time-steps updates""" # ... def needToDoAnotherUpdate(self): """My guess on what I need to calculate""" # .time_left = time since last draw() # .time_adjusted = time_left - number_of_updates * PHYSICS_TIME_STEP # PHYSICS_TIME_STEP = time in MS of constant time between calls to .update() if self.time_adjusted > self.PHYSICS_TIME_STEP: self.time_adjusted -= self.PHYSICS_TIME_STEP return True else: return False def update(self): while not self.bDone: # events self.handle_events() self.time_adjusted = self.time_left # (1) Is this the right way to implement? / what's wrong? while self.needToDoAnotherUpdate(): # calculate all physics self.update() # else draw: # draws everything self.draw() # (2) Does this location of .time_left matter? #not sure If I should be getting time now, or right before # the first call to .update(), OR after clock.tick() ? self.time_left = pygame.time.get_ticks() # Brian F said: make up for the time lost by extra simulation updates by doing fewer draws. # (3) Not sure how else: So I did this: cap FPS self.clock.tick(30) # pygame.time.Clock.tick(fps) -- thanks, jake On Sat, May 10, 2008 at 1:30 PM, Brian Fisher <[EMAIL PROTECTED]> wrote: > 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.
Re: [pygame] Framerate Normalizer
I made sure they were floats. The new program is Asteroids 7.1 on pygame.org I think the solution was mostly successful. Ian
Re: [pygame] Framerate Normalizer
Ian Mallett wrote: ((0.0075/(IdealFPS**2))*((IdealFPS/TargetFPS)**2))*(TargetFPS**2) ...doesn't work. Be careful with data types and division. If IdealFPS and TargetFPS are integers and you're not using future division, then (IdealFPS/TargetFPS) will be doing integer division. -- Greg
Re: [pygame] Framerate Normalizer
Yeah, fixed-time physics is the way to go. How you get that fixed time is up to you, but it's a much better way than trying to put time into all of your code. It is more stable, and easier to program as well. Since you are thinking about lower end computers, you may have to rebalance everything for a lower fixed-time update. (i.e, right now it runs good at 190 fps, but that's probably not a good interval for a slower computer that can only run 60 fps). I think most professional games run at around 30 hz or so. I know Doom3 did anyway, and that's the last I read about any game's update function. Less than 30 though is probably not so good. On a really slow computer, things will slow down, but you wouldn't want to skip too many frames in that case anyway. If I can only run at 10fps, I would prefer the game to update a little slower (slow motion) to having objects be warping around.
Re: [pygame] Framerate Normalizer
I think the best option is to call the update etc. functions the correct number of times. The thrust still seems a little off--slightly slower at slower framerates.
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 <[EMAIL PROTECTED]> 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 >
Re: [pygame] Framerate Normalizer
Jake, that is actually pretty much my current solution. :) I just noticed that linear things, like turning speed do seem to scale properly. Acceleration things, as indeed thrust is, don't. ((0.0075/(IdealFPS**2))*((IdealFPS/TargetFPS)**2))*(TargetFPS**2) ...doesn't work. (Remember, IdealFPS = 198 and TargetFPS = 50) Ian
Re: [pygame] Framerate Normalizer
You can define movement speed per second. That way every computer moves X pixels/sec ( and faster computers still get the benefit of more FPS ) Ie: velocity = 10 pixels/sec , or rotation = 90degrees/sec Then calculate how much to move based on the users FPS: # fps.py class FPS(): def __init__(self): # FPS() calc's delta ( AKA: fps_elapsed ) self.ticks_cur = pygame.time.get_ticks() self.ticks_last = pygame.time.get_ticks() def tick(self): """call once each game-loop to calculate .delta""" # calculate delta self.ticks_cur = pygame.time.get_ticks() self.delta = ( self.ticks_cur - self.ticks_last ) / 1000.0 self.ticks_last = self.ticks_cur # unit.py class Unit(): def update(self): """update physics / etc. for all units.""" # delta is what you multiple your speed per second by delta = self.fps.delta # in my example: .vel, .accel are euclid.Vector2() self.vel += self.accel * delta new_loc = self.loc + self.vel * delta -- Jake
Re: [pygame] Framerate Normalizer
I usually either use time directly in my calculations (rather than fps), because I find it more natural. Does the velocity depend linearly on thrust, or is thrust an acceleration? If the units on thrust are something like meters per tick squared, then I think you will need to compensate twice for the change in frame rate. meters/newtick^2 = meters/oldtick^2 * (oldtick/newtick)^2 --Mike Ian Mallett 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
[pygame] Framerate Normalizer
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