Xbox LIVE Indie Games
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 2 (36 posts) 1 2 Next >

A "Perfect" Fixed Timestep Method

Last post 11/23/2010 2:28 AM by MissTrouble. 35 replies.
  • 5/8/2009 6:25 PM

    A "Perfect" Fixed Timestep Method

    Have you ever gone somewhere right after a daylight savings time change only to find that you were either an hour early or an hour late? Why does this happen? You could have the most accurate clock in the world and still be an hour early or an hour late! Why? The reason is obvious, you're using the wrong clock. It really doesn't matter how accurate your clock is unless you're using the right clock.

    For the last few days, I've been trying to tune my own version of a fixed timestep function. One that doesn't glitch by periodically slipping frames. You can read about it here: http://forums.xna.com/forums/t/30741.aspx

    After playing myself out on it though, I realized that I could never make it perfect. At first I thought it was because I couldn't see all the XNA internals, but now I believe it is because the entire approach is flawed. We're running in a system with two independent unsynchronized clocks - the clock that XNA uses to drive the "tick", and the clock the video card uses to drive refresh. Well, just like the daylight savings time example, it doesn't really matter how accurate your code is when using the XNA tick, you're still using the wrong clock, and you can find yourself an "hour" early or late when trying to render a frame.

    When I say this method is "perfect", I don't mean that I'm some kind of genius that never has a bug, what I mean is that there are no synchronization issues because it is "perfect" by design. If you're writing firmware for a heart monitor, you're probably going be very concerned about "real time", but when you're writing a game, I believe you should be more concerned about synchronizing with the video card rather than staying synchronized to a wall clock.

    For this example, I've changed my entire approach to the fixed timestep concept. Now, instead of timing off the clock and making allowances in hopes to match Vsync, I actually run the game logic off the Vsync "clock", and only use the game clock to see if the game is running slowly.

    I've also changed the demo to display more information about what frame rate is running, whether its synch-locked and if its running slowly. You can press the spacebar or the A button to cycle through different target update rates.

    I'd be very interested to hear any results. Whether the screen "glitches" or looks uniform (when the update rate is different from the refresh rate, the game can look "steppy", but it should be very uniform and not jump or skip).

    This code requires the PNG files Layer1_0.png, Layer1_1.png, and Layer1_2.png, from the platformer example, and the sprite font from NetRumble menu, but probably any spritefont would work.

    One thing to note is that "GameTime" is only valid in Update(). The version of "GameTime" passed to Draw() is the XNA version (running in untimed mode). I don't think I can fix this for drawable game components, so I'm not going to override Draw() and make a Draw2(). The "Game Time" will just have to be wrong in Draw(). If only "GameTime" were writable .... <sigh> .

    If you give it a try, please let me know how it works on your PC and/or Xbox.

    EDIT: I now use this in my own game, and am having very good results. For my game, I do NOT create a new GameTime on every frame since this creates garbage that eventually has to be cleaned. Instead I have game class globals that I maintain for the time deltas, and I ignore the GameTime that is passed in Update() and Draw() within my game objects.

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using Microsoft.Xna.Framework;  
    using Microsoft.Xna.Framework.Audio;  
    using Microsoft.Xna.Framework.Content;  
    using Microsoft.Xna.Framework.GamerServices;  
    using Microsoft.Xna.Framework.Graphics;  
    using Microsoft.Xna.Framework.Input;  
    using Microsoft.Xna.Framework.Media;  
    using Microsoft.Xna.Framework.Net;  
    using Microsoft.Xna.Framework.Storage;  
     
    namespace PerfectFixed  
    {  
        public class FixedTimestepGame : Microsoft.Xna.Framework.Game  
        {  
            float UpdateCredit;         // Amount of update credit we currently have  
            float WallClockAvgSum;      // Running average (sum) of time we're taking  
            float WallClockTarget;      // Target time in ms   
            float refreshRate;          // Master refresh "clock" (fps)  
            float stepRate;             // FPS requested from user  
            bool  lockStep;           
            readonly float[] lockRates = { 0.25f, 1.0f / 3.0f, 0.5f, 2.0f / 3.0f, 0.75f, 1.0f, 1.5f, 2.0f };  
              
            /// <summary>  
            // This constructor just sets IsFixedTimeStep to false.  
            /// </summary>  
            public FixedTimestepGame()  
            {  
                // Get our refresh rate  
                refreshRate = (float)GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.RefreshRate;  
     
                // Sanitize the refresh  
                if (refreshRate == 0 || (refreshRate > 58 && refreshRate < 62))  
                    refreshRate = 60;  
     
                // Set our wall clock target  
                WallClockTarget = 1000.0f / refreshRate;  
                
                // Disable XNA game timing  
                base.IsFixedTimeStep = false;  
     
                // Set a default target elapsed time             
                TargetElapsedTime = TimeSpan.FromTicks((long)(10000000.0f / 60.0f + 0.5f));  
            }  
     
            /// <summary>  
            // We hide the real IsFixedTimeStep, and return fake values  
            // saying that is is always set.  
            /// </summary>  
            new public bool IsFixedTimeStep  
            {  
                get { return true; }  
                set { base.IsFixedTimeStep = false; }  
            }  
     
            /// <summary>  
            // Indicates if Update is in lock-step with Vertical Retrace.  
            /// </summary>  
            public bool LockStep  
            {  
                get { return lockStep; }  
            }  
     
            /// <summary>  
            // Returns the Step Rate in fps if LockStep==true.  
            /// </summary>  
            public float StepRate  
            {  
                get { if (lockStep) return stepRate; else return 0; }  
            }  
     
            /// <summary>  
            // Returns the detected monitor refresh rate.  
            /// </summary>  
            public float RefreshRate  
            {  
                get { return refreshRate; }  
            }  
     
            /// <summary>  
            // We hide the real TargetElapsedTime, so that we can recompute   
            // 'StepRate' when the value of TargetElapsedTime changes.  
            /// </summary>  
            new public TimeSpan TargetElapsedTime  
            {  
                get { return base.TargetElapsedTime; }  
                set 
                {  
                    int i;  
                    float ftmp;  
     
                    stepRate = ((1000.0f / (float)(value.TotalMilliseconds)) + 0.5f);  
     
                    // Try to get in lock-step with the request.  
                    // We will try various ratios in an attempt to lock the rate                 
                    i=0;  
                    lockStep = false;  
                    while( i<8 && !lockStep )  
                    {  
                        ftmp = refreshRate * lockRates[i] - stepRate;  
                        if (ftmp >= -2 && ftmp <= 2)  
                        {  
                            lockStep = true;  
                            stepRate = refreshRate * lockRates[i];  
                        }  
                        i++;  
                    }  
     
                    // Use the target elapsed time as passed  
                    base.TargetElapsedTime = value;  
                }  
            }  
     
            /// <summary>  
            // This function must be used instead of overriding Update(). It  
            // is not needed for drawable game components.  
            /// </summary>  
            protected virtual void Update2(GameTime gameTime) { }  
     
            /// <summary>  
            // This function is called where the expected elapsed time is  
            // about the monitor refresh rate, but can be longer.  
            /// </summary>  
            protected override void Update(GameTime gameTime)  
            {  
                int UpdateCount = 0;  
                bool IsRunningSlowly = false;  
     
                // Tack our moving average  
                WallClockAvgSum -= WallClockAvgSum / 10;  
                WallClockAvgSum += (float)gameTime.ElapsedGameTime.TotalMilliseconds;  
     
                // Set running slowly if we're 10% over budget  
                if (((WallClockAvgSum / 10) / WallClockTarget) >= 1.1f)  
                    IsRunningSlowly = true;  
     
                // We need to create a new GameTime since we don't have  
                // access to the real copy.  
                GameTime myGameTime = new GameTime(gameTime.TotalRealTime, TargetElapsedTime,  
                                                   gameTime.TotalGameTime, TargetElapsedTime, IsRunningSlowly);  
     
                // Bump our UpdateCredit  
                UpdateCredit += stepRate;  
                  
                // See how many times we need to call update (with an allowed margin of error)  
                UpdateCount = (int)(UpdateCredit / refreshRate + 0.5);  
     
                // Call our "Update2" for games that would have normally   
                // used an override on Update(), and call base.Update() for  
                // drawable game components.  
                while (UpdateCount-- > 0)  
                {  
                    Update2(myGameTime);  
                    base.Update(myGameTime);  
                    UpdateCredit -= refreshRate;  
                }  
            }  
        }  
     
        public class Game1 : FixedTimestepGame  
        {  
            GraphicsDeviceManager graphics;  
            SpriteBatch spriteBatch;  
            Rectangle myRect = new Rectangle();  
            int x_index;  
            int firstScreen;  
            Texture2D[] screens;  
            SpriteFont myFont;  
            bool RealRunningSlowly;  
            readonly float[] TestFpsRates = { 60.0f, 120.0f, 30.0f, 90.0f, 15.0f, 20.0f, 40.0f };  
            int FpsIndex = 0;  
            GamePadState previousGamepadState;
    #if !XBOX  
            KeyboardState previousKeyboardState;
    #endif  
     
            public Game1()  
            {  
                graphics = new GraphicsDeviceManager(this);  
                graphics.PreferredBackBufferWidth = 1280;  
                graphics.PreferredBackBufferHeight = 720;  
                graphics.SynchronizeWithVerticalRetrace = true;  
                IsFixedTimeStep = true;  
                TargetElapsedTime = TimeSpan.FromTicks((long)(10000000.0f / TestFpsRates[FpsIndex] + 0.5f));  
                Content.RootDirectory = "Content";  
            }  
     
            protected override void Initialize()  
            {  
                x_index = 0;  
                screens = new Texture2D[3];  
                myRect.Y = 0;  
                myRect.Height = 720;  
                myRect.Width = 1280;  
                base.Initialize();  
            }  
     
            protected override void LoadContent()  
            {  
                spriteBatch = new SpriteBatch(GraphicsDevice);  
                screens[0] = Content.Load<Texture2D>("Textures\\Layer1_0");  
                screens[1] = Content.Load<Texture2D>("Textures\\Layer1_1");  
                screens[2] = Content.Load<Texture2D>("Textures\\Layer1_2");  
                myFont = Content.Load<SpriteFont>("Fonts\\MenuFont");  
     
            }  
     
            void NewStepRate()  
            {  
                if (++FpsIndex > 6)  
                    FpsIndex = 0;  
                TargetElapsedTime = TimeSpan.FromTicks((long)(10000000.0f / TestFpsRates[FpsIndex] + 0.5f));  
            }  
     
            protected override void Update2(GameTime gameTime)  
            {  
                GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);  
                if (gamepadState.Buttons.A == ButtonState.Pressed &&  
                        previousGamepadState.Buttons.A == ButtonState.Released)  
                    NewStepRate();  
                previousGamepadState = gamepadState;
    #if !XBOX  
                KeyboardState keyboardState = Keyboard.GetState();  
                if (keyboardState.IsKeyDown(Keys.Space) &&  
                        previousKeyboardState.IsKeyUp(Keys.Space))  
                    NewStepRate();  
                previousKeyboardState = keyboardState;
    #endif  
                  
                // The gameTime passed to Draw is the bad XNA copy  
                RealRunningSlowly = gameTime.IsRunningSlowly;  
     
                x_index += 5;  
            }  
     
            protected override void Draw(GameTime gameTime)  
            {  
                GraphicsDevice.Clear(Color.CornflowerBlue);  
                spriteBatch.Begin();  
                firstScreen = (x_index / 1280) % 3;  
                myRect.X = 0 - (x_index % 1280);  
                spriteBatch.Draw(screens[firstScreen], myRect, Color.White);  
                if (myRect.X != 0)  
                {  
                    myRect.X = myRect.X + 1280;  
                    spriteBatch.Draw(screens[(firstScreen + 1) % 3], myRect, Color.White);  
                }  
     
                spriteBatch.DrawString(myFont, "Programmed FPS=" + TestFpsRates[FpsIndex].ToString() + ", Locked=" +   
                                       LockStep.ToString() + ", Locked FPS=" + StepRate.ToString() + ", Monitor FPS=" +  
                                       RefreshRate.ToString() + ", IsRunningSlow=" + RealRunningSlowly.ToString(),   
                                       new Vector2(64, 64), Color.White);  
                spriteBatch.DrawString(myFont, "(press 'A' button or [Space] to change FPS rate)",  
                                       new Vector2(64, 96), Color.White);             
                
                spriteBatch.End();  
                base.Draw(gameTime);  
            }  
        }  
    }  
     
  • 5/8/2009 6:40 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    There is a way to decouple your rendering rate from your update rate while still using fixed timesteps...have you read through this?


  • 5/8/2009 7:35 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    MJP:
    There is a way to decouple your rendering rate from your update rate while still using fixed timesteps...have you read through this?
    Thanks for the link, but I'm less concerned with running different physics rates than I am keeping the game well synchronized to the video card.

    This all stemmed from the basic problem that fixed time stepping in XNA can result in screen jumps and jitters. This is because all the XNA timing is decoupled from the video card timing. I tried fixing it twice.

    The first attempt was to allow for a large "margin of error", and resynch the XNA clock to the video card if/while we stayed in that error range. This was the result: http://forums.xna.com/forums/t/30741.aspx. It worked pretty well, but I wasn't happy with it. I view it as a collection of bandaids instead of a clean correct approach.

    The new attempt is above. This one runs the game engine off the video card (well really, off the XNA untimed Update() call), and only uses the wallclock to detect the "IsRunningSlow" condition.

    Again though, this was more about making sure XNA can render different framerates without skip and jitter, and less about decoupling the rates.

    It was an interesting read in any case. Thanks again for the link.
  • 5/8/2009 9:41 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    This approach will work as long as your graphics card correctly implements vsync, and correctly reports its refresh rate, and as long as your game never drops frames (either because of its own processing taking too long, or because some other process steals too many cycles). It seems to me that the intersection of these three requirements is too small for this to be a universally robust technique, though!

    Another issue is that you can't assume the refresh rate will always be 60. Many people run PC monitors at 70, 75, 85, or 90 hz. For this timing mechanism to work on such machines, your update logic will have to be flexible enough to adapt itself to different update frequencies (or else you don't call update at the exact monitor refresh rate in such situations, in which case you are right back where you started with rendered frames and updates not being exactly in sync). But the thing is, once you do the work to make your update robust enough to handle any refresh rate, why not just make this totally variable from frame to frame and use a full on variable timestep mode?

    The fundamental issue, as you have realized, is that the CPU and GPU clocks are entirely independent. But just syncing your game to the GPU clock is not a good solution, because the GPU clock isn't really a true clock, it's just a wait-until-next-vblank operation. There is no robust way to query the frequency of this vblank, and no way to query the total number of elapsed vblanks. All you can do is wait from the current time until the next one, but that's not a rich enough semantic to provide reliable timing.

    Pretty much every game ever made of uses one of three fundamental approaches:

    • Ignore the GPU clock, and let the CPU clock control the update frequency. Sure, this means you will occassionally have dropped or doubled frames, but as long as the clocks are roughly close, this will be rare, and the results are fine for many games. Especially, people tend to notice the time drift in very simple test apps where they are doing things like just moving a box across the screen one pixel per tick, so they freak out about this, but the artifacts tend to become less obvious as the game becomes more complex, so they are often no problem at all in the finished product. The nice thing about this mode is that it keeps your update logic nice and simple, which is why this is the XNA Framework default (we call it fixed timestep mode).

    • Sync to the GPU retract, rather than any fixed CPU clock frequency. Just call Update and Draw as fast as possible, letting the GPU vsync limit the total rate at which these can run. Each time Update is called, use a CPU timer to measure how long has passed since the previous Update, and scale all your physics computations by this amount. The result is a game that synchronises its frames exactly to the GPU retrace, but thanks to the CPU elapsed time measurement, remains robust in the presence of varying retrace rates, lying graphics drivers, and the occassional dropped frame. The downside is that you have to do more work to make your physics able to scale according to elapsed time. This may be easy for some games, but can be very complex (landing you deep into scary calculus land) for others. This mode also comes built into the XNA Framework: we call it variable timestep mode.

    • A few games use a hybrid approach (as in the link that was posted above). They use a variable timestep for Draw, calling it as fast as the GPU retrace will allow, but apply fixed timestep CPU logic to control the frequency of Update. To smooth out the visual results (since Draw may now be called half way in between two Update time locations, or there could even be more than one Draw per Update), they interpolate the game state some fraction between two different Update results when drawing at times that do not exactly align to a fixed timestep tick point. This allows them to maintain as good as possible monitor sync, while still being able to write their physics assuming a nice simple fixed timestep. The downside is the extra code for lining up the two timelines and doing the state interpolation, which can be a serious PITA. There's nothing built into the XNA Framework to help you if you want to use this mode: you'd have to start with our variable timestep and then implement your own logic on top of that.

  • 5/8/2009 9:51 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    XNA Game timing is not decoupled from rendering, that's the whole problem.  You get "jitters" or "stutters" when the Game class tries to "catch up" your updating with the rendering by calling Update multiple times.  This does fine in terms of making sure your simulation behaves exactly as it's supposed to, but visually it's jarring because it doesn't appear as though time is flowing at a constant rate (because indeed it's not). 

    To me it looks like (and correct me if I'm wrong) you're trying to solve this by adjusting the updating rate on the fly to keep in sync with rendering.  The problem with this is that it's not really a fixed time-step...the actual rate at which you update your simulation will fluctuate.  This will cause the simulation to briefly speed up or slow down, although it won't stutter at least. 

    AFAIK the only proper solution is what was proposed at the end of that article I linked to.  Unfortunately it's not something they could build into the Game framework though, since it requires that you implement your simulation updating in a very particular way.
  • 5/9/2009 2:14 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Shawn touched on a couple valid points, but I think he got a couple wrong too (or didn't look at my example closely enough), his final paragraph came closest to the mark. Matt, I think you're missing the point. I was only varying the update rate to show that the code locks at these different rates. Like I said in my initial reply, this is about keeping frames synched when using fixed timestep - this is something that the standard XNA code doesn't cover 100%. I'm not concerned about varying update rates in the game.

    Shawn, I think this code would support other monitor refresh rates - at least I wrote it to do so. It also handles being slowed down by external forces (if you run the demo, you can put a window on top of it and see). As for the game itself running too slow, you're correct in that the game has to fulfill its own performance contract over time (live up to the rate it requested), or it won't be smooth.

    You're almost spot on in your last point. That is, I want the visual stability of variable time step combined with the ease of use of a fixed timestep. You're obviously aware of the advantages of using a fixed time step in Update(), so there's not much to talk about there. I personally place a very high value on keeping in synch with the video, and the current XNA fixed timestep code isn't 100% glitch free.

    Back in the day, we were always tied to vertical synch in our games. We'd do all our control logic while the screen was being rastered, move all the sprites during blanking, and then repeat it all again. I realized that if my XNA game is going to look consistently smooth that we can't throw away this relationship. Yet its still nice to have fixed timestep logic in Update(). So the basic idea is that instead of just assuming we have 1/60 second on each retrace, we instead read the monitor refresh. And instead of assuming our logic *wants* to step in 1/60 of a second, we have a programmable step instead.

    But's here's the important part. Just like old school games, we still start processing as soon as the video card allows. For for each call to Update, I know I have a certain amount of time which is determined by the refresh rate of the monitor. I also know my programmed timestep, so I can compute how many times to call Update() before calling Draw(). I then call Update() immediately, while we're still freshly synched to the video. Waiting any amount of time to call Update() when you know it needs to be called during the current frame period is silly - its just wasting CPU and inviting a glitch to occur on the back end.

    So we keep the exact ratio of Updates() per frame that we would normally have in the standard XNA fixedtimestep, but we also keep the video stability of the variable timestep. Also, with a fixed ratio locking, we don't slip over time. I don't agree that you need to any more interpolating with this approach than you would need to do with the standard XNA fixed timestep. The only difference is that I compute in advance if a call to Draw() should be done during a frame time instead of letting the two clocks run out of synch and taking it as it comes.

    But the proof is really in the pudding, so I invite anyone interested to try and demo and compare its visual performance to the standard fixed timestep.

    Even if you don't agree in the approach, I hope I can convince you to make GameTime writable and ideally allow Tick() to be overridden. This would certainly make custom timing schemes a lot easier to integrate.


  • 5/9/2009 2:44 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Shawn Hargreaves:
    A few games use a hybrid approach (as in the link that was posted above). They use a variable timestep for Draw, calling it as fast as the GPU retrace will allow, but apply fixed timestep CPU logic to control the frequency of Update. To smooth out the visual results (since Draw may now be called half way in between two Update time locations, or there could even be more than one Draw per Update), they interpolate the game state some fraction between two different Update results when drawing at times that do not exactly align to a fixed timestep tick point. This allows them to maintain as good as possible monitor sync, while still being able to write their physics assuming a nice simple fixed timestep. The downside is the extra code for lining up the two timelines and doing the state interpolation, which can be a serious PITA. There's nothing built into the XNA Framework to help you if you want to use this mode: you'd have to start with our variable timestep and then implement your own logic on top of that.
    Shawn, I hate to double reply, but I want to make sure I'm getting one point across. I've underlined one item in your reply that implies that you're not understanding something about the approach, or that I'm not understanding you.

    Whenever the requested fixed step interval is different from the monitor rate, there will be times when you have to call Update() less or more than you call Draw(), but this "hybrid" approach is actually easier, more visually stable, and just as accurate as standard XNA fixed timestep.

    I really don't understand this "interpolate the game state some fraction between two different Update results when drawing at times that do not exactly align to a fixed timestep tick point". What I'm doing is no different from the fixed timestep approach, but its superior in that I always make the decision and act on it immediately, so that if two calls to Update() are required, they are made immediatey at the start of the available interval. When you physically time them with a clock (as in the XNA version), you can end up calling Update() late in the video interval and cause frame slippage.

    I think you can argue your earlier point that vertical synch is not available (or reliable) on all hardware, but in all other respects, I believe this approach is clearly superior in terms of video stability, and not inferior in any way (at least in none of the ways you mentioned).



  • 5/9/2009 2:45 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Captain Comic:
    Even if you don't agree in the approach, I hope I can convince you to make GameTime writable and ideally allow Tick() to be overridden. This would certainly make custom timing schemes a lot easier to integrate.
    If you want to make a suggestion to the team, use Connect. The forum is great for discussing, but Connect is the official place to file a suggestion.
  • 5/9/2009 2:57 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Nick Gravelyn:
    Captain Comic:
    Even if you don't agree in the approach, I hope I can convince you to make GameTime writable and ideally allow Tick() to be overridden. This would certainly make custom timing schemes a lot easier to integrate.
    If you want to make a suggestion to the team, use Connect. The forum is great for discussing, but Connect is the official place to file a suggestion.
    Thanks Nick. I figured if I could convince Shawn it was a good feature, then I'd be golden, but I'll try "Connect" as well. I never believed that Microsoft would put my code in XNA 4, but having the ability to seemlessly plug in 3rd party timing into XNA would allow others to try it without making modifications to their current application.
  • 5/9/2009 3:04 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    I used to use approach #3 - a variable XNA timestep that I custom fixed in Update() and then rendered as fast as possible with interpolation.  Great for recording demos, reproducable physics and no slowdown, PITA making sure you interpolated every physical state change.

    Now I just use #1 - just much simpler to implement - and I'm all for simple.  Sure you get the occasional stutter (on Windows) but Shawn's right, in game, it's rarely if ever a problem (IMHO).

    I will check out your code though when I get a spare 5 mins.
  • 5/9/2009 3:21 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    PaulCunningham:
    I used to use approach #3 - a variable XNA timestep that I custom fixed in Update() and then rendered as fast as possible with interpolation.  Great for recording demos, reproducable physics and no slowdown, PITA making sure you interpolated every physical state change.

    Now I just use #1 - just much simpler to implement - and I'm all for simple.  Sure you get the occasional stutter (on Windows) but Shawn's right, in game, it's rarely if ever a problem (IMHO).
    The standard fixed timestep (#1) glitches on my Xbox as well. You need to be running the right type of game to really notice it (like a 60fps side scroller). Reading the forums, its been an issue since 2007, but I guess so few people are writing side scrollers that there's hasn't been a big push to fix it. Or like you, people go off and spin their own solution and never mention it again on the forums.

    I agree with you 100%. My game was variable timestep, but I has having trouble figuring out how I was going to program attract modes and game intermissions without the repeatabilty. The idea behind modifying the game class is that you don't have to do anything special in your game. Your game still looks like a fixed timestep game to you, only without the glitching.

    If we just got a couple minor mods to XNA, we could completely hide it.

    I really don't care for myself (now that I have something I'm happy with), but it would be nice to be able to post a solution that could be completely hidden within a class derrived from Game. Right now, it can't.
  • 5/9/2009 7:22 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Forgive me for not reading through all the posts here, I'm in a bit of a hurry.
    I looked through your code, and it looks very similar to what I have implemented in xen. (I ended up my own timestep code as I wasn't happy with XNA's fixed time step mode).

    First thing I'll mention is don't use TimeSpan.FromTicks. It rounds to the nearest 100th of a second or so.

    Basically, what I do, is I also use a sanitized refresh rate value. However, the important thing is I allow the game time to fall behind or ahead of 'real' time by a few frames. Either way. This allows for the random jitter and noise that occurs naturally in real time measurements to not affect the game itself.
    Also, due to the way vsync works, the video driver may well stall every ~4 frames or so - to wait for the GPU to catch up. This has no impact on what is displayed. When this happens is when you are most likely to get bad timing data, it becomes obvious in a game where you get a feeling of start-stop motion. So allowing for +/- threshold helps here.
    Whatever you do, don't use running averages or any kind of 'smart' filtering of timing values you sample - it's my experience these never work well, and give a very bad feeling to the game's timing. They are perceptible, whereas timing being out of sync by a couple of frames isn't.

    Hope I haven't repeated too much that's already been mentioned.

  • 5/9/2009 4:57 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    My main issue with the XNA Timing is that when frames are missed (for fixed time step, obviously, since variable time step doesn't make presumptions about how fast the code is expected to run), and IsRunningSlowly becomes true, the XNA Framework assumes the Draw() is what's causing the slowdown.  Perhaps because my software always pushes the CPU to the limits coupled with the .NET Compact Framework / compiler's extreme basic support of floating point and lack of optimization, I always see the Update() being the culprit of slowdowns.  Making the mistake of assuming Draw() is the culprit means it is skipped while Update() is continually called in hopes of catching up.  Because this doesn't happen, the minimal frame rate limit of 2 fps is reached and Draw() is forced.  This causes problems since your 60 fps game suddenly drops to 2 fps, and in a game like Biology Battle (or my own, Duality ZF), when the action gets rough, right when you need ultimate control of your character, you lose it all, and die.  The solution is to implement the classic slowdown syndrome present in all the old school consoles that merely called WaitForRetrace() at the end of each frame to synch to the TV's refresh.  If the frame's update code took too long and missed a retrace, then it'd wait for the next one, and the game would suddently drop to 30 fps.  Bad, yes, but at least every frame is being processed and SEEN by the gamer.  This is better than 2 fps where 29 of the 30 frames processed is NEVER SEEN by the gamer.  My implementation of the slowdown syndrome is to merely ignore the Update() call if Draw() has not been called for the last update.  I refuse to call Update() twice with no intermediate Draw() code.  This would fix all the slowdown issues for Biology Battle and Galax-e-mail and others -- too bad they never thought about it, since it ruins the game right when it's needed most (fortunately only for the best of players, but still -- those are the guys most deserving of your polish).

    Perhaps XNA could have a Boolean property that turns SlowdownSydrome on or off, and have it defaulted to TRUE?

    Thoughts?
  • 5/10/2009 2:38 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    If I understand your comment correctly, then this is my feeling as well. Note that the code I posted above always calls Update() to Draw() in a fixed ratio (based on how you configure it) that is purely timed off the vsynch. The speed of the game as measured by the wall clock is really pointless, but I use it to set "IsRunningSlowly" for a bit of backwards compatibility.

    Don't get me wrong, I know there are games out there that need to run at a variety of fps rates (most likely any 3D title), but I wouldn't exptect games with variable physics rates to want to use fixed timestep anyway.

    The argument that you need to do something heroic based on real time "make up" when you're missing vsynch seems a bit silly to me because if you're missing vsynch, then you're pretty much out of luck anyway. I think its much more important to run well when you're not missing vsynch, and that's where the default fixed timestep algorithm really falls down in my opinion. 

    I wasn't aware that in addition it has the issue you mention. My game is so old-school that (other than multiple scrolling planes) I could almost run it on the original Nintendo system. Its all 48x48 tile based, and not counting particles, I don't have more than 10 sprites on the screen at once. I haven't measured the performance, but I know I must be in the 600fps range. For a game that can run its logic at 600fps to regularly hiccup and glitch at 60fps it just totally unacceptable.

    What's odd though it that I honestly don't believe that the XNA team thinks its a problem since apparently if the game doesn't have a constant scroll, then you really don't notice it. So I don't expect them to fix anything soon. All I'd like to see is a cleaner method for adding our own timing. The frustrating part is that I'm so close to being able to do it now. One problem I have with C# is that people tend to write classes that are too protective. For example, what does XNA gain by making GameTime read only?

  • 5/10/2009 3:04 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Captain, I gave your new code a shot and it works near flawlessly. I do get an occasional jitter every 20 seconds or so, but it is very slight. Good job writing this, I will have to implement it in my game as well since I am manually setting the time step at this point.

    I do hope Microsoft addresses this because it is an issue. I feel like despite all the complaints, they aren't taking this issue seriously with the end result of new game makers getting frustrated trying to make a simple side scroller.

    Keep up the good work Captain Comic!
  • 5/10/2009 3:07 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Captain Comic:
    For example, what does XNA gain by making GameTime read only?
    Not having to fully test what happens when you start putting weird values into the system. The more things you can change, tweak, and override, the more stuff they have to test to make sure the framework can handle each and every scenario. It adds complexity to the test case and truly is only relevant to a small minority of people. The vast majority of users don't seem to have a big issue with this so adding the test overhead may not be the best use of their resources.
  • 5/10/2009 6:49 AM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Do I understand correctly: Does XNA occasionally frame skip with a fixed time step at 60 fps, on a 60 fps TV, with a game that runs its Update() and Draw() loop well under 1/60th of a second (always)?  I.e. Does XNA frame skip even in perfect conditions in where a game always runs at 60 fps?  Occasionally Duality ZF will frame skip, and do so once a second, seemingly out of the blue, even with zero garbage collection, even when performance metrics indicate nothing is wrong.  Could the synch / timing issue be the problem?
  • 5/10/2009 3:27 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    JasonD:
    Do I understand correctly: Does XNA occasionally frame skip with a fixed time step at 60 fps, on a 60 fps TV, with a game that runs its Update() and Draw() loop well under 1/60th of a second (always)?  I.e. Does XNA frame skip even in perfect conditions in where a game always runs at 60 fps?
    Yes. Although you'll get some argument about what makes "perfect conditions". The XNA timing runs off a different clock than the video card. These tend to drift in relation to each other, and once they've drifted enough, you get a skip frame or an extra frame. You can see my original example here: http://forums.xna.com/forums/p/30500/173566.aspx#173566

    What upset me so much intitially about this is that I spent hours trying to find out why my game was glitching. Then, after finding XNA was at fault (through the help of others on the forums), I swapped to variable timestep and was happy. Some people on the forums continue to defend XNA though, telling anyone who posts about a glitch that its in the poster's code. In some cases it might be, but they should at least mention that XNA has been known to glitch on its own to potentially save the poster hours of fruitless debug.

    It was a recent forum exchange that made me start posting alternative approaches, but once I did it, I realized that there is some real potential here to allow for alternative timing philosophies in XNA. They are very close to having something where anyone can provide the timing engine. If they did this, we wouldn't have to argue about which way is better.

    Another Edit: Just to try and keep this all together, here is why I believe the XNA fixed timestep code stutters: http://forums.xna.com/forums/p/30741/174770.aspx#174770 .
  • 5/12/2009 8:20 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    why does microsoft simply give us 

    QueryPerformanceCounter() and QueryPerformanceFrequency()
     
    on xbox360 then we can write our own timer if we need that

    a simple api hook

    what consern me is when i create a emty project that just clear the screen and put a frame counter on it ,it runs ca..2500 frames
     
    but not long ago i have the chance to reproduce the sample running on xdk c++ and i was running ca..5700 frames

    it was about 2 month ago in my school practice in a local game company
    i talk with some of the folks there and thay said the the timer is slowed down in the xnaframework and the net.compact framework
    and some of the folks there says that it has to do with threading becource you can not control the masterthread

    the guide and all the othre things are running in the background is allways there in xna..

    but if you play some of blockbuster hits ,if you press the guide botton it will not show ,you have to first exit the game
    and that mens that thay have full control over things,,remember we are running in a sandbox here with tha xnaframework



  • 5/12/2009 8:31 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    EvoFx Studio:
    why does microsoft simply give us 

    QueryPerformanceCounter() and QueryPerformanceFrequency()
     
    on xbox360 then we can write our own timer if we need that

    a simple api hook
    Because 99% of people don't care. A large purpose of the XNA Framework was to simplify game development for the masses. Most people don't need nor want that level of timing control, so it likely didn't make sense to expose it because, as I mentioned above, everything that is exposed has to be fully tested and that takes time and resources away from other features and APIs. Not to mention that the issue isn't actually in how you are getting the elapsed time (the gameTime.ElapsedGameTime.TotalSeconds is accurate enough) but the fact that you cannot alter the Game class's run loop.
  • 5/12/2009 8:31 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    EvoFx Studio:
    why does microsoft simply give us 

    QueryPerformanceCounter() and QueryPerformanceFrequency()
     
    on xbox360 then we can write our own timer if we need that

    a simple api hook


    You mean like System.Diagnostics.Stopwatch?

    Pretty handy for those of us who don't use the Game class.
  • 5/12/2009 8:35 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    yes you can use the System.Diagnostics.Stopwatch

    and skip the gametimer

  • 5/12/2009 8:35 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    MJP:
    EvoFx Studio:
    why does microsoft simply give us 

    QueryPerformanceCounter() and QueryPerformanceFrequency()
     
    on xbox360 then we can write our own timer if we need that

    a simple api hook


    You mean like System.Diagnostics.Stopwatch?

    Pretty handy for those of us who don't use the Game class.
    I didn't think you could get a game running on the Xbox 360 without the Game class. Is that not the case? It's not entirely off topic since if you can simply replace the Game class, then there's no need to override the Tick method since you can just replace the whole thing instead.
  • 5/12/2009 8:39 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    Nick Gravelyn:
    I didn't think you could get a game running on the Xbox 360 without the Game class. Is that not the case?


    Sure you can. Everything in the Microsoft.Xna.Framework.Game assembly is 100% optional.
  • 5/12/2009 8:43 PM In reply to

    Re: A "Perfect" Fixed Timestep Method

    EvoFx Studio:

    what consern me is when i create a emty project that just clear the screen and put a frame counter on it ,it runs ca..2500 frames
     
    but not long ago i have the chance to reproduce the sample running on xdk c++ and i was running ca..5700 frames


    This is a meaningless comparison. The framerate of an empty game template tells you nothing useful about how the system will perform once it is given a meaningful workload.

    But yes, in general there will be some overhead to programming in managed code. How much depends entirely on your game, but it is not reasonable to expect the XNA Framework to have identical performance to a native C++ app.

    EvoFx Studio:
    i talk with some of the folks there and thay said the the timer is slowed down in the xnaframework and the net.compact framework


    That is 100% incorrect. Time is time. One second is one second.

    EvoFx Studio:
    and some of the folks there says that it has to do with threading becource you can not control the masterthread
    the guide and all the othre things are running in the background is allways there in xna..

    but if you play some of blockbuster hits ,if you press the guide botton it will not show ,you have to first exit the game
    and that mens that thay have full control over things,,remember we are running in a sandbox here with tha xnaframework


    Again incorrect. The Xbox 360 Guide is always active, and cannot be disabled by games regardless of what technology they are programmed with.
Page 1 of 2 (36 posts) 1 2 Next > Previous Discussion Next Discussion