Example #1
0
        private void RunLoop()
        {
            /* Some platforms (i.e. Emscripten) don't support
             * indefinite while loops, so instead we have to
             * surrender control to the platform's main loop.
             * -caleb
             */
            if (FNAPlatform.NeedsPlatformMainLoop())
            {
                /* This breaks control flow and jumps
                 * directly into the platform main loop.
                 * Nothing below this call will be executed.
                 */
                FNAPlatform.RunPlatformMainLoop(this);
            }

            while (RunApplication)
            {
                FNAPlatform.PollEvents(
                    this,
                    ref currentAdapter,
                    textInputControlDown,
                    textInputControlRepeat,
                    ref textInputSuppress
                    );
                Tick();
            }
            OnExiting(this, EventArgs.Empty);
        }
Example #2
0
        public void RunOneFrame()
        {
            if (!hasInitialized)
            {
                DoInitialize();
                gameTimer      = Stopwatch.StartNew();
                hasInitialized = true;
            }

            FNAPlatform.PollEvents(
                this,
                ref currentAdapter,
                textInputControlDown,
                textInputControlRepeat,
                ref textInputSuppress
                );
            Tick();
        }
Example #3
0
        public void Tick()
        {
            /* NOTE: This code is very sensitive and can break very badly,
             * even with what looks like a safe change. Be sure to test
             * any change fully in both the fixed and variable timestep
             * modes across multiple devices and platforms.
             */

            AdvanceElapsedTime();

            if (IsFixedTimeStep)
            {
                /* If we are in fixed timestep, we want to wait until the next frame,
                 * but we don't want to oversleep. Requesting repeated 1ms sleeps and
                 * seeing how long we actually slept for lets us estimate the worst case
                 * sleep precision so we don't oversleep the next frame.
                 */
                while (accumulatedElapsedTime + worstCaseSleepPrecision < TargetElapsedTime)
                {
                    System.Threading.Thread.Sleep(1);
                    TimeSpan timeAdvancedSinceSleeping = AdvanceElapsedTime();
                    UpdateEstimatedSleepPrecision(timeAdvancedSinceSleeping);
                }

                /* Now that we have slept into the sleep precision threshold, we need to wait
                 * for just a little bit longer until the target elapsed time has been reached.
                 * SpinWait(1) works by pausing the thread for very short intervals, so it is
                 * an efficient and time-accurate way to wait out the rest of the time.
                 */
                while (accumulatedElapsedTime < TargetElapsedTime)
                {
                    System.Threading.Thread.SpinWait(1);
                    AdvanceElapsedTime();
                }
            }

            // Now that we are going to perform an update, let's poll events.
            FNAPlatform.PollEvents(
                this,
                ref currentAdapter,
                textInputControlDown,
                textInputControlRepeat,
                ref textInputSuppress
                );

            // Do not allow any update to take longer than our maximum.
            if (accumulatedElapsedTime > MaxElapsedTime)
            {
                accumulatedElapsedTime = MaxElapsedTime;
            }

            if (IsFixedTimeStep)
            {
                gameTime.ElapsedGameTime = TargetElapsedTime;
                int stepCount = 0;

                // Perform as many full fixed length time steps as we can.
                while (accumulatedElapsedTime >= TargetElapsedTime)
                {
                    gameTime.TotalGameTime += TargetElapsedTime;
                    accumulatedElapsedTime -= TargetElapsedTime;
                    stepCount += 1;

                    AssertNotDisposed();
                    Update(gameTime);
                }

                // Every update after the first accumulates lag
                updateFrameLag += Math.Max(0, stepCount - 1);

                /* If we think we are running slowly, wait
                 * until the lag clears before resetting it
                 */
                if (gameTime.IsRunningSlowly)
                {
                    if (updateFrameLag == 0)
                    {
                        gameTime.IsRunningSlowly = false;
                    }
                }
                else if (updateFrameLag >= 5)
                {
                    /* If we lag more than 5 frames,
                     * start thinking we are running slowly.
                     */
                    gameTime.IsRunningSlowly = true;
                }

                /* Every time we just do one update and one draw,
                 * then we are not running slowly, so decrease the lag.
                 */
                if (stepCount == 1 && updateFrameLag > 0)
                {
                    updateFrameLag -= 1;
                }

                /* Draw needs to know the total elapsed time
                 * that occured for the fixed length updates.
                 */
                gameTime.ElapsedGameTime = TimeSpan.FromTicks(TargetElapsedTime.Ticks * stepCount);
            }
            else
            {
                // Perform a single variable length update.
                if (forceElapsedTimeToZero)
                {
                    /* When ResetElapsedTime is called,
                     * Elapsed is forced to zero and
                     * Total is ignored entirely.
                     * -flibit
                     */
                    gameTime.ElapsedGameTime = TimeSpan.Zero;
                    forceElapsedTimeToZero   = false;
                }
                else
                {
                    gameTime.ElapsedGameTime = accumulatedElapsedTime;
                    gameTime.TotalGameTime  += gameTime.ElapsedGameTime;
                }

                accumulatedElapsedTime = TimeSpan.Zero;
                AssertNotDisposed();
                Update(gameTime);
            }

            // Draw unless the update suppressed it.
            if (suppressDraw)
            {
                suppressDraw = false;
            }
            else
            {
                /* Draw/EndDraw should not be called if BeginDraw returns false.
                 * http://stackoverflow.com/questions/4054936/manual-control-over-when-to-redraw-the-screen/4057180#4057180
                 * http://stackoverflow.com/questions/4235439/xna-3-1-to-4-0-requires-constant-redraw-or-will-display-a-purple-screen
                 */
                if (BeginDraw())
                {
                    Draw(gameTime);
                    EndDraw();
                }
            }
        }