A Better Silverlight Game Loop?

I've had a problem with my timers in my games.  Basically the problem is that when the loop happens too quickly I get a loop that has 0 ticks elapsed.  I am of the belief that there is an issue with resolution from the DateTime.Now which I use to tell how much time has elapsed between a game frame.  You can read more about the problem in this thread on the Silverlight site (I'm pretty innarticulate in it).  The higher the frame rate, the stranger my games appeared to behave and the more occurances of bugs (divide by zero, etc...).  This was less of a problem in Silverlight 2 because it had a limited frame rate at 60 frames.  In Silverlight 3, framerates can go much higher.

In my "Game Engine" I use different loop classes that were originally derived from the Silverlight Games 101 blog.  I've made some modifications from that original code and they all (DispatcherTimer, StoryBoardTimer and CompositionTarget) inherit from the base GameLoop class.

In order to fix my problem, I added a queue that keeps track of the last ten times and returns and average time elapsed.  The result has been very positive as I have not experienced a lot of the errors I used to have, and the games appear to be smoother.  

I could be crazy and this may be a bad technique.  Please contact me if you try it, or have tried something similar and it doesn't quite work out.  For now, it is my production timer until I have a bad experience.

GameLoop.cs

    public abstract class GameLoop : IDisposable
    {
        public delegate void UpdateHandler(TimeSpan elapsed);
        public event UpdateHandler Update;

        private Queue<long> pastFrames;
        
        protected long lastTick;

        // reused vars for Tick.
        private long tempNow; 
        private long tempElapsed;

        public GameLoop()
        {
            pastFrames = new Queue<long>();
        }

        public virtual void TimerTicked()
        {
            tempNow = DateTime.Now.Ticks;
            tempElapsed = tempNow - lastTick;
            pastFrames.Dequeue();
            pastFrames.Enqueue(tempElapsed);
            if (Update != null) Update(TimeSpan.FromTicks(pastFrames.Sum() / 10));
            lastTick = tempNow;
        }

        public virtual void Start()
        {
            InitPastFrames();
            lastTick = DateTime.Now.Ticks;
        }

        public abstract void Stop();

        /// <summary>
        /// Inits the past frame queue at an average frame rate of 60 frames per second
        /// </summary>
        private void InitPastFrames()
        {
            pastFrames.Clear();
            for (int idx = 0; idx < 10; idx++) pastFrames.Enqueue(156250);
        }
        
        #region IDisposable Members

        public virtual void Dispose()
        {
            Stop();
            Update = null;
        }

        #endregion
    }

Copyright © 2010 DDtMM

Powered by BlogEngine.NET 1.5.0.7