2D scrolling, random hitches or skips, fixed timestep, etc...

So… I think most of us know about this issue. I’m currently using isFixedTimeStep = true with SyncronizeWithVerticalRetrace = true. I get the random “skips” or “hitches” that have been discussed to death online. Here’s the curious thing… if I set isFixedTimeStep to false my animations are just a tiny bit slower. For everything. Now, I’ve implemented a stopwatch and my Update and Draw methods combined average between 6 and 7 milliseconds. Additionally, there’s no GC kicking in. There’s not a single “new” call outside of Constructors and Init methods called from Game1.Initialize(). I also force GC to kick in once all of that method is finished.

I’m running a core i7 7700, Radeon 480x 8GB, and 24GB ram. Obviously plenty of power (and again each Update and Draw cycle takes 6-7 milliseconds combined).

Has anyone figured out how to get rid of the hitches? Also, can anyone explain why my animations (which are all running off of timers incremented by gameTime.ElapsedGameTime.TotalMilliseconds) are SLOWER when I unlock the framerate (SyncronizeWithVerticalRetrace = true in either configuration).

I’d be happy to just turn it off and leave SyncronizeWithVerticalRetrace = true (it seems to fix the hitching), but I’ll have to go back and re-code movement speeds, impact pauses, etc… and I’m quite happy with the feel of the game as is.

Ok, well… I was hoping somebody had some input lol. I’m surprised this hasn’t been solved as it’s been a thing for a long time. I will certainly update this thread if I find a suitable solution :slight_smile:

I’m working on a 2D scroller as well (using FixedTimeStep) but haven’t really noticed this as an issue, however it could be because my game involves a lot of changes of direction and scroll speed. You can try it here to see if you think it does.

Note that not using ‘new’ doesn’t necessarily mean no GC as you also have to make sure objects are not being disposed as well as not being created. Also there are API calls and language features that can cause a lot of memory allocation/deallocation if not used carefully - foreach loops being a notorious example.

I tend to count frames for timing animations, sometimes use DateTime.Now for other timing tasks.

Have you checked your memory use with a profiler?

I haven’t had a chance to check out your game yet, but I can answer your questions. I’m using Visual Studio 2017 and can see when the GC kicks in using the memory profiler. So, GC is definitely not the issue.

I’ve actually done so more research. The hitching occurs because an extra update call is made. I put a counter in both the Update and Draw methods (fixedTimeStep = true). For the first second or so there are 3 more Update calls than Draw calls. It looks like it takes a few frames for Draw to be called when I first begin running the game in Debug mode. This stays consistent and there’s always a 3 count difference between Update and Draw as the game runs. Until a hitch happens. Then the difference is 4. So, an extra Update call was made. The “hitch” is really everything moving by two frame ticks (all movement is coded to happen on a per-frame basis). The game runs at a steady 60fps and isGameRunningSlowly is never set to ‘true.’ My guess is that the extra frame has to do with the isFixedTimeStep = true logic and is the result of an accumulator for rounding. Once that rounding accumulator gets to a certain value it automatically fires off another Update. Again… this is my guess.

Anyway, I believe I’ve found a solutions for this. It’s been working for the last few days at least. If you have issues with this you should do the following:

set isFixedTimeStep = true;
set SynchronizeWithVerticalRetrace = true;

In your game class add:

protected override bool BeginDraw() {
return false;
}

This will inhibit the normal draw calls. with isFixedTimeStep = true the logic calls Draw() “whenever they feels like it.” To quote one of the developers of XNA. So, you are not guaranteed a Draw call for each Update call. This is why when it decided to call an extra Update I saw the “hitch” which was really everything moving at twice the amount(s) they should.

Lastly, you add this to the end of your Update method:

if (base.BeginDraw()) {
Draw(spriteBatch);
base.EndDraw();
}

This guarantees Draw is called after each Update call. So, as long as your Update + Draw time is less than 1/60 second you will always have smooth scrolling. If the isFixedTimeStep logic decides to add an extra Update call in there (again, I’m assuming it’s does so accounting for rounding) you won’t get the “hitching” as you are now calling Draw after each and every Update.

Maybe this can help too: