Как реализовать цикл с фиксированным шагом? - PullRequest
2 голосов
/ 15 марта 2009

Я пытаюсь создать фиксированный пошаговый цикл в моей программе, но по какой-то причине я просто не могу заставить его работать должным образом. По сути, мне нужен цикл, который выполняет:

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

или что-то подобное, с. Я пытался использовать Thread.Sleep, но я не уверен, что он дал мне реальный фиксированный пошаговый цикл, и когда я пытался реализовать решение на этом веб-сайте, у меня были проблемы из-за того, что я Не удалось найти способ сохранить состояние объектов, затронутых циклом. Это заставило меня исключить эту часть, что привело к замедлению, когда в цикле было много объектов.

Как получить фиксированный пошаговый цикл без необходимости постоянно сохранять состояние каждого объекта в цикле?

Ответы [ 3 ]

1 голос
/ 15 марта 2009

Если вы работаете над игровым движком, таймер, вероятно, не будет работать хорошо. Таймеры не имеют достаточной точности для обработки цикла с фиксированным шагом и поддержания его регулярности.

Вам нужно будет реализовать это, используя высокоточный таймер. В этом случае вы захотите использовать класс Секундомер. Это позволит вам иметь достаточно точности для точного отслеживания вашего elapsedTime.

Вам просто нужно отслеживать, как часто вы хотите обновлять (в тиках), а затем использовать секундомер, чтобы измерить время, которое требуется для каждого из ваших обновлений. После этого вы можете потенциально использовать вызов Sleep () для блокировки, но при этом понимаете, что в большинстве систем sleep будет иметь точность только 14-15 мс, даже если вы спите только 0 или 1 мс. Это может слишком сильно замедлить ваш цикл, поэтому вам может понадобиться реализовать спин-блокировку или аналогичную (в то время как (ожидание) {сделать что-то}). Sleep () хорош, потому что он экономит процессор, если вы можете, спин-блокировка будет потреблять циклы процессора, пока вы ждете, но дает вам большую точность.

1 голос
/ 15 марта 2009

Вы запрашиваете цикл, который будет работать в основном каждые n тиков? Это звучит как Таймер . В BCL есть пара таймеров. таймер для серверов или один для оконных форм .

Вы можете использовать их по этим направлениям. Ниже приведен код psuedo, предназначенный для общего представления о том, как это делается. Другими словами, он, вероятно, не скомпилируется, если вы просто скопируете и вставите.

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

               }

}

Вы также можете использовать замыкание для обобщения состояния метода, в котором определен таймер.

Редактировать

Я прочитал статью и понял проблему; тем не менее, вы все еще можете использовать таймер, но вам нужно, как он покажет, настроить вашу функцию, чтобы вызывать механизмы для каждого интервала, для которого вы установили свой физический механизм.

Используете ли вы WPF, у них есть некоторые события, которые, я полагаю, запускаются с постоянной скоростью для обычных анимаций.

Редактировать

Я обновил пример кода, чтобы показать вам мою интерпретацию, но в основном вы определяете интервал для вашего физического движка, а затем то, что вам нужно делать на каждом проходе через «цикл / таймер», определяет, насколько реально время прошло с последней итерации. Затем вы сохраняете эту дельту в Accumalator, который будете использовать для обратного отсчета до тех пор, пока вы не вызовете свой физический движок для всех интервалов, которые вы пропустили с момента последнего вызова.

С чем я борюсь, так это с тем, чтобы лучше использовать таймер, а затем иметь спящий выделенный поток или какую-то другую реализацию.

0 голосов
/ 15 марта 2009

Thread.Sleep не даст вам фиксированный пошаговый цикл, он просто будет ждать заданное количество времени, прежде чем позволит вашей программе продолжить работу. Фактическая частота будет зависеть от того, насколько точен сон и насколько последовательно ваша программа запускает одинаковое количество часов на каждом шаге. Однако, если вы можете приспособиться к некоторому дрейфу, это может быть адекватным и, безусловно, самым простым.

Чтобы получить реальный фиксированный пошаговый цикл, вам нужен интервальный таймер , который выполняет ваш код с помощью обратного вызова, когда истекает таймер. Обратите внимание, что это больше не цикл, но ваш код выполняется периодически, что, я думаю, то, что вы хотите. Опять же, может быть некоторый сдвиг, и поэтому вам может понадобиться настроить интервал на каждом шаге, чтобы следующее событие запускалось в нужное время, если вам нужна большая точность. На самом деле невозможно сделать его абсолютно точным - в конце концов, даже аппаратные интервальные таймеры имеют точность - но, надеюсь, вы сможете сделать его достаточно точным для ваших целей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...