Подтвердить что ты не робот

Лучший способ отделить логику игры от рендеринга для быстро развивающейся игры для Android с OpenGL?

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

Для меня прыжок с родного кода на С++ на Android Java был не таким уж трудным, но мне больно думать о том, как я могу поддерживать логику отдельно от рендеринга.

Я читал здесь и на других сайтах, которые:

Лучше не создавать для него еще один поток, просто потому, что Android наверняка не будет иметь проблем для обработки.

Значение кода будет примерно таким:

public void onDrawFrame(GL10 gl) {
    doLogicCalculations();
    clearScreen();
    drawSprites();
}

Но я не уверен, что это лучший подход. Поскольку я не думаю, что мне нравится, как это будет выглядеть, если я положу свою логику внутри метода GLRenderer::onDrawFrame. Насколько мне известно, этот метод предназначен только для рисования, и я могу замедлить фреймы, если я поставлю туда логику. Не говоря уже о том, что это вредит концепциям POO в моем понимании.

Я думаю, что использование потоков может быть таким, как я планировал:

Основная деятельность:

public void onCreate(Bundle savedInstanceState) {
    //set fullscreen, etc

    GLSurfaceView view = new GLSurfaceView(this);
    //Configure view

    GameManager game = new GameManager();
    game.start(context, view);

    setContentView(view);
}

GameManager:

OpenGLRenderer renderer;
Boolean running;
public void start(Context context, GLSurfaceView view) {
    this.renderer = new OpenGLRenderer(context);
    view.setRenderer(this.renderer);

    //create Texturelib, create sound system...

    running = true;
    //create a thread to run GameManager::update()
}

public void update(){
    while(running){
        //update game logic here
        //put, edit and remove sprites from renderer list
        //set running to false to quit game
    }
}

и, наконец, OpenGLRenderer:

ListOrMap toDraw;
public void onDrawFrame(GL10 gl) {
    for(sprite i : toDraw)
    {
        i.draw();
    }
}

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

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

Итак, вот мои вопросы:

Какой лучший способ отделить мой игровая логика из рендеринга при использовании OpenGLES? Прошивка моего выражение? Поместите логику в отдельный метод и просто вызовите его из метод рисования?

4b9b3361

Ответ 1

Итак, я думаю, что вы можете пойти сюда двумя способами.

  • Выполнять все обновления из onDrawFrame():. Это похоже на использование GLUT, и Android будет вызывать эту функцию как можно чаще. (Отключите это с помощью setRenderMode(RENDERMODE_WHEN_DIRTY).) Эта функция вызывается в своем потоке (а не в потоке пользовательского интерфейса), и это означает, что вы вызываете свое логическое обновление здесь. Ваша первоначальная проблема заключалась в том, что это кажется немного грязным, и я согласен, но только потому, что функция называется onDrawFrame(). Если он был вызван onUpdateScene(), то обновление логики вполне соответствовало бы этой модели. Но это не самое худшее в мире, оно было спроектировано таким образом, и люди это делают.

  • Дайте логике собственный поток: Это сложнее, так как теперь вы имеете дело с тремя потоками: поток пользовательского интерфейса для ввода, поток рендеринга onDrawFrame() для рисования материала и логический поток для непрерывной работы с данными ввода и рендеринга. Используйте это, если вам нужна действительно точная модель того, что происходит, даже если ваша частота кадров падает (например, точная реакция столкновения). Это может быть концептуально немного чище, но не очень чище.

Я бы порекомендовал # 1. Вам действительно не нужно # 2. Если вы это сделаете, вы можете добавить его позже, я думаю, но большинство людей просто используют первый вариант, потому что аппаратное обеспечение достаточно быстро, поэтому вам не нужно его проектировать.

Ответ 2

Держите свой дизайн максимально простым:) Стандартный (и, возможно, лучший) подход:

public void update(){
    while(running){
        updateAll();
        renderAll();
    }
}

Я хотел бы обратить внимание на некоторые моменты:

  • вам необходимо последовательно вызвать методы update и render, дважды вызывать вызов update
  • если вы предпочитаете многопоточность (я этого не делаю), создайте свои методы, поэтому update записывает данные и render только для чтения
  • Имейте в виду, что OpenGL имеет собственный "поток", поэтому, когда вы вызываете функцию GL, она отправляет только команду OpenGL (кроме glFlush() - она ​​завершает все команды)