/// <summary> /// Calls directly into our Draw method from the background worker thread, /// so as to update the load animation in parallel with the actual loading. /// </summary> void DrawLoadAnimation(GameTime gameTime) { if ((graphicsDevice == null) || graphicsDevice.IsDisposed) { return; } try { graphicsDevice.Clear(Color.Black); // Draw the loading screen. Draw(gameTime); // If we have a message display component, we want to display // that over the top of the loading screen, too. if (messageDisplay != null) { messageDisplay.Update(gameTime); messageDisplay.Draw(gameTime); } graphicsDevice.Present(); } catch { // If anything went wrong (for instance the graphics device was lost // or reset) we don't have any good way to recover while running on a // background thread. Setting the device to null will stop us from // rendering, so the main game can deal with the problem later on. graphicsDevice = null; } }
/// <summary> /// Worker thread draws the loading animation and updates the network /// session while the load is taking place. /// </summary> void BackgroundWorkerThread() { long lastTime = Stopwatch.GetTimestamp(); // EventWaitHandle.WaitOne will return true if the exit signal has // been triggered, or false if the timeout has expired. We use the // timeout to update at regular intervals, then break out of the // loop when we are signalled to exit. #if !Windows while (!backgroundThreadExit.WaitOne(1000/30)) { #endif #if Windows while (!backgroundThreadExit.WaitOne(1000/30,false)) { #endif GameTime gameTime = GetGameTime(ref lastTime); DrawLoadAnimation(gameTime); UpdateNetworkSession(); } } /// <summary> /// Works out how long it has been since the last background thread update. /// </summary> GameTime GetGameTime(ref long lastTime) { long currentTime = Stopwatch.GetTimestamp(); long elapsedTicks = currentTime - lastTime; lastTime = currentTime; TimeSpan elapsedTime = TimeSpan.FromTicks(elapsedTicks * TimeSpan.TicksPerSecond / Stopwatch.Frequency); return new GameTime(loadStartTime.TotalGameTime + elapsedTime, elapsedTime ); } /// <summary> /// Calls directly into our Draw method from the background worker thread, /// so as to update the load animation in parallel with the actual loading. /// </summary> void DrawLoadAnimation(GameTime gameTime) { if ((graphicsDevice == null) || graphicsDevice.IsDisposed) return; try { graphicsDevice.Clear(Color.Black); // Draw the loading screen. Draw(gameTime); // If we have a message display component, we want to display // that over the top of the loading screen, too. if (messageDisplay != null) { messageDisplay.Update(gameTime); messageDisplay.Draw(gameTime); } graphicsDevice.Present(); } catch { // If anything went wrong (for instance the graphics device was lost // or reset) we don't have any good way to recover while running on a // background thread. Setting the device to null will stop us from // rendering, so the main game can deal with the problem later on. graphicsDevice = null; } } /// <summary> /// Updates the network session from the background worker thread, to avoid /// disconnecting due to network timeouts even if loading takes a long time. /// </summary> void UpdateNetworkSession() { if ((networkSession == null) || (networkSession.SessionState == NetworkSessionState.Ended)) return; try { networkSession.Update(); } catch { // If anything went wrong, we don't have a good way to report that // error while running on a background thread. Setting the session to // null will stop us from updating it, so the main game can deal with // the problem later on. networkSession = null; } } #endregion }