Steady_Clock пропуск между обновлениями в основном игровом цикле - PullRequest
0 голосов
/ 12 декабря 2018

В процессе разработки прочного игрового цикла в SFML я столкнулся с этой проблемой, которую, похоже, не могу понять.Мне удалось убрать весь код SFML и все еще видеть проблему с clock() в time.h.Затем я пошел дальше и по-прежнему вижу проблему, используя std::chrono::steady_clock.

Проблема: в некоторой степени последовательно я вижу пропуски в объеме работы, которую можно выполнить между обновлениями.Каждое обновление должно занимать 1/60 секунды, а остальное время тратится на Draw(), чтобы сделать как можно больше рисунков.Иногда количество ничьих падает до 0 или 1 без видимой причины.Это пузыри до фактического применения в виде заметного заикания.Кроме «пропусков», количество выполненных розыгрышей очень стабильно.

Вот изображение (обратите внимание на скачок времени обновления и падение числа розыгрышей): Вывод на консоль вопроса

Какой-то код:

#include <iostream>
#include <time.h>
#include <chrono>

using namespace std;
using namespace std::chrono;

void Draw()
{
    //for (int i = 0; i < 1000000; i++);
}

int main()
{
    steady_clock::time_point update_time;
    steady_clock::time_point update_next;
    int update_rate = 16666666; // 60 times a second (nanosecs)
    int updates;
    int max_updates = 5;
    int draws = 0;
    update_next = steady_clock::now();

    while (true)
    {
        updates = 0;
        update_time = steady_clock::now();
        while (duration_cast<nanoseconds>(update_time - update_next) > nanoseconds(update_rate) && updates++ < max_updates)
        {
            if (draws <= 1) {
                cout << "!!!!!!!!!!!!!ERROR!!!!!!!!!!!!!" << endl;
            }
            cout << "UPDATE - ";
            cout << "Draws: " << draws 
                 << " - UT - UN: " << duration_cast<nanoseconds>(update_time - update_next).count()
                 << endl;

            draws = 0;
            update_next += nanoseconds(update_rate);
        }
        draws++;
        Draw();
    }

    return 0;
}
  • Возможно, есть что-то, чего я не понимаю в типичных приложениях?Нужно ли Windows периодически перехватывать циклы ЦП?
  • Я видел эту проблему с устойчивыми часами, часами и в специализированном приложении SFML, где работа выполняется во время обновления и отрисовки
  • Я полагаюЧасы SFML, вероятно, используют time.h clock
  • Из моего тестирования проверки max_updates не имеют ничего общего с этой проблемой (я не думаю, что они вызывают проблему)

Фактто, что я видел это с несколькими разными таймерами, наводит меня на мысль, что что-то не так с моей реализацией или моей системой.Этот пример был запущен в VS, но я видел его также в отдельном выпуске exe.Игра с частотой обновления или объемом работы, выполненной в розыгрыше, может помочь вам показать это.


После тестирования моих фоновых процессов я заметил странную корреляцию.Эта проблема пропуска возникает только тогда, когда веб-плеер Spotify открыт в Chrome и возникает раз в секунду или около того.

Я нашел это сообщение, которое может быть связано: https://community.spotify.com/t5/Other-Partners-Web-Player-etc/Web-Player-on-Chrome-causes-lag-stutter/td-p/4587103

Ответы [ 4 ]

0 голосов
/ 12 декабря 2018

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

0 голосов
/ 12 декабря 2018

В дополнение к ответу @ paddy я рекомендую вам посмотреть фиксированные временные шаги .Если это не стоит того, чтобы его реализовать, вы также должны заметить, что SFML имеет Window.setFramerateLimit().Это не очень точно, но большинству простых игр не нужна значительная точность.

0 голосов
/ 12 декабря 2018

Изначально это выглядело так, как будто проблема была вызвана моим антивирусом, но я думаю, что на самом деле я сузил его, чтобы из-за того, что веб-плеер был открыт и вызывал всплеск производительности 1 / сек.Я не уверен, почему это будет.

0 голосов
/ 12 декабря 2018

Возможно, есть что-то, чего я не понимаю в типичных приложениях?Нужно ли Windows периодически перехватывать циклы процессора?

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

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

Однако у меня есть опыт работы с аудио в реальном времени (и видео в этом отношении), работающим в циклах, которые превышают 1000 обновлений в секунду.Вы можете улучшить свою долю времени игрового цикла, установив приоритет потока в THREAD_PRIORITY_HIGHEST или THREAD_PRIORITY_TIME_CRITICAL (см. SetThreadPriority ).

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

ОчевидноеМесто для ожидания до вашего следующего цикла розыгрыша.Вместо того, чтобы крутить таймер со 100% использованием ядра, просто посчитайте, сколько времени вы готовы ждать и позвоните std::this_thread::sleep_for.Помните, что единственной гарантией является то, что сон будет на не менее указанной вами суммы.Это может быть и будет больше, чем это.Но я рекомендую вам начать с экспериментов.

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