I have written an ordinary dispatcher timer method for creating a gameloop in WPF. I notice though that if it is set to a shorter interval than say 200 ms, it doesn't catch up correctly.
I printed the seconds to screen (see code below) and compared it to my wrist watch. With a setting of 500 ms, it's okay, but if I set it much lower there is a huge discrepancy. I tried a setting of 10 ms, and that meant that the time onscreen passed only 38 seconds in a (real) minute! (Note that all my game engine code was removed during testing, so it's just the timer loop that is called. Also, it doesn't matter if I run the code from VS or the exe file in the Debug folder.)
Note that the games I create run smoothly, it's just that my (standard) Each_Tick method doesn't get called at the correct times. This in turn means that my games will run faster on a faster computer.
So how do I keep correct track of time and make sure that the Each_Tick method fires at the same time, independently of the computer (or cellphone) used? That is, I would rather have a limit on the number of game objects, collision detection precision etc, but on time, rather than just going as fast as possible. Put differently, if I set the timer increment value to 50ms (which I think is reasonable as that would mean 20 times per second), I really want the game to be updated 20 times per second.
I really don't want to get into threading etc if it's possible to avoid it, as the games themselves run fine now. I just want them to play back at the same speed.
I looked up some great replies at How to control frame rate in WPF by using dispatcher timer accurately? but this still doesn't answer my question: how do I get my games to run at the same speed, regardless of (modern) computer/cell phone and whether it's WPF/UWP or perhaps something else?
Or is this impossible to do in a rather easy manner, and I should just accept that game speed depends on the computer used?
Thanks!
Code:
public void StartTimer()
{
//This variable is used to get to the controls (labels etc) of the MainWindow (WPF)
MainWindow mainWin = System.Windows.Application.Current.Windows.Cast<System.Windows.Window>().FirstOrDefault(window => window is MainWindow) as MainWindow;
time = TimeSpan.FromSeconds(0);
//What the code below does is this:
//For each 10 ms, call the different methods. Then add 10 ms to the current time.
timer = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 10), DispatcherPriority.Normal, delegate
{
if (runGame == false) return; //only go on if not in pause mode
mainWin.txtInfo.Text = time.ToString("mm\\:ss");//Shows the timer in a textbox, only showing minutes and seconds.
//Collision code etc removed during the test
time = time.Add(TimeSpan.FromMilliseconds(10)); //adds a specified time to the current time
}, System.Windows.Application.Current.Dispatcher);
}
Note that the code above was added for testing purposes. The original code (facing the same problems) looks like this:
public void StartTimer()
{
//A note on the dispatcherTimer http://www.wpf-tutorial.com/misc/dispatchertimer/
var timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 10); // Each every n milliseconds (set low to avoid flicker)
timer.Tick += EachTick;
timer.Start();
}
// A testing counter
int counter = 0;
// Raised every tick while the DispatcherTimer is active.
private void EachTick(object sender, object e)
{ etc