Ejemplo n.º 1
0
        private void DrawFrame()
        {
            if (SlowDownDrawCalls && (UpdateTime.FrameCount & 1) == 1) // skip the draw call about one frame over two.
            {
                return;
            }

            try
            {
                // Initialized
                if (!profilingDraw.IsInitialized)
                {
                    profilingDraw = Profiler.Begin(GameProfilingKeys.GameDrawFPS);
                }

                // Update profiling data
                profilingDraw.CheckIfEnabled();

                if (!isExiting && GameSystems.IsFirstUpdateDone && !Window.IsMinimized)
                {
                    drawTime.Update(totalDrawTime, lastFrameElapsedGameTime, singleFrameUpdateTime, drawRunningSlowly, true);

                    if (drawTime.FramePerSecondUpdated)
                    {
                        // TODO: store some GameTime information as attributes in the Profiling using  profilingDraw.SetAttribute(..)
                        profilingDraw.Mark("Frame = {0}, Update = {1:0.000}ms, Draw = {2:0.000}ms, FPS = {3:0.00}", drawTime.FrameCount, updateTime.TimePerFrame.TotalMilliseconds, drawTime.TimePerFrame.TotalMilliseconds, drawTime.FramePerSecond);
                    }

                    using (Profiler.Begin(GameProfilingKeys.GameDraw))
                    {
                        Draw(drawTime);
                    }
                }
            }
            finally
            {
                lastFrameElapsedGameTime = TimeSpan.Zero;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Updates the game's clock and calls Update and Draw.
        /// </summary>
        public void Tick()
        {
            try
            {
                // If this instance is existing, then don't make any further update/draw
                if (isExiting)
                {
                    CheckEndRun();
                    return;
                }

                // If this instance is not active, sleep for an inactive sleep time
                if (!IsActive)
                {
                    Utilities.Sleep(InactiveSleepTime);
                    return;
                }

                // Update the timer
                if (updateTime.FrameCount < 2) //-> delay timer reset after first draw to avoid important gap in game time space
                {
                    timer.Reset();
                }
                timer.Tick();

                // Update the playTimer timer
                playTimer.Tick();

                // Measure updateTimer
                updateTimer.Reset();

                var elapsedAdjustedTime = timer.ElapsedTimeWithPause;

                if (forceElapsedTimeToZero)
                {
                    elapsedAdjustedTime    = TimeSpan.Zero;
                    forceElapsedTimeToZero = false;
                }

                if (elapsedAdjustedTime > maximumElapsedTime)
                {
                    elapsedAdjustedTime = maximumElapsedTime;
                }

                bool suppressNextDraw       = true;
                int  updateCount            = 1;
                var  singleFrameElapsedTime = elapsedAdjustedTime;
                var  drawLag = 0L;

                if (IsFixedTimeStep)
                {
                    // If the rounded TargetElapsedTime is equivalent to current ElapsedAdjustedTime
                    // then make ElapsedAdjustedTime = TargetElapsedTime. We take the same internal rules as XNA
                    if (Math.Abs(elapsedAdjustedTime.Ticks - TargetElapsedTime.Ticks) < (TargetElapsedTime.Ticks >> 6))
                    {
                        elapsedAdjustedTime = TargetElapsedTime;
                    }

                    // Update the accumulated time
                    accumulatedElapsedGameTime += elapsedAdjustedTime;

                    // Calculate the number of update to issue
                    updateCount = (int)(accumulatedElapsedGameTime.Ticks / TargetElapsedTime.Ticks);

                    if (IsDrawDesynchronized)
                    {
                        drawLag          = accumulatedElapsedGameTime.Ticks % TargetElapsedTime.Ticks;
                        suppressNextDraw = false;
                    }
                    else if (updateCount == 0)
                    {
                        // If there is no need for update, then exit
                        return;
                    }

                    // Calculate a moving average on updateCount
                    lastUpdateCount[nextLastUpdateCountIndex] = updateCount;
                    float updateCountMean = 0;
                    for (int i = 0; i < lastUpdateCount.Length; i++)
                    {
                        updateCountMean += lastUpdateCount[i];
                    }

                    updateCountMean         /= lastUpdateCount.Length;
                    nextLastUpdateCountIndex = (nextLastUpdateCountIndex + 1) % lastUpdateCount.Length;

                    // Test when we are running slowly
                    drawRunningSlowly = updateCountMean > updateCountAverageSlowLimit;

                    // We are going to call Update updateCount times, so we can substract this from accumulated elapsed game time
                    accumulatedElapsedGameTime = new TimeSpan(accumulatedElapsedGameTime.Ticks - (updateCount * TargetElapsedTime.Ticks));
                    singleFrameElapsedTime     = TargetElapsedTime;
                }
                else
                {
                    Array.Clear(lastUpdateCount, 0, lastUpdateCount.Length);
                    nextLastUpdateCountIndex = 0;
                    drawRunningSlowly        = false;
                }

                bool beginDrawSuccessful = false;
                try
                {
                    beginDrawSuccessful = BeginDraw();

                    // Reset the time of the next frame
                    for (lastFrameElapsedGameTime = TimeSpan.Zero; updateCount > 0 && !isExiting; updateCount--)
                    {
                        updateTime.Update(totalUpdateTime, singleFrameElapsedTime, singleFrameUpdateTime, drawRunningSlowly, true);
                        try
                        {
                            UpdateAndProfile(updateTime);
                            if (EarlyExit)
                            {
                                return;
                            }

                            // If there is no exception, then we can draw the frame
                            suppressNextDraw &= suppressDraw;
                            suppressDraw      = false;
                        }
                        finally
                        {
                            lastFrameElapsedGameTime += singleFrameElapsedTime;
                            totalUpdateTime          += singleFrameElapsedTime;
                        }
                    }

                    // End measuring update time
                    updateTimer.Tick();
                    singleFrameUpdateTime += updateTimer.ElapsedTime;

                    // Update game time just before calling draw
                    //updateTime.Update(totalUpdateTime, singleFrameElapsedTime, singleFrameUpdateTime, drawRunningSlowly, true);

                    if (!suppressNextDraw)
                    {
                        totalDrawTime           = TimeSpan.FromTicks(totalUpdateTime.Ticks + drawLag);
                        DrawInterpolationFactor = drawLag / (float)TargetElapsedTime.Ticks;
                        DrawFrame();
                    }

                    singleFrameUpdateTime = TimeSpan.Zero;
                }
                finally
                {
                    if (beginDrawSuccessful)
                    {
                        using (Profiler.Begin(GameProfilingKeys.GameEndDraw))
                        {
                            EndDraw(true);
                        }
                    }

                    CheckEndRun();
                }
            }
            catch (Exception ex)
            {
                Log.Error("Unexpected exception", ex);
                throw;
            }
        }