C ++: подсчет количества кадров в игре - PullRequest
3 голосов
/ 14 января 2011

Не очень хороший заголовок, но я не знал, как его назвать.

В любом случае, я подсчитываю общее количество кадров (чтобы я мог рассчитать средний FPS) в моей игре с long int. На случай, если игра продлится действительно долго, что я должен сделать, чтобы мой long int не увеличился больше своего лимита? И что будет, если он выйдет за пределы своего лимита?

Спасибо.

Ответы [ 6 ]

8 голосов
/ 14 января 2011

Эта проблема присутствует для любого типа счетчиков.

Я бы не стал беспокоиться о вашей конкретной проблеме.

A long int насчитывает до 2 миллиардов (и более) всамые худшие случаи (на 32-битных компьютерах / консолях).Предположим, ваша игра работает со скоростью 1000 кадров в секунду (а это очень много!), Вам потребуется 20000000 секунд для переполнения вашего счетчика: более 5000 часов, более 231 дня.

Я уверен, что-то ещеможет привести к остановке вашей игры, если вы попытаетесь запустить ее так долго!

5 голосов
/ 14 января 2011

Вместо этого я бы рассмотрел использование экспоненциально взвешенного скользящего среднего .Этот подход убьет двух зайцев одним выстрелом: он позволит избежать проблемы накопления большого количества, и он также адаптируется к недавнему поведению, так что накопленное среднее значение 100 кадров в секунду в 2010 году не сместит среднее значение, так что скорость 2 кадра в секундуказалось бы приемлемым в течение месяца или около того в 2011 году:).

4 голосов
/ 14 января 2011

Средний FPS на протяжении всей игры не очень полезная статистика. Как правило, вам нужно измерять пики и впадины, такие как максимальный fps / минимальный fps и количество кадров, потраченных ниже и выше пороговых значений.

Хотя на самом деле я бы не волновался. Даже если вы просто используете 32-битное unsigned int, ваша игра может работать со скоростью 60 кадров в секунду в течение 19884 часов, прежде чем она переполнится. Вы должны быть в порядке.

EDIT:

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

1 голос
/ 14 января 2011

Если long int 32-битное, максимальное значение равно 2 ^ 31-1, поэтому при обновлениях 1 мс оно переполнится через 24,9 дня, а не 231 [2 ^ 31/1000/60/60/24].

Надеюсь, не слишком OT ... как правило, для игр это не может быть проблемой, но это для других приложений. Распространенная ошибка, с которой нужно быть осторожным, это делать что-то вроде

extern volatile uint32_t counter;
uint32_t one_second_elapsed = counter + 1000;
while ( counter < one_second_elapsed ) do_something();

Если счетчик + 1000 переполнен, то do_something () вызываться не будет. Способ проверить это,

uint32_t start = counter;
while ( counter - start < 1000 ) do_something();
1 голос
/ 14 января 2011

Вы можете активно проверять переполнение в ваших арифметических операциях. Например SafeInt может сделать это для вас. Конечно, производительность хуже, чем у i++.

Однако маловероятно, что 32-разрядное целое число переполнится, если вы всегда увеличиваете его на единицу.

0 голосов
/ 14 января 2011

Вероятно, лучше использовать среднее значение для небольшого числа кадров. Вы упомянули, что хотите вычислить среднее значение, но на самом деле нет причин хранить такое большое количество выборок для расчета среднего значения. Просто сохраняйте общее количество кадров в течение небольшого промежутка времени (где маленьким может быть что-то между 10-50 кадрами - мы обычно используем 16). Затем вы можете использовать эту сумму для расчета среднего числа кадров в секунду. Этот метод также помогает сгладить отчеты о времени кадра, чтобы числа не перепрыгивали повсюду. Однако следует обратить внимание на то, что при усреднении за слишком длительный период времени пики частоты кадров становятся более «скрытыми», что означает, что может быть сложнее обнаружить кадры, из-за которых частота кадров падает, если эти кадры случаются очень часто .

Что-то вроде этого было бы вполне достаточно, я думаю (непроверенный код, чтобы следовать):

// setup some variables once
const int Max_samples = 16;    // keep at most 16 frametime samples
int FPS_Samples = 0;
int Current_sample = 0;
int Total_frametime = 0.0f;
float Frametimes[Max_samples];
for ( int i = 0; i < Max_samples; i++ ) {
    Frametimes[i] = 0.0f;

Затем, когда вы вычисляете время кадра, вы можете сделать что-то вроде этого:

// current_frametime is the new frame time for this frame
Total_frametime -= Frametimes[Current_sample];
Total_frametime += current_frametime;
Frametimes[Current_sample] = current_frametime;
Current_sample = ( Current_sample + 1 ) % Max_samples;   // move to next element in array

Frames_per_second = Max_samples / Total_frametime;

Это черновой вариант и, возможно, может использоваться некоторая проверка ошибок, но это дает общее представление.

...