Archived

This topic is now archived and is closed to further replies.

graveyard filla

opinions on frame based vs time based movement

Recommended Posts

high, im currently working on a top down RPG.. anyway, i was planning on locking the frame-rate at 30 or so FPS.. but just recently i have switched my drawing code to use OpenGL so now i am getting a pretty decent framerate (around 3-500 on my machine but its p4 3 gig radeon 9600)...i was thinking i should take advantage of this and use time based movement instead of frame based... this way, i could get high FPS and play the game at a normal speed.. anyway, im asking your opinions about this. is it worth the pain? my first game (a pong clone) i did time based movement, and had some undesireable results. everything appeared fine, but the enemy AI would be kind of jerky at times, also (and most disturbing), was on some machines, the enemy AI was impossibly hard... on other machines, it was extremely too easy to beat the AI... i pretty much attributed it to the TB movement, but i could be wrong. im pretty sure thats why it was happening though... since i couldnt get time based movement working properly, im a little nervous to implement it into my newer game. i mean, i was getting weird bugs in pong.. i dont want things to start popping up in my game.. but it would suck to have to lock the framrate.. (would anyone notice a diff between say 60 FPS and hundreds of FPS?).. also, i plan to add networking to the game (NO not a MMORPG!).. i want to learn winsock anyway, and i figured i would learn it and implement it into the game after i got a good feel of it by networking a more simple game (like maybe my pong..).. i only want about 2 or 4 people to connect to deathmatch / team up... also, is frame independant movement better for networked games? thanks for any advice!! [edited by - graveyard filla on May 26, 2004 3:23:44 AM]

Share this post


Link to post
Share on other sites
steveth45    122
I just finished my first game and I''d have to put a vote in for frame based movement. I made an asteroids clone and with all those asteroids and missiles flying everywhere, it''s just easier to do collision detection at set intervals. In my program, every frame I calculate all the movement and collision detection whether or not the frame was displayed. I implemented a simple frame-skipping/speed throttling algorithm using SDL''s SDL_GetTicks(). Game play is no different on slower or faster computers. All that changes is how smooth the graphics are. Sure, it''s cool when you run some 3D game or demo at 243 fps on your super-fast expensive video card, but most of those frames are not even being written to a screen with a 75hz refresh rate. It''s just a cheap thrill, not necessary for good, fun games. 60 fps provides as smooth of gameplay as you''ll ever want. It keeps the algorithms simpler... trust me. Here''s my code:

#include "SDL.h"
#define TICKS_PER_FRAME 16 // 60 fps is approx 16 ms per frame

Uint32 tick_tock = SDL_GetTicks();
Uint32 old_tick;
int time_passed;
int extra_time = 0;

while(gameover==0){
old_tick = tick_tock;
tick_tock = SDL_GetTicks();
time_passed = tick_tock - old_tick;

if(time_passed <= (TICKS_PER_FRAME - extra_time)) {
SDL_Delay(TICKS_PER_FRAME - extra_time - time_passed);
extra_time = 0;
}
else if(time_passed > (TICKS_PER_FRAME - extra_time)) {
extra_time = time_passed - TICKS_PER_FRAME + extra_time;
tick_tock = SDL_GetTicks();
goto EndOfDisplay;
}
tick_tock = SDL_GetTicks();
// Put the code to render a frame to the screen
EndOfDisplay:
// Put the code to check input and calculate the next frame
}

My complete game and source code are here:
http://www.geocities.com/steveth_45/



steveth45 = new gamecoder;

Share this post


Link to post
Share on other sites
Agony    3452
In terms of real development, I'd say: Do what fits your needs. If frame-based fits your needs best, then use that. Otherwise, use time-based.

However, for learning, I would suggest you keep trying time-based, until you get comfortable with it. The same applies to frame-based, if you're also uncomfortable with various aspects of that method. Understand both, so that when more important projects come along, you can make good design decisions. Don't just run away from time-based because it can be more difficult. It definitely has its uses, probably more than frame-based does, although that second part could be debatable. It often just depends on what type of project your working on.

Regardless, like I said, be sure to be comfortable with both. The knowledge will help you out later on.

[edited by - Agony on May 26, 2004 12:56:45 PM]

Share this post


Link to post
Share on other sites
CaptainJester    523
steveth45 is correct as far as single player games go. But if you ever plan to network, then having time based movement is easier to synchronize across a network connection. Also if you disable vertical sync on the video card, then you can unlock the framerate form the refresh rate. And most people with high end video cards/monitor can refresh up to 150Hz. The other advantage of time based movement is that you guaruntee that the game speed(not frame speed) will be the same, no matter what speed machine it runs on.



First make it work, then make it fast. --Brian Kernighan

The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities. We need men and women who can dream of things that never were. - John Fitzgerald Kennedy(35th US President)

Do not interrupt your enemy when he is making a mistake. - Napolean Bonaparte

Share this post


Link to post
Share on other sites
steveth45    122
Captain Jester,
I agree except that you said that an advantage of time-based movement is that you guarantee game speed will be the same regardless of the system. I have acheived that with frame based code so I don''t see how that''s an advantage.



steveth45 = new gamecoder;

Share this post


Link to post
Share on other sites
Raptor85    180
while locking the frame rate works on faster systems than yours, what about slower systems, that, say, can only max at 27 fps? (when you''re locking at 30) In that case the game will run slower on that machine.

___________________
-Nicholas Anton, Owner RaptorTech
-Admin(at)Raptor85.com

Share this post


Link to post
Share on other sites
steveth45    122
Raptor,
Take a look at my code, it''s simple. The framerate is locked only so far as game logic is concerned. There is frameskipping code that skips the part of each frame where the graphics are rendered. Any Windows system capable of surfing the net and downloading my game should be able to handle the logic portion of the code at my fixed framerate of 60 fps. If you are not sure, download my source code; I use lookup tables for sine and cosine to do 2D transformations so the ship and asteroids can rotate. It''s the rendering portion of most games that take the _vast_ majority of processor time. My code example skips the rendering part of each frame when the loop falls behind where it should be. Sure, on a slow 486 the game might not look as smooth if 4 out of 5 frames are skipped, but the gameplay will go on at the _same speed_.

To clarify: There are _two_ things going on in my code. One is "speed throttling" where the game will not exceed the prescribed framerate. The other is "frame skipping" which is really just skipping the graphical rendering portion of each frame so the game will play at the same speed on slower systems.

Graveyard is working on a top down RPG, the "logic" portion of his code will probably be faster than my asteroid game. I think he could safely use a 60 fps framerate.

Share this post


Link to post
Share on other sites
Jason Zelos    211
quote:
Original post by steveth45

if(time_passed <= (TICKS_PER_FRAME - extra_time)) {
SDL_Delay(TICKS_PER_FRAME - extra_time - time_passed);
extra_time = 0;
}




Wasted processing time. Your just doing nothing waiting for 16 milisecs to pass by.

quote:

else if(time_passed > (TICKS_PER_FRAME - extra_time)) {
extra_time = time_passed - TICKS_PER_FRAME + extra_time;
tick_tock = SDL_GetTicks();
goto EndOfDisplay;
}
tick_tock = SDL_GetTicks();
// Put the code to render a frame to the screen
EndOfDisplay:
// Put the code to check input and calculate the next frame
}




The lines tick_tock.... and goto... within the loop are unecessary. Also as mentioned on a slow system capable of less than 60fps this code would not degrade gracefully.

There is nothing wrong (although I prefer varable) with fixed rate timeing, but it must be independent of the frame rate to keep ai working ok, even when the video is stuttering and slow.

Rough Example.

While Main_Loop {

While Last_Time + Interval <= Current_Time {
Last_Time = Last_Time + Interval
Do_AI()
}

DrawFrame

}


Jay

Share this post


Link to post
Share on other sites
leiavoia    960
Time based, definately. You''ve got nothing to lose and everything to gain by it. And i disagree that it''s harder. It might be harder if you''ve programmed your entire game frame-based then decide to switch to time based. If you start it from the beginning, it''s not the least bit difficult.

The other thing is, theoretically, don''t limit my hardware by your sloppy coding / bad hardware. Let it run fast on fast computers.

The easiest thing to do is just let the gameloop run as fast as it can go and when you update objects, supply the current time to the object and give all objects the same exact time

time = SDL_GetTicks();

foreach (object) {
object->Update( time );
}

Share this post


Link to post
Share on other sites
leia, shouldnt i send my objects Update() function the time passed since the last frame? will the general layout look something like this?


while(!done)
{

time_now = old_time;
old_time = SDL_GetTicks();
time_passed = old_time - time_now;

//do my game here


Some_Object.Update(time_passed);

}

Some_Object::Update(Uint32 time_passed);
{
if(im_moving_right())
xPos = xPos + (SOME_NUMBER * time_passed);
}


so is this all there is to it? and what weird things should i expect / look out for? like i said im a little nervous because of the results i had with pong, but i was also a (bigger)newbie back then.. you think i should just go for it (i want high FPS allowed!)? do you see anything wrong in my exmaple code? thanks again for all your help

Share this post


Link to post
Share on other sites
steveth45    122
quote:

Wasted processing time. Your just doing nothing waiting for 16 milisecs to pass by.



Actually, it''s not wasted time. The delay function _frees_ the processor, allowing whatever tasks you are running in the background (like a separate audio thread) better access to the processor. Not wasted at all.

quote:

Also as mentioned on a slow system capable of less than 60fps this code would not degrade gracefully.



Wow, can you tell just by looking at it how graceful it will be? Actually, I upped the resolution and put a few thousand asteroids on the screen to see how well the game played when the processor couldn''t keep up. Amazingly, the gameplay became only a bit choppy but remained responsive as user input is still checked and accounted for each frame. Also, the speed of gameplay did not change. You should try it out before you bash it.

quote:

Rough Example.



I said it was my first game and my timing code does work, however "rough" it may be.


While Main_Loop {

While Last_Time + Interval <= Current_Time {
Last_Time = Last_Time + Interval
Do_AI()
}

DrawFrame

}


That''s a good idea. Actually from the discussion on this forum I''ve decided to rewrite the game using timing based movement. I agree it would probably be better in the long run. It will make collision detection more difficult and all the other timing things that counted frames. I guess I spent a lot of time with old consoles and console emulators and kind of assumed fixed frame-rate was standard.


steveth45 = new gamecoder;

Share this post


Link to post
Share on other sites
leiavoia    960
I would not pass the time since last frame. The problem is with the "time tick resolution". Like if you are getting 500fps and there are only 1000 ticks, you are passing either 1 or 2 ticks as "time since last interval". You can see how there is a 100% difference between 1 and 2! 50% between 2 and 3. That little difference shows up as herky-jerky movement.

Pass the current time. Not all objects will use time the same way. If an object needs interval time, it can calculate that itself. Or you can keep TIME and INTERVAL_TIME as global variables so objects can use either one and only calculate them once. whatever you want.

Share this post


Link to post
Share on other sites
what do you mean by pass the current time? you mean something like



//main game loop

while(!done)
{
Uint32 time = SDL_GetTicks();

//do my whole game here


//Player.Update(time);

//Enemy.Update(time)



}


Player/Enemy::Update(Uint32 time)
{

//now what? what do i do with the current time?


}




you see, im a little confused on what to do with the time once my object has the time.. also, why not call SDL_GetTicks() from inside of update? then the objects wouldnt need to receive the time.. they could find out for themselves.. OR, do you purposely only call SDL_GetTicks() ONCE, so there is only ONE time for all your objects,because if you called SDL_GetTicks() from each Update(), like this:

player.Update();
enemy.Update();


the player Update and enemy Update would have DIFFERENT times, maybe only different by a few milliseconds, but still difference. would this throw things off sync? is that why you only take the time once, so all the objects have the same time to work with? but like i said, could you explain please what to do once that object has the time. in my above example, i could calculate movement if i had the time that passed since the last frame.. but how do i calculate movement if i have just the current clock ticks ? thanks for any help!!!


Share this post


Link to post
Share on other sites
eFoDay    300
here is a timer class


class CTimer
{

protected:

double m_Frequency;

__int64 m_StartClock;

float m_FrameTime;
float m_FrameStart;
float m_FrameEnd;

public:

float GetFrameTime() { return m_FrameTime; }

double GetTime();

void Init();
void Update();

};



#include <windows.h>
#include "timer.h"

double CTimer::GetTime()
{
__int64 EndClock;

QueryPerformanceCounter((LARGE_INTEGER*)&EndClock);

return (double)(EndClock-m_StartClock)*m_Frequency;
}

void CTimer::Init()
{
__int64 rate;

// Get the performance frequency

QueryPerformanceFrequency((LARGE_INTEGER*)&rate);

// Invert it so we can multiply instead of divide

m_Frequency = 1.0/(double)rate;

// Get the start time

QueryPerformanceCounter((LARGE_INTEGER*)&m_StartClock);

m_FrameTime = 0.0f;
m_FrameStart = (float)GetTime();
m_FrameEnd = 0.0f;
}

void CTimer::Update()
{
// Cap the frame rate to the timer frequency

// The timer frequency is normally always faster than the frame rate

do {
m_FrameEnd = (float)GetTime(); // Get the end frame time

} while( m_FrameEnd == m_FrameStart);

//

m_FrameTime = m_FrameEnd - m_FrameStart; // Get the elapsed time

m_FrameStart = m_FrameEnd; // Set the end time to be the next start time

}


here is how you can use it

CTimer timer;
timer.Init();

// game loop
{
// update the timer
timer.Update();

// update sprite animation at 1 frame per second
sprite.updateAnimation(1.0, timer.GetFrameTime());
}

Share this post


Link to post
Share on other sites
Unliterate    122


QueryPerformanceFrequency(&frame_delay);
frame_delay.QuadPart/=85;//set at 85 fps

QueryPerformanceCounter(&ticks);
QueryPerformanceCounter(&last_frame);

//------------------------GAME LOOP-------------------------------

do
{
do
{
while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
switch(Msg.message)
{
case WM_LBUTTONDOWN:
break;
case WM_QUIT:
game_over=true;
}
}
QueryPerformanceCounter(&ticks);
}while(ticks.QuadPart<last_frame.QuadPart+frame_delay.QuadPart);
QueryPerformanceCounter(&last_frame);

Inputs(Game);
UpdateWorld(Game);
HitDetection(Game);
Refresh(Game);
}while(!game_over);



and i have constant deltas for 85 fps as one would expect. to support constant framerate that are determined at start up i could easily gives those deltas a coefficients. now if im going to be locking the framerate at the refresh rate in this manner, is it worth worying about rare instances of poor performance? (this is a 2d game anyway)

[edited by - unliterate on May 27, 2004 9:49:29 PM]

Share this post


Link to post
Share on other sites
leiavoia    960
well, you only want to call SDL_GetTicks() ONCE. Otherwise some of your objects will move ahead of / more than / less than other objects. You want them all to move the same amount each frame so give everybody the same time. You also want to call it only once because it cuts down on function calls as well, especially if you have thousands of objects that need the time. By making time a global, you can also cut down on passing it around every loop as too.

Share this post


Link to post
Share on other sites
Unliterate    122
lei, (i know you werent adressing me but) would that apply if the framerate is locked? that doesnt seem to take account the only problem applicable to the way im doing things, and that problem would be certain game function calls taking way longer than expected (because of something going on in the game, like lots of explosions or something). also, by ''time'' do you mean the diference in between the current time and the last time check?

Share this post


Link to post
Share on other sites
leiavoia    960
i don''t want to sound like my way is the best way, but the way *I* do it is just to let the gameloop run as fast as it can and update everything as fast as i can. It doesn''t matter if the game is bogged down at 10 FPS or is running like the Devil at 500 FPS, objects still all move and such at the same rate. Instead of saying an object should move X pixels per frame, you make it pixels per second.

I pass the current absolute time to my objects. Different objects handle that time differently. Some completely ignore it. Some keep track of the last update and calculate the difference. Some only care about the absolute time (if i want something to happen at exacty 10 seconds into the game or something), some need the difference (moving objects), some need the time since they were born (particles), some need the time relative to their whole lifespan (conditional animations), etc.

Now to (not) answer your question, i''m not sure how to get the framerate to be nice while doing other CPU intensive activities like AI besides using threads. I haven''t started AI functions for my project. I''m having to much fun designing special FX :-) But when the screen gets really bogged down, the framerate slows to a crawl, but objects still move at the same pace.

Share this post


Link to post
Share on other sites
alnite    3438
Haven't read everybody's responses, but this is how I do it, and it works fine for me.

1. set a time on which the game objects move at "normal" speed. this is like the standard time.
2. get the time spent to render a single frame. compare this time with the standard time.
3. adjust all movements of objects according to the comparison.

example:

// the game objects move at normal speed when it's 60fps
float standard_time = 60.0f/1000.0f;

// this will adjust all movements of the objects
float fps_factor = 1.0f;

void render()
{
float start_time = SDL_GetTicks();

// do stuff
objectA.x += objectA.speed * fps_factor;
objectB.x += objectB.speed * fps_factor;

float end_time = SDL_GetTicks();
float difference = start_time - end_time;

fps_factor = difference * standard_time;
}


[edited by - alnite on May 27, 2004 12:34:51 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by leiavoia
i don't want to sound like my way is the best way, but the way *I* do it is just to let the gameloop run as fast as it can and update everything as fast as i can. It doesn't matter if the game is bogged down at 10 FPS or is running like the Devil at 500 FPS, objects still all move and such at the same rate. Instead of saying an object should move X pixels per frame, you make it pixels per second.

I pass the current absolute time to my objects. Different objects handle that time differently. Some completely ignore it. Some keep track of the last update and calculate the difference. Some only care about the absolute time (if i want something to happen at exacty 10 seconds into the game or something), some need the difference (moving objects), some need the time since they were born (particles), some need the time relative to their whole lifespan (conditional animations), etc.

Now to (not) answer your question, i'm not sure how to get the framerate to be nice while doing other CPU intensive activities like AI besides using threads. I haven't started AI functions for my project. I'm having to much fun designing special FX :-) But when the screen gets really bogged down, the framerate slows to a crawl, but objects still move at the same pace.




thanks but i have another question, what is a good way at determining what velocity? to use while moving an object... like this (inside class Player)

xPos += (xVel * LastFramesTime);

yPos += (yVel * LastFramesTime);

what is a good way to figure out what an objects velocity should be if its moving? do i just guess and check or is there something that would help me figure this out ? also, to the guys talking about QueryPerformanceTimer.. im assuming this is windows only? im trying to keep my game cross platform...

thanks for your help....

also, what else should use the time besides my player/enemies/bullets ? im sure my animations will need the time, but stuff like taking input or something will not use it at all ? just wondering if theres anything else i should use the time with specifically besides obviouse stuff like movement...

[edited by - graveyard filla on May 28, 2004 1:26:10 AM]

[edited by - graveyard filla on May 28, 2004 1:26:52 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by leiavoia
I would not pass the time since last frame. The problem is with the "time tick resolution". Like if you are getting 500fps and there are only 1000 ticks, you are passing either 1 or 2 ticks as "time since last interval". You can see how there is a 100% difference between 1 and 2! 50% between 2 and 3. That little difference shows up as herky-jerky movement.

Pass the current time. Not all objects will use time the same way. If an object needs interval time, it can calculate that itself. Or you can keep TIME and INTERVAL_TIME as global variables so objects can use either one and only calculate them once. whatever you want.


ok now im confused, so i should NOT base my objects movement the way i described in my last post (with finding the time it took to go through one frame).. how should i calculate movement then? thanks again for any help

Share this post


Link to post
Share on other sites
leiavoia    960
well, eventually, yeah you are going to have to do NOW - THEN to get the interval. I''m just saying that that can lead to some precision issues for some things.

For instance, my particles do not use that. They require the TIME_OF_BIRTH and calculate their own screen positions based on NOW - TIME_OF_BIRTH. Accuracy is much greater with this. For regular moving objects, you''ll have to just get an interval like you normally would.

The point is, just give objects the time and let them figure out what they want to do with it (unless they ALL use it the same way, but don''t PLAN for that. Plan for future expansion).

The accuracy issue comes from the fact that SDL_GetTicks() only has a resolution of 1000ms. So if your frame rate is >500 FPS, your intervals will be 1ms ( 1000/501 = 1. that''s as fine a detail as you can get). If <500 FPS, then your interval will be 2ms or more. But see how there is a large difference between 1 and 2? If your interval was like 100 (arbitrary number) and 101, there''s not much difference there.

So if you were getting 501 FPS, your objects would move in units of time of 1ms. If your FPS slips to 499 (oh, my! time to upgrade!), your objects now move in units of time of 2ms. So just by increasing 2 FPS, your objects just doubled their speed. See the problem?

So if you have low FPS or a high resolution of time, it''s not a huge issue. But if you are getting theose really high numbers, use the absolute time or a better time keeper that tracks up to 1/1000000.

Share this post


Link to post
Share on other sites
leiavoia    960
more on that:

lots of things use time for my project. currently:

Particles
Light flare effects
Moving objects (All of them of course)
Animations

You could also use time for world triggers (time bombs...), calculating reload time for guns and lasers, charging a blast (holding down a key for X amount of time), blinkers, certain time based events (super mario steps on a block... block disappears after 2 seconds, mario falls), delayed reactions of any imaginable type, appearences of random powerups, invincibility comebacks (5 second grace period), and a million other things.

Share this post


Link to post
Share on other sites
ok, i understand that different objects will use the time differently... BUT, are you saying i shuold calculate the seconds passed from inside each classes Update() function? if i do this,



//global variable

Uint32 CurrentTime = 0;


//main game loop

while(!done)
{
CurrentTime = SDL_GetTicks();

////update all of my objects...


Some_Object.Update();

//update more objects...


}

//some objects update

Some_Object::Update()
{
static Uint32 PreviousTime = 0;

FrameTime = (CurrentTime - PreviousTime) * 0.001f;

PreviousTime = SDL_GetTicks() //start the counter for FPS

}


is this what your code looks like? should i just make a couple global variables, IE one called FrameTime, and then only calculate the time passed in a frame ONCE, as apposed to inside every objects Update()? wouldnt since the PreviousTime be different in each object, things would be out of synch? so should i only calculate CurrentTime, PreviousTime, and FrameTime ONCE, at the top of the game loop? like this:

PreviousTime = CurrentTime; //start the counter for FPS

CurrentTime = SDL_GetTicks(); //end the counter for FPS

FrameTime = (CurrentTime - PreviousTime) * 0.001f;

??

thanks for anymore help!!

Share this post


Link to post
Share on other sites
eFoDay    300
you need a more accurate timer than SDL_GetTicks()
did u see the last post I made? look at it and see how easy it is.

// increase x position at 200 pixels per second
sprite.x += 200.0f * timer.GetFrameInterval();

Share this post


Link to post
Share on other sites