如何实现固定步骤循环?

我试图在我的程序中创建一个固定的步骤循环,但由于某种原因,我似乎无法让它正常工作。 基本上我需要的是一个循环:

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

或类似的东西,用。 我尝试过使用Thread.Sleep,但我不太确定它给了我一个真正的固定步骤循环,当我试图在这个网站上实现解决方案时,我遇到了问题,因为我看不到一个方法保存受循环影响的对象的状态。 这迫使我排除那部分,当循环中有许多对象时导致速度减慢。

如何在不必经常保存循环中每个对象的状态的情况下获得固定的步骤循环?

如果您正在使用游戏引擎,Timer可能无法正常工作。 定时器没有足够的精度来处理固定的步进循环并保持规律。

您需要使用高精度计时器来实现它。 在这种情况下,您将需要使用秒表类。 这将使您具有足够的精度来准确跟踪经过的时间。

您只需要跟踪您想要更新的频率(在Ticks中),然后使用秒表来衡量每次更新所需的时间。 之后,您可以使用Sleep()调用来阻止,但是在大多数系统上都会意识到睡眠的精度只有14-15 ms,即使您只睡眠0或1 ms。 这可能会使您的循环速度过慢,因此您可能需要实现自旋锁或类似操作(while(等待){do something})。 Sleep()很好,因为它可以节省CPU,旋转锁会在你等待时吃CPU周期,但会给你更高的精度。

你是否要求一个基本上每n个刻度运行的循环? 这听起来像一个计时器 。 BCL中有几个计时器。 服务器的计时器或Window Forms的 计时器 。

您可以沿着这些方向使用它们。 以下是伪代码,旨在显示如何完成此操作。 换句话说,如果你只是复制和粘贴,它可能无法编译。

 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; } } } 

您还可以使用闭包来包装定义计时器的方法的状态。

编辑

我读了这篇文章,我理解了这个问题; 但是,您仍然可以使用计时器,但是您需要设置您的function,以便在您设置物理引擎的每个时间间隔内调用引擎。

你使用WPF他们有一些事件,我认为这些事件会以稳定的速度为doign动画解雇。

编辑

我更新了我的代码示例以向您展示我的解释,但基本上您所做的是为您的物理引擎定义一个间隔,然后您在每次通过“循环/定时器”时需要做什么,这决定了自从经过了多少实时最后一次迭代。 然后,您将该delta存储在Accumalator中,您将用它来倒数,直到您为自上次调用后错过的所有间隔调用物理引擎。

我挣扎的是如果在这里使用计时器更好,然后让一个dedidicated线程hibernate,或其他一些实现。

Thread.Sleep不会给你一个固定的步骤循环,它只会等待给定的时间,然后让程序继续运行。 实际频率取决于睡眠的准确程度以及您的程序在每个步骤运行相同数量的挂钟时间的一致性。 但是,如果你可以适应一些漂移,这可能是足够的,当然也是最容易的。

要获得一个真正的固定步骤循环,您需要的是一个间隔计时器 ,它在计时器到期时通过回调执行您的代码。 请注意,这不再是一个循环,但是代码会定期执行,我想,这就是你想要的。 同样,可能会有一些漂移,因此您可能需要调整每个步骤的间隔,以便在需要更高精度时,在正确的时间触发下一个事件。 它真的不可能让它完全准确 – 毕竟基于硬件的间隔定时器毕竟具有精确性 – 但希望你可以使它准确到达你的目的。