private void RunGameLoopInBackground() { try { int hertz = 60; var second = Stopwatch.Frequency; var shortFrame = second / hertz; var longFrameCount = (int)(second % hertz); var nextFrame = Stopwatch.GetTimestamp(); var nextSecond = nextFrame + second; int frameIndex = 0; bool wasPrepared = true; while (_running && _gameLoop.Running) { var now = Stopwatch.GetTimestamp(); if (nextSecond <= now) { // TODO: Add metric reporting nextSecond += second; } // Erase all the empty seconds (due to a long application pause). while (nextSecond <= now) { nextSecond += second; } if (now < nextFrame) { if (wasPrepared) { // TODO: Pick the optimal sleep strat. // https://randomascii.wordpress.com/2012/06/05/in-praise-of-idleness/ Thread.Sleep(1); } else { _gameLoop.PrepareScene(); wasPrepared = true; } } else { _gameLoop.FrameUpdate(); wasPrepared = false; // Stretch the leftover sub-frame across all the other frames. nextFrame += shortFrame + Convert.ToInt64(frameIndex < longFrameCount); frameIndex = (frameIndex + 1) % hertz; } } _gameLoop.Close(); if (!_running) { _logger.LogDebug("Game loop exited gracefully via disposal."); } else { _logger.LogDebug("Game loop exited gracefully via game loop."); } } catch (Exception ex) { _logger.LogError(ex, "Error in game loop."); } }