Цикл Android Game с использованием потока postdelayed ()

Я подумал, что поступил сообразительно, используя этот код для цикла игрового потока вместо обычного цикла while(running):

    @Override
    public void run() {
        Log.d(TAG, "+ run()");
        final long [] old = new long [] { System.currentTimeMillis() };
        Log.w(TAG,"Start time=" + old[0]);

        Thread loop = new Thread() {
            public void run() {
                if( running ) {
                    Canvas canvas = null;
                    try {
                        canvas = mSurfaceHolder.lockCanvas(null);
                        long t = System.currentTimeMillis();
                        Log.w(TAG,"Loop time=" + t + ", delta=" + (t-old[0]));
                        old[0] = t;
                        synchronized( mSurfaceHolder ) {
                            mGame.update();
                            mGame.onDraw(canvas);
                        }
                    }
                    finally {
                        // Do this in finally so that if an exception is thrown
                        // we don't leave the Surface in an inconsistent state
                        if( canvas != null ) {
                            mSurfaceHolder.unlockCanvasAndPost(canvas);
                        }
                    }
                    Log.i(TAG, "Posting thread with delay " + interval + " milliseconds");
                    handler.postDelayed(this, interval);
                }
            };
        };
        Log.i(TAG, "Posting thread with no delay");
        handler.post(loop);
        Log.d(TAG, "- run()");
    }

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

Что произвело этот журнал (частичный):

03-09 12:51:22.665: D/GameLoop(3116): + run()
03-09 12:51:22.665: W/GameLoop(3116): Start time=1362826282665
03-09 12:51:22.665: I/GameLoop(3116): Posting thread with no delay
03-09 12:51:22.665: D/GameLoop(3116): - run()
03-09 12:51:22.687: W/GameLoop(3116): Loop time=1362826282691, delta=26
03-09 12:51:22.687: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:22.687: D/GameView(3116): + onWindowFocusChanged(hasWindowFocus:true)
03-09 12:51:22.687: D/GameLoop(3116): + resume()
03-09 12:51:22.687: D/GameLoop(3116): - resume()
03-09 12:51:22.687: D/GameView(3116): - onWindowFocusChanged()
03-09 12:51:22.745: W/GameLoop(3116): Loop time=1362826282745, delta=54
03-09 12:51:22.745: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.284: W/GameLoop(3116): Loop time=1362826283284, delta=539
03-09 12:51:23.285: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.366: W/GameLoop(3116): Loop time=1362826283367, delta=83
03-09 12:51:23.366: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.425: W/GameLoop(3116): Loop time=1362826283426, delta=59
03-09 12:51:23.425: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.495: W/GameLoop(3116): Loop time=1362826283504, delta=78
03-09 12:51:23.505: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.555: W/GameLoop(3116): Loop time=1362826283561, delta=57
03-09 12:51:23.555: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.615: W/GameLoop(3116): Loop time=1362826283622, delta=61
03-09 12:51:23.615: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.675: W/GameLoop(3116): Loop time=1362826283675, delta=53
03-09 12:51:23.686: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.749: W/GameLoop(3116): Loop time=1362826283750, delta=75
03-09 12:51:23.749: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.807: W/GameLoop(3116): Loop time=1362826283808, delta=58
03-09 12:51:23.807: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.875: W/GameLoop(3116): Loop time=1362826283884, delta=76
03-09 12:51:23.875: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:23.936: W/GameLoop(3116): Loop time=1362826283938, delta=54
03-09 12:51:23.946: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:24.006: W/GameLoop(3116): Loop time=1362826284006, delta=68
03-09 12:51:24.006: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:24.065: W/GameLoop(3116): Loop time=1362826284065, delta=59
03-09 12:51:24.065: I/GameLoop(3116): Posting thread with delay 50 milliseconds
03-09 12:51:24.126: W/GameLoop(3116): Loop time=1362826284126, delta=61
03-09 12:51:24.126: I/GameLoop(3116): Posting thread with delay 50 milliseconds

Я знаю, что пост-задержка неточна, но здесь каждый раз она опаздывает, чем требуемые 50 милли.
Мой mGame.update() метод сейчас пуст, а mGame.onDraw() рисует 2 прямоугольника, одну строку и один текст. Считаю, что он не особо тяжелый, и все равно не может угнаться за 20FPS.

Как они отрисовывают игры с интенсивной графикой, такие как асфальт, и поддерживают высокий FPS?

Предостережение: это работает в эмуляторе под управлением механизма Intel HAXM, который работает настолько быстро, насколько это возможно в эмуляторе.

Чтобы прояснить, о чем я спрашиваю, это:

Что мне нужно сделать, чтобы достичь высокого FPS в игровом цикле (не требующем больших вычислительных ресурсов)?

Примечание: я знаю, что задержка будет не менее 50 милли. Но меня всегда беспокоят две вещи: второй вызов занимает несколько сотен милли, а точность варьируется от 20 до 10 кадров в секунду, и меня беспокоит, что движение на экране не будет выглядеть равномерным.

Редактировать
Просто для проверки я уменьшил интервал до 20 милли (50 кадров в секунду), а дельта осталась в диапазоне 50-70 милли (эмулятор).
Я увеличил интервал до 83 милли ( 12FPS), а дельта - 87-93 (эмулятор).
Я установил приложение в ASUS TF201 под управлением Nvidia quadcore, и дельта не сильно изменилась.

Вывод таков, что для игр, использующих Canvas и циклы обновления-отрисовки, я не могу подняться выше 20FPS. Разочарование.


person ilomambo    schedule 09.03.2013    source источник


Ответы (2)


Я думаю, они используют OpenGL вместо Canvas

Почему вы используете синхронизацию в

synchronized( mSurfaceHolder )
person M G    schedule 09.03.2013
comment
Я использую синхронизацию, чтобы убедиться, что это единственный код, касающийся SurfaceView. ::: Большинство примеров игровых циклов в сети используют цикл while() с телом synchronize(), когда я изменил свой код, я оставил его там, потому что я не совсем уверен, какие другие потоки выполняются в системе, и мог бы попытаться получить доступ к тому же самому SurfaceView (например, сборка мусора (?)) - person ilomambo; 09.03.2013
comment
by canvas = mSurfaceHolder.lockCanvas(null); только этот поток может изменять этот холст - person M G; 09.03.2013
comment
Я так не думаю. Используя холст, вы не добьетесь хорошей производительности. Вместо этого используйте OpenGL - person M G; 09.03.2013

Чувак, я использую холст и получаю кадры 15 мс, задержку от 1 до 4 мс, с 200 спрайтами, все растровые изображения нарисованы на синхронизированном холсте. не уверен, в чем заключается ваша сделка, но я только что посмотрел демонстрацию api lunarlander год назад, и оттуда все было просто подливкой. одна строка в манифесте включает аппаратное ускорение, и забудьте об эмуляторах, работающих со всем, что вам нужно, чтобы быть быстрым и графическим. Я не буду лгать и говорить, что это самая простая платформа для разработчиков игр (это примерно худшая ИМО), но дайте ей немного времени, и вы разберетесь.

person dudeman    schedule 09.03.2013