🔒 Locked
Time based movement problems
Advertisement
Original Post
Well im back again. A couple of busy months meant I had to give up the project I was working on. But I''ve now got some free time to carry on.
* Warning the following may contain bad spelling and grammar
*
Basically the problem I was having was time based movement.
To start with I was just letting the game run with no sort of movement management. I realized that just moving something wont move the same on all computers (computer spec, refresh rate).
The game is a simple 2d racing game. Its written in C and uses dx 8. Ive pretty much nailed most of the intial things:
Simple car physics
Pixel perfect collision detection (pretty fast)
Map loader/editor
Camera
Custom file formats
Now when it comes to getting time based movement to work I just cant. Ive looked through all the tutorials on the net I can find, implemented them and the same result with them all.
The problem I find is "jerky" movement. To expand:- when I run the game on a computer with the refresh rate set to 120 the game runs fairly smoothly (because the time between each frame is less). However on a computer with the rate at 60 the game runs horribly.
I came to the conclusion the reason for this was because at 60fps it would draw 60 times then there would be a big wait (ms), there is also longer gaps between each frame. To the eye this is noticable and makes the game look very jerky.
Im stumped, because time based movement works off time which is never constant its expected that I will get jerky movement. The only way I can see to get around this is to find the refresh rate of the users computer in the resolution, spilt it up for a second and do all movement by that value, of course that doesnt take into account if the fps drops, but Im lost for ideas
I would REALLY appreciate help on this, its stopping me progress any further, im DETERMINED to overcome this problem!
Thanks for your time.
hm.. so what are you using right now?
this would be a simple timer class using the performance counter
class CTimer{
private:
LARGE_INTEGER start;
LARGE_INTEGER current;
LARGE_INTEGER PerfFreq;
public:
float DeltaTime;
inline void CalcDeltaTime();
CTimer() {QueryPerformanceFrequency(&PerfFreq);}
} Timer;
inline void CTimer::CalcDeltaTime(){
QueryPerformanceCounter(¤t);
DeltaTime=(float)(current.QuadPart-start.QuadPart)/PerfFreq.QuadPart;
start=current;
}
for youre movement you need a speed (like 5units/second). all you need to do is something like:
position=direction*speed*Timer.DeltaTime;
just call Timer.CalcDeltaTime() at the beginning of each frame and should be it.
this would be a simple timer class using the performance counter
class CTimer{
private:
LARGE_INTEGER start;
LARGE_INTEGER current;
LARGE_INTEGER PerfFreq;
public:
float DeltaTime;
inline void CalcDeltaTime();
CTimer() {QueryPerformanceFrequency(&PerfFreq);}
} Timer;
inline void CTimer::CalcDeltaTime(){
QueryPerformanceCounter(¤t);
DeltaTime=(float)(current.QuadPart-start.QuadPart)/PerfFreq.QuadPart;
start=current;
}
for youre movement you need a speed (like 5units/second). all you need to do is something like:
position=direction*speed*Timer.DeltaTime;
just call Timer.CalcDeltaTime() at the beginning of each frame and should be it.
calculate a value to multiply all movements (rotations, etc) by.
Okay, so your game is tweaked to work perfectly at 120fps. So when the computer is running at 120 fps you don''t need to adjust your hard wired values so you would want to multiply them by 1.0
if it were running 60fps you would need to multiply the movements by 2.0 because the game is running half the speed.
SO
1. get the current fps. (e.g. 60.3)
2. Assuming the fps is more than 0, you divide your "ideal" fps by the actual fps (e.g. 120.0 / 60.3 = 1.99 [approx])
3. multiply ANY and EVERY motion (including acceleration) by this value.
viola.
sorry bout the explanation i am tired
Okay, so your game is tweaked to work perfectly at 120fps. So when the computer is running at 120 fps you don''t need to adjust your hard wired values so you would want to multiply them by 1.0
if it were running 60fps you would need to multiply the movements by 2.0 because the game is running half the speed.
SO
1. get the current fps. (e.g. 60.3)
2. Assuming the fps is more than 0, you divide your "ideal" fps by the actual fps (e.g. 120.0 / 60.3 = 1.99 [approx])
3. multiply ANY and EVERY motion (including acceleration) by this value.
viola.
sorry bout the explanation i am tired
Thanks for the replies.
At the moment im not using any time based/frame based movement. I was using the method you have suggested Trienco, unfortunately like I said I get the "jerk" problems.
I havent tried SpazBoy''s exact solution and off hand it looks a good idea. Although it would only update the movement multiplier every second, but from the idea I finished the post on its an improvement.
Really I guess I dont need to worry so much about this problem as much as I am. The game runs constantly at whatever the users refresh rate is (on a 400mhz+ cpu, 64mb ram, 16mb gfx card) which these days is a low level system. But im a perfectionist and dont really like to bodge a game together
I will implement SpazBoy''s solution tonight, hopefully it should run better.
Thx again.
At the moment im not using any time based/frame based movement. I was using the method you have suggested Trienco, unfortunately like I said I get the "jerk" problems.
I havent tried SpazBoy''s exact solution and off hand it looks a good idea. Although it would only update the movement multiplier every second, but from the idea I finished the post on its an improvement.
Really I guess I dont need to worry so much about this problem as much as I am. The game runs constantly at whatever the users refresh rate is (on a 400mhz+ cpu, 64mb ram, 16mb gfx card) which these days is a low level system. But im a perfectionist and dont really like to bodge a game together
I will implement SpazBoy''s solution tonight, hopefully it should run better.
Thx again.
id be curious for the result because i just dont see the point in useless calculations.
lets pretend you get the fps each frame (because never will you have exactly x fps in every single frame, more likely you will have single frames with low fps).
to calc the fps you have 1/time. you want 120fps and would do 120 / (1/time) which is 120*time. so the only difference is that your speed would be "units per frame if fps is 120" instead of "units per second". so instead of speed*time you would have speed*120*time. to calc the fps you need the time, if you have the time theres absolutely NO reason to use fps for timing.
the question is: what timer are you using? gettickcount etc. have a low resolution and are pretty useless for a game. at 120fps youd have about 0.000833s per frame so a timer with a resolution of say 0.01 is worthless.
if you have jerky movements with the performance counter i''d be interested in the code (especially if there are any casts involved)
lets pretend you get the fps each frame (because never will you have exactly x fps in every single frame, more likely you will have single frames with low fps).
to calc the fps you have 1/time. you want 120fps and would do 120 / (1/time) which is 120*time. so the only difference is that your speed would be "units per frame if fps is 120" instead of "units per second". so instead of speed*time you would have speed*120*time. to calc the fps you need the time, if you have the time theres absolutely NO reason to use fps for timing.
the question is: what timer are you using? gettickcount etc. have a low resolution and are pretty useless for a game. at 120fps youd have about 0.000833s per frame so a timer with a resolution of say 0.01 is worthless.
if you have jerky movements with the performance counter i''d be interested in the code (especially if there are any casts involved)
Trienco, I am taking it that your method calculates the time passed since last frame and calculates the multiplier based on that. Am I correct?
so your loop would look something like this.
LOOP BEGINS
CALCULATE Timer.DeltaTime
MOVE STUFF
DRAW STUFF
ETC...
LOOP ENDS
Now, a lot of the time (because you are an excellent optimizer and your code is tight and your computer is a number crunching hotrod) the amount of time between frames is very very small, so you are constantly taking a lot of small measurements. (There is a division and a subtraction every frame)
This is kind of like trying to count grains of sand.
What I like to do is use a non-performance counter because performance counters shit me and I like to pretend they don''t exist. My loop counts frames, and when a minimum amount of time has passed (say one second), I update my count.
LOOP BEGINS
FRAME_COUNT = FRAME_COUNT + 1
IF CURRENT_TIME - LAST_UPDATE_TIME < THRESHOLD
FPS = FRAME_COUNT / (LAST_UPDATE_TIME - CURRENT_TIME)
DELTA = EXPECTED_FPS / FPS
FRAME_COUNT = 0
END IF
BLAH BLAH BLAH...
LOOP ENDS
So instead of calculating a very precise delta every frame, you calculate an average delta over an acceptable timeframe. The longer you wait between updates, the worse it gets, but most of the time it does the job well with only one addition per loop and a pair of divisions when you choose to update (like once per second).
It''s a very simple, low resolution, low tech solution and it probably (i wouldn''t really know) have a smaller footprint performance wise.
so your loop would look something like this.
LOOP BEGINS
CALCULATE Timer.DeltaTime
MOVE STUFF
DRAW STUFF
ETC...
LOOP ENDS
Now, a lot of the time (because you are an excellent optimizer and your code is tight and your computer is a number crunching hotrod) the amount of time between frames is very very small, so you are constantly taking a lot of small measurements. (There is a division and a subtraction every frame)
This is kind of like trying to count grains of sand.
What I like to do is use a non-performance counter because performance counters shit me and I like to pretend they don''t exist. My loop counts frames, and when a minimum amount of time has passed (say one second), I update my count.
LOOP BEGINS
FRAME_COUNT = FRAME_COUNT + 1
IF CURRENT_TIME - LAST_UPDATE_TIME < THRESHOLD
FPS = FRAME_COUNT / (LAST_UPDATE_TIME - CURRENT_TIME)
DELTA = EXPECTED_FPS / FPS
FRAME_COUNT = 0
END IF
BLAH BLAH BLAH...
LOOP ENDS
So instead of calculating a very precise delta every frame, you calculate an average delta over an acceptable timeframe. The longer you wait between updates, the worse it gets, but most of the time it does the job well with only one addition per loop and a pair of divisions when you choose to update (like once per second).
It''s a very simple, low resolution, low tech solution and it probably (i wouldn''t really know) have a smaller footprint performance wise.
I started off using gettickcount but after having realizing its perfomance wasnt acceptable for games I tried gettime (?cant remember exact name?) and queryperformancecounter. I had the same problem with them both.
You''ll have to forgive me for my lack of knowledge but isnt there also a problem with queryperformancecounter? I thought that not all computers support it, so you have to use gettime as a backup? It''s just I tested the game on a couple of computers and one of them didnt support it.
Like you suggest trienco it could be my code.
Im confused but when a game draws say 60fps does this mean those 60 frames will be evenly distributed over the second? or will it draw the frames as quickly as it can then start over again on the next second? If you could clarfiy that Id have a better idea what was going on.
You''ll have to forgive me for my lack of knowledge but isnt there also a problem with queryperformancecounter? I thought that not all computers support it, so you have to use gettime as a backup? It''s just I tested the game on a couple of computers and one of them didnt support it.
Like you suggest trienco it could be my code.
Im confused but when a game draws say 60fps does this mean those 60 frames will be evenly distributed over the second? or will it draw the frames as quickly as it can then start over again on the next second? If you could clarfiy that Id have a better idea what was going on.
hi d00ds,
its my impression that the fps of a game is an average - the number of frames over the number of seconds.
as the game loops its updates all the stuff and then renders it - once its finished it does it all again. variances in frame rate could be due to a particular part of the game needing a lot of processing or rendering - for example when you need to blend 100 textures for an explosion or summut.
however, as previously stated in other replies, you must have a variable to which you apply the difference in time - for exmaple:
your car have a direction vector and a speed. the speed is measured in m/s - this is the distance the car travels in a second - the direction vector is a normalised vector pointing in the direction of motion. you multiply the direction vector by the speed by the time it took to get to the current execution point from the last time you were at this point: or more simply
v_direction * f_speed * f_seconds
where f_seconds is a float representing time in seconds
hope that helps and that its not too dumbed down
Fusi0n^
"We are what we repeatedly do. Excellence, then, is not an act, but a habit." - Aristotle
its my impression that the fps of a game is an average - the number of frames over the number of seconds.
as the game loops its updates all the stuff and then renders it - once its finished it does it all again. variances in frame rate could be due to a particular part of the game needing a lot of processing or rendering - for example when you need to blend 100 textures for an explosion or summut.
however, as previously stated in other replies, you must have a variable to which you apply the difference in time - for exmaple:
your car have a direction vector and a speed. the speed is measured in m/s - this is the distance the car travels in a second - the direction vector is a normalised vector pointing in the direction of motion. you multiply the direction vector by the speed by the time it took to get to the current execution point from the last time you were at this point: or more simply
v_direction * f_speed * f_seconds
where f_seconds is a float representing time in seconds
hope that helps and that its not too dumbed down
Fusi0n^
"We are what we repeatedly do. Excellence, then, is not an act, but a habit." - Aristotle
TDragon is completely correct.
Remember that the time between frames when running at 60 fps is only 16 & 2/3 ms (16.6666). It''s hardly noticable. One possible problem, though, is the method you''re using to store the time deltas may not have enough fidelity - i.e. if the time between two frames is 8.3 ms (120 fps), and you''re storing it as an integer (8), the .3 won''t be taken into account.
Remember that the time between frames when running at 60 fps is only 16 & 2/3 ms (16.6666). It''s hardly noticable. One possible problem, though, is the method you''re using to store the time deltas may not have enough fidelity - i.e. if the time between two frames is 8.3 ms (120 fps), and you''re storing it as an integer (8), the .3 won''t be taken into account.
>> TDragon is completely correct.<<
Actually, he''s not COMPLETELY correct. Just because something is running at 60fps doesn''t mean that every frame takes 1/60th of a second. It means every frame takes 1/60th of a frame ON AVERAGE. You could have half your frames going really fast, and the other half not so fast. This may still give you an average of 60fps, but not all the frames may be the same. Now, whether or not that''s what you''re noticing....I don''t know.
I think the best approach is to just check once per frame how much time has passed in seconds. Then use that as a multiplier against everything. This will make it easy to work with everything for one thing, since all your characters will be moving in units-per-second. It''ll also make everything move at a consistant pace.
Oh, as for the QueryPerformanceCounter thing....yeah, I think some computers may not support that. But, and I could be totally wrong here, as far as I know only really old computers don''t support it.
-John
Actually, he''s not COMPLETELY correct. Just because something is running at 60fps doesn''t mean that every frame takes 1/60th of a second. It means every frame takes 1/60th of a frame ON AVERAGE. You could have half your frames going really fast, and the other half not so fast. This may still give you an average of 60fps, but not all the frames may be the same. Now, whether or not that''s what you''re noticing....I don''t know.
I think the best approach is to just check once per frame how much time has passed in seconds. Then use that as a multiplier against everything. This will make it easy to work with everything for one thing, since all your characters will be moving in units-per-second. It''ll also make everything move at a consistant pace.
Oh, as for the QueryPerformanceCounter thing....yeah, I think some computers may not support that. But, and I could be totally wrong here, as far as I know only really old computers don''t support it.
-John
Hi, I had a similar problem when I was working on my final project.
We had time base movement using queryPerformance however the movement was really jerky. The reason for this as it was explained to be was because of something with the swap buffer have to wait for the 60fps refresh. We turned off vsync and we had less of a jump but we still had the problem and we were pretty much stuck. We basically switched to frame base movement and the display was smooth again. We made sure our game ran over 60fps and we put a framelock on the game loop at 60 so then if you use a frame base movement of 60fps it works pretty good.
We had time base movement using queryPerformance however the movement was really jerky. The reason for this as it was explained to be was because of something with the swap buffer have to wait for the 60fps refresh. We turned off vsync and we had less of a jump but we still had the problem and we were pretty much stuck. We basically switched to frame base movement and the display was smooth again. We made sure our game ran over 60fps and we put a framelock on the game loop at 60 so then if you use a frame base movement of 60fps it works pretty good.
I actually tried to post a fairly comprehensive response last night, but the stupid intarnet ate it
and I gave up. But I will try again.
FPS, or Frames Per Second is a measurement of the speed at which single pictures in an animation are being dislayed.
In television & film, the rate at which the frames are displayed is constant, so for a film running at 25 fps, each frame would be shown for exactly 1/25th of a second.
In a dynamic computer game however, the amount of complexity in a scene can change (i.e. hordes of enemies appear), or system services / background programs might be running. This means that your program is not always displaying frames at the same speed.
Now the problem you are having occurs because your movements are set up on a per frame basis, that is they move a fixed amount every loop. So naturally, when the computer is flying along your loop will be run quicker and your objects will be moved more often. But if your computer suddenly needs resources for something else that''s running your loops will run slower and the user will notice a change in the game''s speed.
The idea is to realise that rather than moving a certain amount per frame, what you want to accomplish is to move a certain amount PER SECOND.
First of all you need to express all motion (transformation, acceleration, rotation etc.) as an amount of motion per second (i.e. degrees per second or pixels per second or whatever). For a car you might decide that it can turn 5 degrees per second and accelerates at 3 pixels per second with a top speed of 30 pixels per second.
Then what you need to do is determine how much time has passed since the last frame was displayed. Measure this in seconds and you will be able to multiply all your movement amounts by this value to compensate for changing frame rates.
So, just say that the user is holding down the "turn left" key.
You measure the time passed since last frame and in seconds it is 0.00833 seconds (roughly 120 fps). Now we know that the car can turn 5 degrees per second, and we are updating for 0.00833 seconds, so we multiply them and get 0.04165. So you turn the car by 0.04165 degrees.
There was an awful lot of scenery to draw in that frame though and when we get back to the top of the loop, 0.0333 seconds have passed (roughly 30 fps). Now we obviously have to show a larger change on the screen to compensate for this slowdown. 0.0333 multiplied by 5 (degrees) gives 0.1665 degrees.
Does that clarify any?
Oh yeah, just say you don''t have access to a high precision timer and still want to compensate.
What you then do is pick an amount of time which is measurable by your timer, and in which more than 0 frames are likely to be drawn. I usually choose something like 1 second, but this can be TOO inaccurate sometimes.
What you do is count each frame that passes in this alloted period of time to calculate the AVERAGE FPS over that period. Take the reciprocal of that reading and multiply your movements by that value while you count frames for the next period.
So say you chose a 0.5 second interval. You run your program and in the first 0.5 seconds 60 frames are drawn. 60 / 0.5 gives 120 fps, and the reciprocal of 120 is 0.00833 (approx). The rest is the same as the first example in the previous method.
So there was 10 big explosions to do and your particle system is very badly written (you naughty monkey) so over the next 0.5 seconds 15 frames are drawn. 15 / 0.5 gives 30 fps, and the reciprocal of 30 is 0.0333. I''m sure you get the picture.
The main advantage of this method is that it is not dividing every frame, it only divides once per interval. The limitation of this method is that it doesn''t ACCURATELY eliminate jerkiness, and sometimes may only reduce it.
Okay I''m sorry if I just confused everybody with this, I can write some source code for a demo if you like (i think
)
FPS, or Frames Per Second is a measurement of the speed at which single pictures in an animation are being dislayed.
In television & film, the rate at which the frames are displayed is constant, so for a film running at 25 fps, each frame would be shown for exactly 1/25th of a second.
In a dynamic computer game however, the amount of complexity in a scene can change (i.e. hordes of enemies appear), or system services / background programs might be running. This means that your program is not always displaying frames at the same speed.
Now the problem you are having occurs because your movements are set up on a per frame basis, that is they move a fixed amount every loop. So naturally, when the computer is flying along your loop will be run quicker and your objects will be moved more often. But if your computer suddenly needs resources for something else that''s running your loops will run slower and the user will notice a change in the game''s speed.
The idea is to realise that rather than moving a certain amount per frame, what you want to accomplish is to move a certain amount PER SECOND.
First of all you need to express all motion (transformation, acceleration, rotation etc.) as an amount of motion per second (i.e. degrees per second or pixels per second or whatever). For a car you might decide that it can turn 5 degrees per second and accelerates at 3 pixels per second with a top speed of 30 pixels per second.
Then what you need to do is determine how much time has passed since the last frame was displayed. Measure this in seconds and you will be able to multiply all your movement amounts by this value to compensate for changing frame rates.
So, just say that the user is holding down the "turn left" key.
You measure the time passed since last frame and in seconds it is 0.00833 seconds (roughly 120 fps). Now we know that the car can turn 5 degrees per second, and we are updating for 0.00833 seconds, so we multiply them and get 0.04165. So you turn the car by 0.04165 degrees.
There was an awful lot of scenery to draw in that frame though and when we get back to the top of the loop, 0.0333 seconds have passed (roughly 30 fps). Now we obviously have to show a larger change on the screen to compensate for this slowdown. 0.0333 multiplied by 5 (degrees) gives 0.1665 degrees.
Does that clarify any?
Oh yeah, just say you don''t have access to a high precision timer and still want to compensate.
What you then do is pick an amount of time which is measurable by your timer, and in which more than 0 frames are likely to be drawn. I usually choose something like 1 second, but this can be TOO inaccurate sometimes.
What you do is count each frame that passes in this alloted period of time to calculate the AVERAGE FPS over that period. Take the reciprocal of that reading and multiply your movements by that value while you count frames for the next period.
So say you chose a 0.5 second interval. You run your program and in the first 0.5 seconds 60 frames are drawn. 60 / 0.5 gives 120 fps, and the reciprocal of 120 is 0.00833 (approx). The rest is the same as the first example in the previous method.
So there was 10 big explosions to do and your particle system is very badly written (you naughty monkey) so over the next 0.5 seconds 15 frames are drawn. 15 / 0.5 gives 30 fps, and the reciprocal of 30 is 0.0333. I''m sure you get the picture.
The main advantage of this method is that it is not dividing every frame, it only divides once per interval. The limitation of this method is that it doesn''t ACCURATELY eliminate jerkiness, and sometimes may only reduce it.
Okay I''m sorry if I just confused everybody with this, I can write some source code for a demo if you like (i think
quote:
Original post by SpazBoy_ForgotHisPassword My loop counts frames, and when a minimum amount of time has passed (say one second), I update my count.
so you could also call Timer.CalcDeltaTime every x frames and use that if rounding problems occur.
both ways contain errors. one by dealing with small numbers (which in fact arent that small, as ticks are counted in 64bit integers). and one by ignoring that fps can drop for single frames and applying an average that might be far off the actual value.
the main reason i didnt like that approach is because its throwing around with fps where i dont see a need for them. also wouldnt measuring each second have another problem, because you will never have excactly 1second? if you do it ever 60frames you end up with 60/time. you measure movement in m/60frames. you end with 60*m / time*60 or m/time (with m being (m/s) / 60)
of course if running at 6000fps you would have pretty small times again. so i guess as long as we dont have timers with endless accuracy or variables with endless precision all you can do is choose the poison you prefer *g*.
i for example cant get used to thinking in movement per frame at x fps (but then, i had a hard time to understand why people claim opengl would apply your transformations in reverse order til i found that their way of looking at it seemed pretty twisted to me *g*).
though i would prefer your approach over cityhunters way of ''make the game crawl on very slow computers that cant reach 60fps'' (im quite tolerant so i dont mind playing at 20fps for example without feeling much ''jerkiness'')
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement