libgdx и kryonet: потоки

Я пытаюсь разработать игру для платформы Android, используя библиотеку Libgdx. Для сети я использую библиотеку Kryonet.

Я хочу изменить экран, когда буду уверен, что мое приложение подключено к моему серверу.
Сетевая часть работает, но у меня проблема с потоками: это поток Kryonet, который выполняет OpenGL, а не поток Libgdx:

public class MyGdxGame extends Game {
    public static int UDP_PORT = 55555, TCP_PORT = 55556;
    private Client client;

    @Override
    public void create() {
        /*
         * client connection
         * etc ...
         */
        client.addListener(new Listener() {
            private int nb = 0;

            @Override
            public void received(Connection connection, Object data) {
                super.received(connection, data);
                nb++;
                if (nb == 5) {
                    MyGdxGame.this.setSecondScreen();
                }
            }
        });
        setScreen(new First(this, client));
    }

    protected void setSecondScreen() {
        setScreen(new Second(this, client)); //This part should be executed by Libgdx thread ?!     
    }

Обратите внимание, что First и Second являются классами Screen, которые просто рисуют изображение.

У меня есть это исключение, когда я пытаюсь запустить Второй экран: Исключение в потоке "Клиент" java.lang.RuntimeException: В текущем потоке не найден контекст OpenGL.

Могу ли я заставить поток LibGDX выполнять инструкции? Возможен ли другой подход?

Спасибо, Джонатан


person Jonathan    schedule 09.05.2013    source источник


Ответы (1)


В Libgdx только один поток (поток, который выполняет обратные вызовы жизненного цикла приложения) имеет допустимый контекст OpenGL и может вызывать вызовы OpenGL. Вы можете опубликовать Runnable в потоке GDX из других ваших потоков, чтобы заставить его выполнять вещи от имени других потоков. Опубликованные runnables будут выполнены до запуска следующего обратного вызова рендеринга. См. Gdx.app .postRunnable()

В вашем случае вы можете сделать что-то вроде этого:

@Override
public void received(Connection connection, Object data) {
   super.received(connection, data);
   nb++;
   if (nb == 5) {
      final MyGdxGame g = MyGdxGame.this;
      Gdx.app.postRunnable(new Runnable() {
         public void run() {
            g.setSecondScreen();
         });
   }
}

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

person P.T.    schedule 09.05.2013
comment
Круто, я этого не знал. Я стараюсь как можно скорее. Ошибка Это именно то, что я хочу. Runnable должен выполняться только один раз, в начале игры, поэтому я полагаю, что могу использовать ваш код с распределением. Спасибо! - person Jonathan; 10.05.2013