Непостоянное время в игровом цикле Android

Я разрабатываю игру для Android. Поскольку это моя первая игра для Android, я хотел, чтобы она была максимально простой. Я хочу отобразить последовательность случайных чисел (по одному). Между каждой парой чисел должно пройти заданное количество времени (в настоящее время я использую 500 мс).

Проблема в том, что задержка между двумя числами непостоянна (ни на эмуляторе, ни на реальном устройстве под управлением Android 2.3.4). Большую часть времени цифры изменяются с постоянной скоростью, но иногда появляется значительная и заметная задержка (даже достигающая более 1 секунды).

Я включаю части кода, отвечающие за рендеринг чисел. Я использую SurfaceView, и следующая часть — это метод run() игрового цикла, реализованный в дополнительном потоке:

while (!mDone) {
    long now = System.nanoTime();
    if (mLastTime == -1) mLastTime = now;
    long delta = now - mLastTime;
    if (delta > 500000000) {
        mNumberBox.update();
        mLastTime = now;
    }

    if ((w > 0) && (h > 0)) {
        Canvas canvas = mSurfaceHolder.lockCanvas();
        if (canvas != null) {
            mRenderer.drawFrame(canvas);
            mSurfaceHolder.unlockCanvasAndPost(canvas);
        }
    }
}

mNumberBox.update() обновляет число, которое нужно нарисовать, и предполагается, что оно вызывается каждые 500 мс. Его код очень прост:

mCurrNumber = mRand.nextInt(9) + 1;

mRenderer.drawFrame() отвечает за отображение числа на экране. Вот код:

canvas.drawRoundRect(mBoxRect, 45, 45, mBoxPaint);
String numStr = String.format("%d", mCurrNumber);
Rect bounds = new Rect();
mTextPaint.getTextBounds(numStr, 0, 1, bounds);
int height = bounds.bottom - bounds.top;
canvas.drawText(numStr, canvas.getWidth() / 2, canvas.getHeight() / 2 + height / 2, mTextPaint);

Я профилировал код, выполняя приложение примерно 260 секунд. Вот результаты, которые я нашел:

  • Количество итераций цикла run(): 16765
  • Среднее время на итерацию: 16 мс
  • Максимальное время для всех итераций: 97 мс

Практически 100% этого времени уходит на drawFrame(), особенно на вызовы lockCanvas() и unlockCanvasAndPost(), которых я не могу избежать.

Самое странное, что максимальное время для всех итераций составило 97 миллисекунд, что намного меньше, чем задержки, которые я замечаю при выполнении игры. Так что почему-то я считаю, что проблема может быть не в коде игрового цикла, а, возможно, в конфигурации или еще где-то. Есть ли у кого-нибудь совет?


person betabandido    schedule 07.01.2012    source источник
comment
w и h — это всего лишь две переменные, содержащие ширину и высоту холста. Во время создания представления они могут быть не инициализированы и, следовательно, равны нулю, но после этого их значения не меняются. Следовательно, условная проверка всегда истинна.   -  person betabandido    schedule 07.01.2012


Ответы (2)


Вы должны разработать свой компонент для рисования чисел, и все.

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

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

Более того, ваш компонент игровой логики должен делать меньше ожиданий. Подождите 100 мс и каждый раз проверяйте, не прошло ли больше 500 мс после выбора последнего номера.

person Snicolas    schedule 07.01.2012
comment
На самом деле игровой цикл никогда не блокируется (т. е. рендеринг происходит настолько быстро, насколько это возможно для аппаратного обеспечения). Я знаю, что это может быть не самое лучшее с точки зрения потребления батареи, но оно должно давать наилучшую производительность. Таким образом, цикл делает то, что вы сказали в последнем абзаце (за исключением того, что он не блокируется даже на 100 мс). - person betabandido; 07.01.2012

Попробуй это:

Используйте задачу таймера с 500 мс и обновите свой mNumberBox и аннулируйте свою поверхность.

В классе поверхности в onDraw() вызовите mRenderer.onDraw(canvas).

Это решение не будет потреблять много ресурсов процессора, будет очень экономичным и будет очень отзывчивым.

Вы также увидите, что ваши проблемы с задержкой будут решены.

person eagle.android.2012    schedule 10.10.2012