How do I make time based movement

Started by
11 comments, last by _goat 18 years, 7 months ago
The title says it all. How do I make frame rate independant movement for my game?
bi-FreeSoftware
Advertisement
Express every speed or acceleration (linear and/or angular) in units per time.

Example:     speed = 1m / sec           or  speed = 1 cubit/ minute          or  speed = 7miles/hour  


It does not matter: you have unit/time

Then you need a timer.

Search in the forum you will find a lot of threads about.
You can use timeGetTime() under windoz if you dont need extreme precision (~10ms).

To compute the new position in the next frame multiply the elapsed time for your speed and you have the space.

// frame ....static float previous_time = timeGetTime();float speed = 1;  // 1 unit/secondstatic float position = 0;float current_time = timeGetTime();float elapsed_time = (current_time - previous_time)/1000; // [ms] -> </span><br><br>position += speed * elapsed_time;  <span class="cpp-comment">// update</span><br><br>previous_time = current_time; <span class="cpp-comment">// update</span><br>…<br><br><br></pre></div><!–ENDSCRIPT–><br><br>In practice your speed could be in vectorial form <br><br>speed = Vector (Vx, Vy, Vz)<br><br>but the idea is the same.<br><br><br><br>
But where would I put that. For example:

PSEUDO CODEmain loop{   DrawMap();   UpdateMovement();}


because I want to update movement only every lets say 10 miliseconds. So if I use the previous and current time thing you showed, my previous would be updateed each time, even if the difference between previous and current is not 10 miliseconds. I would never reach 10 miliseconds and my code would be stuck! I might be wrong, so please prove me wrong. Thanks for the above help anyways.
bi-FreeSoftware
You'd want to definately test for >= 10ms. The chances of hitting exactly 10ms is very slim as you point out.

I don't know why you'd want to do such specific time steps -- that just sounds like you're making it framerate dependant like you are trying to avoid. If I were you, I'd just update it based on the time elapsed since the previous frame (as the poster above mentioned). This is how you make it framerate independant.

Here is a sample bit of code to show how I handle my movement in nearly every case (simplified quite a bit for readability).
// This is the bit of code that runs each frameGameLoop(){	// Find the time elapsed since last frame (m_fPrevTime is a member var 	//	or static or whatever to make it persist between frames)	float fCurrTime = timeGetTime();	float fTimeElapsed = fCurrTime - m_fPrevTime;//	fTimeElapsed *= 0.001f;	// Run this line only if you want your result in seconds	// Iterate through each object and update	for( /* iterate through list of objects */ )		pObject->Update( fTimeElapsed );	m_fPrevTime = fCurrTime;}void Object::Object( vector vPos, vector vDir, float fSpeed ){	m_vForces(0.0f,0.0f,0.0f);	m_vAcceleration(0.0f,0.0f,0.0f);	m_vVelocity = vDir * fSpeed;	m_vPos = vPos;}void Object::Update( float fDt ){	m_vAcceleration += m_vForces * fDt;	m_vVelocity += m_vAcceleration * fDt;	m_vPos += m_vVelocity * fDt;}

I almost never use the forces and acceleration components as constant velocity is most common for me. But you could make acceleration be gravity and forces be wind or something like that. This will work the same for both two and three dimensions.
Quote:Original post by AdamGL
But where would I put that. For example:

*** Source Snippet Removed ***

because I want to update movement only every lets say 10 miliseconds. So if I use the previous and current time thing you showed, my previous would be updateed each time, even if the difference between previous and current is not 10 miliseconds. I would never reach 10 miliseconds and my code would be stuck! I might be wrong, so please prove me wrong. Thanks for the above help anyways.


One frame you will use 10 ms, the next, say, 5 ms then 2 ms (note also that you get the average since you compute a difference between absolute values).
This is how an animation works...[smile]
You dont know when you update the scene but when you update it you use the right elapsed time and move objects accordingly.

If you prefer a time based update (different than time based movement) you can derive an alarm from your timer class and write something like this

if (elapsed_time > 10ms) render_new_frame();

but be warned! You need a more precise timer to do this ( for example QueryPerformanceCounter() ) but I dont see the benefit .
To helix
Quote:
void Object::Update( float fDt ){	m_vAcceleration += m_vForces * fDt;	m_vVelocity += m_vAcceleration * fDt;	m_vPos += m_vVelocity * fDt;}



The code, from a physic point of view, is meaningless.
It's more correct to write
acceleration = k*force (who remember F = ma ?)
where k can be the inverse of the mass or something simulating it.

This method works if you dont need precise results but simply a nice result.
Thanks guys, I finally got it. I kept screwing around with the "loop till its time" thing and that was bull, so thanks for putting me in the right direction! Oh by the way if you guys know any internet resources that teach vectors and stuff like that, could you post them, because I know I need to learn these things soon to keep programming and I haven't learned it in school yet(grade 9). Thanks for the help! :)
bi-FreeSoftware
Quote:Original post by blizzard999
To helix
The code, from a physic point of view, is meaningless.
It's more correct to write
acceleration = k*force (who remember F = ma ?)
where k can be the inverse of the mass or something simulating it.

This method works if you dont need precise results but simply a nice result.


I certainly wouldn't call it meaningless because it works quite nicely. But if you want to throw mass into the equation, by all means, add that in. There are always some tweaks for any situation. As far as games are concerned, isn't a nice result what we're looking for? If you're going to make a racing sim for example, you probably wouldn't be doing movement this way at all in favor of something vastly more complex and precise.
Quote:Original post by helix
This method works if you dont need precise results but simply a nice result.


Only I dont see why multiply a force by a time...:) If you like it...
What blizzard999 is saying is that the line
    m_vAcceleration += m_vForces * fDt; 
is wrong. A constant force produces a constant acceleration, but in your code a constant force produces a changing acceleration. The correct code would be:
    m_vAcceleration = m_vForces / mass; 


It should also be noted that if the acceleration is not 0, then there can be enough error in the computation to cause problems (the motion changes depending on the frame rate). When the acceleration is constant (such as simple gravity), the following algorithm produces error-free results:
    v0 = v;    d0 = d;    v = v0 + a * dt;    d = d0 + v0 * dt + 0.5f * a * dt * dt; 
If acceleration is not constant, then you should use a more advanced method of integration such as RK4 or verlet.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!

This topic is closed to new replies.

Advertisement