tags:

views:

417

answers:

3

I am attempting to create a fixed step loop in my program, but for some reason I just can't seem to get it to work properly. Basically what I need is a loop that does:

while(!over) {
    Update(elapsedtime);
    Draw(elapsedtime);
}

or something similar, with a . I've tried using Thread.Sleep but I'm not so sure it gave me a real fixed step loop, and when I tried to implement the solution on this website I had problems due to the fact that I couldn't see a way to save the state of the objects affected by the loop. This forced me to exclude that part, which led to slowdown when there were many objects in the loop.

How can I get a fixed step loop without constantly having to save the state of every object in the loop?

+1  A: 

Are you asking for a loop which will run basically every n ticks? This sounds like a Timer. There are a couple of timer's in the BCL. A timer for servers or one for Window Forms.

You can use them along these lines. The following is psuedo code and meant to show generally how this is done. In other words it probably won't compile if you just copy and paste.

public class RepeatingTask
{
    public MyObjectState _objectState;

    public RepeatingTask(Timespan interval)
    {
       Timer timer=new Timer(Timer_Tick); //This assumes we pass a delegate. Each timer is different. Refer to MSDN for proper usage
       timer.Interval=interval;
       timer.Start();

    }
    private DateTime _lastFire;
    private void Timer_Tick()
    {
       DateTime curTime=DateTime.Now();
       DateTime timeSinceLastFire = curTime-lastFireTime;
       _lastFire=DateTime.Now(); //Store when we last fired...

       accumulatedtime+=timeSinceLastFire
       while(accumulatedtime>=physicsInterval)
       {
          Update(physicsInterval);
          accumulated-=physicInterval;
       }

               }

}

You can also use a closure to wrap up your state of the method which the timer is defined in.

Edit

I read the article and I understand the issue; however, you could still use a timer, but you need to as he indicates set your function up to call the engines for each interval you set your physics engine to.

Are you using WPF they have some events I believe which get fired at steady rates for doign animations.

Edit

I updated my code sample to show you my interpretation but basically what you do is define an interval for your physics engine, and then what you need to do on each pass through your "Loop / Timer whatever" is determine how much real time passed since the last iteration. You then store that delta in an Accumalator, which you will use to count down until you've called your physics engine for all the intervals that you missed since you last called.

What I struggle with is if using a timer here is better, then having a dedidicated thread sleeping, or some other implementation.

JoshBerke
Using just a Timer will cause problems. What if the Update method takes slightly longer than the loop is supposed to? Since the timer always ticks at a certain interval, this will increase the interval and cause slowdown. Take a look at the article I linked to.
Bevin
Wait, how exactly do you mean? I don't understand what you mean by "call the engines for each interval you set your physics engine to."
Bevin
Yes, I see. I tried to use this system with an accumulator, but it caused the framerate to drop extremely low; what happened was that the draw function sat after the accumulator, and it drew as often as possible, but the update function wasn't called as often and resulted in lag.
Bevin
Can you move your calls to the Physics function to a seperate thread? Then you will draw based on a consistent interval, and do the physics on a consistent interval but they are seperate intervals...
JoshBerke
Well, I was trying to avoid too much threading... I thought it might mess up the order of the update and draw logic.
Bevin
i think if you decouple them you'd be fine. Especially if you do the accumulator for the physics engine. It will let you throttle the two items completly seperatley. I'm not a game programer so I'm just guessing;-)
JoshBerke
Give us an update if you find a good solution I'm curious about this.
JoshBerke
I've tried this with timers. They work great at lower framerates, but the latency is too bad when you're trying for 60fps if you're trying to use dispatch timers, etc. and have to do any significant processing.
Reed Copsey
interesting it was worth a shot...well what if you get rid of the timers and just use the two threads (assuming you went with that) and do thread.sleep(0). You've gotten rid of the timing issues by using accumulators...
JoshBerke
A: 

Thread.Sleep is not going to give you a fixed step loop, it will simply wait the given amount of time before it lets your program continue. The actual frequency will depend on how accurate the sleep is and how consistent your program is in running the same amount of wall clock time at each step. If you can accommodate some drift, though, this might be adequate and is certainly the easiest.

To get a real fixed step loop, what you need is an interval timer that executes your code via a callback when the timer expires. Note that isn't really a loop anymore, but you code gets executed periodically, which is, I think, what you want. Again, there may be some drift and so you may need to adjust the interval at each step so that the next event fires at the right time if you need more accuracy. It's not really possible to make it perfectly accurate -- even hardware-based interval timers have a precision, after all -- but hopefully you can make it accurate enough for your purposes.

tvanfosson
+1  A: 

If you are working on a game engine, a Timer will probably not work well. Timers do not have enough accuracy to handle a fixed step loop and keep it regular.

You'll need to implement this using a high precision timer. In this case, you'll want to use the Stopwatch class. This will allow you to have enough precision to track your elapsedTime accurately.

You'll just need to keep track of how frequently you want to update (in Ticks), then use a stopwatch to measure the time it takes for each of your updates. After that, you can potentially use a Sleep() call to block, but realize that sleep will only have a precision of 14-15 ms on most systems, even if you only sleep for 0 or 1 ms. This may slow down your loop too much, so you may need to implement a spin lock or similar (while (waiting) { do something }). Sleep() is nice because it saves CPU if you can, the spin lock will eat CPU cycles while you're waiting, but gives you more precision.

Reed Copsey
Yes, a solution depicted on a website I found used a high resolution timer, so I tried the Stopwatch class together with his solution. The problem was that when my particle system added many particles, it caused the loop to run slower even though his code should have compensated. I'm still clueless.
Bevin
If the particle system takes longer than one "tick"'s time, there's no way to compensate. You have two options - optimize your particles to be faster, or reduce your framerate overall. Otherwise, a long running frame will cause a delay.If it's faster than a single tick, it should handle it.
Reed Copsey
How are you handling the pause between frames? Are you calling Sleep() or writing a spin lock?
Reed Copsey
In my original implementation I called Sleep.
Bevin
What framerate are you targetting? Sleep will never sleep for less than 14-15ms, and it's not that accurate. That may be your problem.
Reed Copsey
My target framerate is 1/60 second, namely 16ms, so it should work fine.
Bevin
Not likely, unfortunately. That only leaves 1-2 ms total for your update and draw methods to complete. You will probably need to implement a spin lock to get the precision you want.
Reed Copsey
Could you provide an example? I'm not totally sure I understand what exactly goes in your "waiting" and "do something" part of the loop.
Bevin
You'll have to just wait and eat CPU cycles if you want to maintain a perfect 60 FPS. This can be multiple updates, or even just a while loop that eats CPU cycles. You just need something that will "eat time" away until it's ready to update/draw again.
Reed Copsey
And what if the loop takes too long? Skip an update to catch up?
Bevin
You could do that - However, the normal means of handling this is to do a loop where you're continually checking the time required (recheck your stopwatch in the loop) to eat away nearly the exact amount of required time.
Reed Copsey
Yes, I see. But I meant what should happen if the actual updating takes too long. What should happen then?
Bevin
In that case, you have a few options. If your finding that updating is taking longer than the time you have for one tick, you probably should decrease your target framerate. If you can't "keep up" at 60FPS, I'd drop to 45FPS, then maybe 40FPS, etc.
Reed Copsey
On the other hand, if you're spinning too much, you can try to bump up to 90FPS, or even 120FPS. Many people have 120 hertz monitors now, so having a moving target framerate can be the best approach.
Reed Copsey
I tried implementing a spin lock, it caused the particles to chop and I constantly lose input and control of the game form. I think I'll just go back to my old system... It's probably not a real fixed step loop, but it worked.
Bevin
Sorry you didn't get it working. Feel free to ask if you decide to try again.
Reed Copsey