Программирование с помощью SurfaceView и стратегия потоков для разработки игр

Я использую SurfaceView и поток рендеринга для разработки игры, основанной на такой структуре, как LunarLander.

Однако я столкнулся со многими проблемами, и здесь я хочу указать на них все. Я желаю всем, кто хочет разработать игру, больше не придется с ними бороться. И любой, кто имеет лучшее представление о структуре, может поделиться своим опытом, потому что я все еще новичок в android и очень хочу учиться :)

[1] Функцию thread.start () больше не следует называть чем один раз.

Во многих статьях упоминается создание потока при создании поверхности для повторного рендеринга после приостановки активности с помощью метода:

public void surfaceCreated(SurfaceHolder holder) {
    // start the thread here so that we don't busy-wait in run()
    // waiting for the surface to be created
    if (thread.getState() == Thread.State.TERMINATED)
    {
        thread = new LunarThread(getHolder(), getContext(), getHandler());
    }
    thread.setRunning(true);
    thread.start();
}

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

[2] Если вы нажали кнопку «питание» или «красный телефон», или если телефон не используется в течение нескольких минут, действие будет иметь состояние onPause () , но поток все еще работает. Это действительно плохая практика, поэтому мне нужно найти способ, позволяющий остановить поток и запустить его снова, когда onResume () .

[3] Если блокировка экрана - книжная / альбомная, а ваша игра придерживается другой ориентации, блокировка экрана заставила вас «сориентироваться» один раз. Это означает, что нужно начать работу еще раз. Я до сих пор не могу найти решение. (как я упоминал в Ошибка ориентации экрана Android )

Вот мой код для решения этих проблем:

UIThread

public class UIThread extends Activity
{
    private gameView gameview;
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        gameview = (gameView) findViewById(R.id.gameview);
    }
    protected void onPause()
    {
        super.onPause();
        Log.v("MY_ACTIVITY", "onPause");
        gameview.terminateThread();
        System.gc();
    }
    protected void onResume()
    {
        super.onResume();
        Log.v("MY_ACTIVITY", "onResume");
        if (gameview.surfaceCreated == true)
        {
            gameview.createThread(gameview.getHolder());
        }
    }
}

GameView

public class gameView extends SurfaceView implements SurfaceHolder.Callback
{
    boolean surfaceCreated;
    class gameThread extends Thread{}
    public gameView(Context context, AttributeSet attrs)
    {
        super(context, attrs);context.getResources();
            Log.v("MY_ACTIVITY", "gameView");
        surfaceCreated = false;
    }
    public void createThread (SurfaceHolder holder)
    {
            thread = new gameThread(holder);
        thread.run = true;
        thread.start();
    }
    public void terminateThread ()
    {
        thread.run = false;
        try
        {
            thread.join();
        }
        catch (InterruptedException e)
        {
            Log.e("FUNCTION", "terminateThread corrupts");
        }       
    }
    public void surfaceCreated(SurfaceHolder holder)
    {
        Log.v("MY_ACTIVITY", "surfaceCreated");
        if (surfaceCreated == false)
        {
            createThread(holder);
            surfaceCreated = true;
        }
    }
    public void surfaceDestroyed(SurfaceHolder holder) 
    {
        Log.v("MY_ACTIVITY", "surfaceDestroyed");
        surfaceCreated = false;
    }
}

Manifest


Я использую onResume ( ) вместо surfaceCreated () в новый поток. И я установил логическое значение surfaceCreated , чтобы знать, что onResume () исходит от первого создания приложения или от ситуации «выключен экран».

Таким образом, поток умирает каждый раз, когда вызывается onPause () . Кажется, это хорошая практика. Другой способ позволить потоку остановиться, а затем возобновить его снова - это синхронизировать объект и вызвать ожидание / уведомление. Но я не знаю, лучше это или нет.

Есть ли лучший способ управлять потоком рендеринга?

15
задан Community 23 May 2017 в 12:10
поделиться