After programming in XNA, then moving on to C++ and DirectX, something I have never done before is framerate independent game. I came back to Monogame to work on an android project so I decided this would be the best time to try it. I want to know what are the main drawbacks to this is there are any? How would I handle time based events if I can no longer rely on consistent updates (ie: variable foo will reach 20 in exactly 20 updates)?
These two are my main questions but if there’s any advice I can get on the subject I would like to know.
I won’t claim to be an expert, but here’re some things I’ve learned.
There are two basic methods behind frame rate independence, both with their own pros and cons, and therefore neither is considered ‘the best’ way.
The simpler method is to have a fixed number of updates running in the background and a free frame rate. I.e. regardless of the frame rate, the game still updates a fixed number of times per second. This is often used by developers who port console games to PC because console games often just sync the game updates with the frame rate (e.g. 30fps), and its easier to just keep this process for PC. In order to allow the frame rate to run faster, you interpolate the graphics between update states.
- Physics is simpler as you don’t have to consider variable acceleration over variable frame rates.
- Time based events can still be processed by using the number of updates.
- The game will (or should) play exactly the same regardless of the frame rate.
- Can make multiplayer easier to implement as you’re not dealing with a different number of updates per player.
- Can produce stuttering on systems where the update is slow to process but the graphics is fast, resulting is slow frames when it updates and fast ones when it does not.
- Interpolation between updates can be tricky to implement.
- If the frame rate is too much higher than the update speed the controls can feel somewhat unresponsive.
The second method is to process only one update per frame and do all calculations using a time step value. This can be considered the ‘true’ frame rate independence method (but there may be some who might argue that) and I think that is what you’re after.
- Avoids all (or at least ‘most of’) the Cons of the above method.
- If done right, it can run at practically any frame rate and compensate for changes in frame rate.
- Controls always update each frame, allowing as close to instant responsiveness as possible.
- Very hard to program physics due to variable time step with variable acceleration.
- All calculations that involve time (i.e. movement, acceleration, animation) must use the same time step value throughout the update method, or things will get out of sync. Its amazing how easy it is to get this wrong.
- If not done right, the gameplay can change with the frame rate, i.e. some things may move faster or slower as the frame rate changes and make the game feel wonky. This makes stable multiplayer damn-near impossible to achieve.
- Players who get faster frame rates can benefit from more responsive controls, which could make things a little unfair in multiplayer.
Regardless of which method you use you have to consider the real time of the program, i.e. the actual time between each update. Monogame provides this in the same way XNA did with the ‘gameTime’ parameter passed into the Update() method. I recommend using ‘gameTime.ElapsedGameTime.Ticks’ for this as it is the most accurate.
For the fixed background method you’d need to work out how many (if any) updates to process from the program time step and then use the actual time step for calculating the interpolation.
For the true variable method you use the time step in your calculations to vary how much they update.
Stop thinking about something happening in 20 frames, and start thinking about something happening in 1/3 second, or similar. Everything becomes time based rather than frame based. Fit this, use the GameTime parameter given to each Game Update and Draw. Take the elapsedTime.TotalSeconds. This is how much time has elapsed since the last call to Update or Draw. If you have expressed everything in metres per second or pixels per second, you just multiply that value by the elapsed seconds to get the amount of movement for that update.
I see, i will test out these methods. Could the Stopwatch class also be used to time events?
and how can you do it with acceleration or jerk?
Acceleration is metres per second per second, so naively you would multiply that acceleration by the time elapsed to get the acceleration amount for that update. This is where it gets interesting because different elapsed times will result in slightly different accelerations being added to the velocity. This is one of the reasons why it is recommended that physics simulations always be run using a fixed timestep, even if the game update is using a variable timestep.
@KonajuGames that’s not necessarily true. You can account for elapsed time when adjusting velocity and position. The end result is (aside from floating point precision issues) you can get framerate independent acceleration.
The following code was pulled/slightly modified from FlatRedBall:
// secondDifference represents the frame time
float squaredDividedByTwo = (secondDifference * secondDifference) / 2.0f;
Position.X += Velocity.X * secondDifference + Acceleration.X * squaredDividedByTwo;
Position.Y += Velocity.Y * secondDifference + Acceleration.Y * squaredDividedByTwo;
Position.Z += Velocity.Z * secondDifference + Acceleration.Z * squaredDividedByTwo;
Velocity.X += Acceleration.X * secondDifference;
Velocity.Y += Acceleration.Y * secondDifference;
Velocity.Z += Acceleration.Z * secondDifference;
Of course if you do implement a linear approximation for acceleration, then you will be subject to framerate inaccuracies.