Ранее в моем основном цикле игры время было установлено на уровне 60 кадров в секунду и соответствующей задержки для временной задержки.
Последовательность Спрайта была анимирована следующим образом:
<pre>
if(++ciclos > 10){
siguienteSprite++;
ciclos = 0;
}
</pre>
Учитывая, что я использую Smooth Motion с DeltaTime, поэтому я исключил задержку из основного цикла; Делая это, циклы анимации спрайтов быстрее, и не только это, но также и время между каждой последовательностью меняется.
Кто-то может мне помочь, только с логикой этой проблемы, заранее спасибо. 🙂
delay
в основном цикле не очень хороший способ для этого (так как он не учитывает время, затрачиваемое другими вещами в основном цикле). Когда вы удаляете задержку, скорость увеличивается и меняется больше, потому что другие элементы в вашем основном цикле более значительны и обычно не постоянны по многим причинам, таким как:
Есть больше способов, как справиться с этим:
измерять время
<pre>
t1=get_actual_time();
while (t1-t0>=animation_T)
{
siguienteSprite++;
t0+=animation_T;
}
// t0=t1; // this is optional and change the timing properties a bit
</pre>
где t0
некоторая глобальная переменная, содержащая «последнее» измеренное время изменения спрайта. t1
фактическое время и animation_T
постоянная времени между изменениями анимации. Для измерения времени нужно использовать Операционные системы апи как PerformanceCounter
на окнах или RDTSC
в asm или любой другой, вы получили под рукой, но с достаточно маленьким разрешением.
Таймер ОС
просто увеличить siguienteSprite
в каком-то таймере с animation_T
интервал. Это просто, но таймеры ОС не точны и обычно составляют около 1 мс или более + степень детализации ОС (аналогично Sleep
точность).
Таймер потока
Вы можете создать один поток для целей синхронизации, например, что-то вроде этого:
for (;!threads_stop;)
{
Delay(animation_T); // or Sleep()
siguienteSprite++;
}
Не забудь этого siguienteSprite
должно быть volatile
и буферизуется во время рендеринга, чтобы избежать мерцания и / или ошибок нарушения доступа. Этот подход немного более точен (если у вас нет одноядерного ЦПУ).
Вы также можете увеличить некоторую переменную времени и использовать ее в качестве фактического времени в своем приложении с любым разрешением, которое хотите. Но будьте осторожны, если delay
не возвращается ЦПУ контроль Операционные системы тогда этот подход будет использовать ваши ЦПУ в 100%/CPU_cores
, Для этого есть средство, которое заменяет ваш delay
с этим:
Sleep(0.9*animation_T);
for (;;)
{
t1=get_actual_time();
if (t1-t0>=animation_T)
{
siguienteSprite++;
t0=t1;
break;
}
Если вы используете измеренное время, вы должны справиться с переполнением (t1<t0)
потому что любой счетчик будет переполнен со временем. Например, используя 32-битную часть RDTSC на 3.2 GHz
Ядро процессора переполнит каждый 2^32/3.2e9 = 1.342 sec
так что это реальная возможность. Если у меня хорошо работает память, то счетчики производительности в Windows обычно бегают 3.5 MHz
на старшего Операционные системы системы и вокруг 60-120 MHz
на более новых (по крайней мере, в прошлый раз, когда я проверяю), и они 64-битные, так что переполнения не являются большой проблемой (если вы не запускаете 24/7). Также в случае RDTSC использовать вы должны установить сродство процесса / потока в один ЦПУ ядро, чтобы избежать проблем с синхронизацией на многоядерных ЦПУs.
В течение многих лет я проводил сравнительный анализ и улучшал синхронизацию с высоким разрешением на низком уровне, поэтому здесь мало кто контроль качествамои:
неправильные измерения тактового цикла с помощью rdtsc — ОС Гранулярность
Измерение задержек кэша — измерение частоты процессора
Оценка размера кэша в вашей системе? — PerformanceCounter
пример
Вопросы по измерению времени с использованием тактовых частот процессора — PIT как альтернативный источник синхронизации
Других решений пока нет …