#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() для большей точности?