QTimer setInterval без сброса оставшегося времени

У меня есть приложение, написанное на QT, которое использует QTimer. По сути, это игра, и все действия контролируются таймером. Игра включает в себя возможность увеличения\уменьшения скорости игры. Код для увеличения скорости

    timerValue -= speedUpValue;
    if (timerValue < maxSpeed) {
        timerValue = maxSpeed;
    }
    timer -> setInterval(timerValue); 

speedUpValueи maxSpeed являются константами. Почти такой же код используется для уменьшения скорости. Проблема в том, что setInterval сбрасывает внутренний таймер, и поэтому, если вы продолжаете быстро увеличивать или уменьшать скорость, игра в конечном итоге никогда не продолжится, потому что remainingTime постоянно сбрасывается. Есть ли способ установить remainingTime вручную или изменить интервал без его сброса?


person DannyPhantom    schedule 03.10.2015    source источник
comment
Нет, невозможно изменить интервал без автоматического перезапуска таймера. Однако вы, вероятно, можете добиться аналогичного эффекта, обновляя интервал только по истечении времени ожидания таймера.   -  person RA.    schedule 03.10.2015


Ответы (1)


Вы можете вообще опустить объект таймера и вместо этого использовать статический метод QTimer::singleShot(...) и установить новый одиночный выстрел для каждого события таймера с помощью метода timerValue. Таким образом, независимо от того, как часто timerValue изменяется, каждый цикл таймера будет завершен со старым значением и запланирован с текущим значением.

Как уже упоминалось RA, вы можете эффективно добиться того же, сохраняя объект таймера, но перемещая setInterval() в событие таймера, в основном то же самое, что и выше, но сохраняя объект таймера, если он вам нужен по какой-то причине.

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

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

person dtech    schedule 03.10.2015
comment
Еще одно преимущество использования одиночного выстрела каждый раз заключается в том, что в этом случае события не накапливаются. Если вы используете QTimer и не можете потреблять его сигналы так же быстро, как они генерируются, они накапливаются. Одиночные выстрелы не могут накапливаться таким образом, потому что вы инициируете следующий только при обработке текущего. Основным недостатком является меньшая точность/регулярность интервала. - person Craig Scott; 03.10.2015
comment
@CraigScott: Я знаю, что это все старые новости, но это лучшая информация, которую я могу найти на данный момент. Этот ответ, по-видимому, предполагает, что периодические события QTimer в любом случае не накапливаются. Больше похоже на проверку в конце цикла событий, чтобы узнать, не истекло ли еще заданное время. Если это так, даже грубо, оно запускает одно событие и сбрасывает таймер. Какой правильный? - person AaronD; 01.12.2017
comment
@AaronD Прошло много времени с тех пор, как я сделал вышеупомянутый комментарий, но я думаю, что он был основан на реальном поведении, которое я видел, а не на гипотетике. Слишком давно, чтобы я мог вспомнить подробности, поэтому вам придется провести собственные тесты, чтобы проверить поведение с последней версией Qt. - person Craig Scott; 02.12.2017
comment
Также учтите, что слот, подключенный к сигналу таймера, может быть соединением в очереди, поэтому накопление может происходить не с самим таймером, а скорее в очереди отложенных вызовов слота. - person Craig Scott; 02.12.2017