Вопрос о запуске программы с одинаковой скоростью на любом компьютере - PullRequest
3 голосов
/ 03 марта 2010

Я создал программу (на C ++, использующую gl / glut) для учебных целей, где вы можете бегать вокруг экрана (от первого лица), и в нем есть несколько твердых тел по сцене. Я попытался запустить его на другом компьютере, и скорость была совершенно другой, поэтому я искал предмет, и в настоящее время я делаю что-то вроде этого:

Функция холостого хода:

    start = glutGet (GLUT_ELAPSED_TIME);
    double dt = (start-end)*30/1000;

    <all the movement*dt>

    glutPostRedisplay ();

    end = glutGet (GLUT_ELAPSED_TIME);

Функция отображения:

    <rendering for all objects>

    glutSwapBuffers ();

Мой вопрос: это правильный способ сделать это? Сцена отображается после функции ожидания, верно?

Я попытался поместить end = glutGet (GLUT_ELAPSED_TIME) перед glutSwapBuffers () и не заметил каких-либо изменений, но когда я помещаю его после glutSwapBuffers (), оно сильно замедляется и иногда даже останавливается.

РЕДАКТИРОВАТЬ: Я только что заметил, что, как я думаю, конечный запуск должен заканчиваться временем, прошедшим с того момента, как все рисование было выполнено, и до обновления движения, так как idle () будет вызван, как только display () заканчивается, так что правда, что единственное время, которое здесь не учитывается, - это время, которое требуется компьютеру для выполнения всех операций? (Что должно быть едва ли ничем?)

Извините, если это слишком запутанно ..

Заранее спасибо.

Ответы [ 7 ]

4 голосов
/ 03 марта 2010

Я не знаю, что такое «перенасыщение», но, как общее правило разработки игр, я бы никогда не основывал скорость движения на том, насколько быстро компьютер может обрабатывать директивы. Это то, что они сделали в конце 80-х, и поэтому, когда вы играете в старую игру, все движется со скоростью света.

Я бы настроил таймер и основывал все свои движения на четких и определенных временных событиях.

1 голос
/ 04 марта 2010

У вас есть много ответов о том, как сделать это «правильным» способом, но вы используете GLUT, и GLUT иногда жертвует «правильным» способом для простоты и поддержания независимости платформы. GLUT - это регистрация функции обратного вызова таймера с помощью glutTimerFunc ().

static void timerCallback (int value)
{
    // Calculate the deltas

    glutPostRedisplay(); // Have GLUT call your display function
    glutTimerFunc(elapsedMilliseconds, timerCallback, value);
}

Если вы установите для elapsedMilliseconds значение 40, эта функция будет вызываться чуть менее 25 раз в секунду. Это немного меньше будет зависеть от того, сколько времени потребуется компьютеру для обработки кода вычисления дельты. Если вы сохраните этот код простым, ваша анимация будет работать с одинаковой скоростью во всех системах, если каждая система может обрабатывать функцию отображения менее чем за 40 миллисекунд. Для большей гибкости вы можете настроить частоту кадров во время выполнения с помощью параметра командной строки или добавив элемент управления в ваш интерфейс.

Вы запускаете цикл таймера, вызывая glutTimerFunc(elapsedMilliseconds, timerCallback, value); в процессе инициализации.

1 голос
/ 04 марта 2010

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

1 голос
/ 03 марта 2010

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

Внутренне вы можете реализовать небольшие подэтапы с фиксированным временем, потому что попытка заставить все работать правильно на переменных шагах не так просто, как x + = v * dt.

Попробуйте gamedev.net для подобных вещей. много статей и насыщенный форум.

1 голос
/ 03 марта 2010

Установите таймер высокого разрешения (например, QueryPerformanceCounter в Windows) и измерьте время между каждым кадром. Это время, называемое дельта-временем (dt), должно использоваться во всех расчетах движения, например. в каждом кадре установите позицию объекта на:

obj.x += 100.0f * dt; // to move 100 units every second

Поскольку сумма dt всегда должна составлять 1 за 1 секунду, приведенный выше код увеличивает x на 100 каждую секунду, независимо от частоты кадров. Вы должны сделать это для всех значений, которые меняются со временем. Таким образом, ваша игра идет с одинаковой скоростью на всех машинах (независимо от частоты кадров), а не в зависимости от скорости, с которой компьютер обрабатывает логику (зависит от частоты кадров). Это также полезно, если частота кадров начинает падать - игра неожиданно не запускается в замедленном режиме, она продолжает двигаться с той же скоростью, просто рендеринг реже.

0 голосов
/ 04 марта 2010

Это очень сложный вопрос.

Первое, что вам нужно, чтобы удивить себя, действительно ли вы хотите, чтобы ваше приложение работало с той же скоростью или просто показывалось с той же скоростью? В 99% случаев вы хотите, чтобы он работал с одинаковой скоростью.

Теперь есть две проблемы: ускорение вашего приложения или замедление его.

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

Замедление вашего приложения довольно легко. У вас есть два варианта сна или «занят ожидания». Это в основном зависит от вашей целевой частоты кадров для симуляции. Если ваша симуляция превышает 50 мс, вы можете спать. Проблема в том, что во время сна вы зависите от планировщика процессов, и он работает в средней системе со степенью детализации 10 мс.

В играх ожидание не так уж плохо. Что вы делаете, вы обновляете симуляцию и визуализируете свой кадр, а затем используете накопитель времени для следующего кадра. При рендеринге кадров без симуляции вы интерполируете состояние, чтобы получить плавную анимацию. Очень хорошая статья на эту тему может быть найдена на http://gafferongames.com/game-physics/fix-your-timestep/.

0 голосов
/ 03 марта 2010

Я программист игр и делал это много раз.

Большинство игр запускают ИИ с фиксированными приращениями, например, 60 Гц. Кроме того, большинство из них синхронизируются с обновлением монитора, чтобы избежать разрыва экрана, поэтому максимальная скорость будет равна 60, даже если машина была действительно быстрой и могла делать 1000 кадров в секунду. Так что, если машина работала медленно и работала со скоростью 20 кадров в секунду, она вызывала бы функцию обновления ai 3 раза за рендер. Это позволяет решить проблему ошибок округления с небольшими значениями, а также делает ИИ детерминированным на нескольких машинах, поскольку частота обновления ИИ не зависит от скорости машины (необходимо для многопользовательских онлайн-игр).

...