Нестабильная скорость gameloop

#java #android #opengl-es #timing

#java #Android #opengl-es #время

Вопрос:

Я делаю простую прорывную игру в OpenGL (-es) на Android. Изначально у меня было обновление состояния игры и вызовы рисования в одном цикле: onDrawFrame. Теперь я решил разделить их, оставив только вызовы рендеринга в onDrawFrame, а управление игровым состоянием осуществлялось в другом потоке:

 public void run() {
    Log.d("GameLogicThread", "GameLogicThread started");
    final long UPDATE_INTERVAL = 1000000000 / 30;
    long endingTime;
    int timeElapsed;
    long startingTime = System.nanoTime();

    while (!running) {// wait for it...

    }
    while (running) {
        endingTime = System.nanoTime();
        timeElapsed = (int) (endingTime - startingTime);
        Log.d("timeElapsed",Integer.toString(timeElapsed));
        if (timeElapsed < UPDATE_INTERVAL-timeElapsed){
            try {
                Thread.sleep(timeElapsed);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        startingTime = System.nanoTime();
        Game.updateGame(timeElapsed);
    }
  

Редактировать
Теперь я изменил код следующим образом ^^, но он по-прежнему работает некорректно..

Что-то в самом цикле не так, или я должен смотреть снаружи (вероятно, нет, поскольку он отлично работал до перемещения кода). Что мне делать?

Комментарии:

1. «поскольку он отлично работал до перемещения кода» <- так что же изменилось?

2. Сначала у меня был код для обновления состояния игры (например, положения объектов), подобный приведенному выше, в моем цикле рисования с именем onDrawFrame (посмотрите его, он вызывается автоматически OpenGL), и теперь он у меня есть в отдельном потоке, из которого вы можете увидеть run()метод выше…

3. @pst Я думаю, что под «работал отлично» он подразумевает, что истекшее время всегда было> 0, что не лучше. Теперь он заставил его работать намного быстрее.

Ответ №1:

Есть несколько логических ошибок, которые указаны / обсуждены в комментариях ниже:

     endingTime = System.currentTimeMillis();
    timeElapsed = (int) (endingTime - startingTime);
    // Why is the "elapsed" time being waited? Hmm.
    // If *any* wait is being done (I'd recommend sleep(0) for starters)
    // it should be the MAXIMUM desired cycle time MINUS the
    // currently used cycle time (MINUS some fudge factor).
    if (timeElapsed < UPDATE_INTERVAL) // I dislike hanging blocks...
        try {
            Thread.sleep(timeElapsed);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    startingTime = System.currentTimeMillis();
    // The game needs to know the TOTAL time elapsed since
    // the last update, not the time "until before the yield".
    // This will likely be passed fictitiously small values as
    // it is only time the the LAST updateGame took to run.
    Game.updateGame(timeElapsed);
  

Я бы никогда не ожидал, что время истекло (передано в updateGame) ниже, скажем, 10 мс с sleep(...) исправленными вычислениями времени.

Однако он может не иметь требуемой точности (увеличение минимальной длины цикла, скажем, до 1/30 секунды, что было бы результатом фиксированной математики, сделало бы это менее важным): см. Ответ Cristian Vrabie для предложения по таймеру с более высоким разрешением. (Могут быть некоторые лучшие сторонние альтернативы, разработанные специально для этого — есть в «обычной» Java — я не программирую Android;-)

Счастливого кодирования.

Комментарии:

1. Правильно! Я пропустил тот факт, что он прошел время до выхода. Говоря о доходности, это может быть лучше, чем sleep (0), и нет исключений для перехвата: goo.gl/B4AzF Не уверен, что Java не делает этого уже под прикрытием 0 sleep, хотя.

2. Теперь я (немного) изменил свой приведенный выше код, но он все еще не разрешен. Кроме того, есть ли у вас какой-нибудь хороший пример такой сторонней альтернативы?

3. @user717572 Код обновления по-прежнему неверен. Пожалуйста, обратитесь ко всем комментариям выше. Что означает / подразумевает каждый комментарий? Как можно решить (множественные) проблемы? И что, черт timeElapsed < UPDATE_INTERVAL-timeElapsed возьми, предполагается делать?

Ответ №2:

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

Вы пробовали использовать nanoTime() для большей точности?