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

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

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

[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] Если вы нажали кнопку "power" или "red phone", или телефон простаивает в течение нескольких минут, это будет состояние 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;
    }
}

манифеста

<activity android:name=".UIThread"
          android:screenOrientation="landscape"
          android:configChanges="orientation">

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

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

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

Ответы

Ответ 1

решение здесь

public void surfaceCreated(SurfaceHolder holder){

            if (plot_thread.getState() == Thread.State.TERMINATED) {
                plot_thread = new WaveformPlotThread(getHolder(), this);
                plot_thread.setRunning(true);
                plot_thread.start();
            }
            else {
                plot_thread.setRunning(true);
                plot_thread.start();
            }
        }

Ответ 2

Я надеюсь, что это поможет

@Override
public void surfaceCreated(SurfaceHolder holder) {

   //if it is the first time the thread starts
   if(thread.getState() == Thread.State.NEW){
    thread.setRunning(true);//riga originale
    thread.start();//riga originale
   }

   //after a pause it starts the thread again
   else
   if (thread.getState() == Thread.State.TERMINATED){
       thread = new MainThread(getHolder(), this);
       thread.setRunning(true);
       thread.start();  // Start a new thread
       }
   }

и этот

    @Override
    protected void onPause() {
    Log.d(TAG, "Pausing...");
    MainThread.running=false;//this is the value for stop the loop in the run()
    super.onPause();
    }

Ответ 3

Я занимался той же проблемой. Я изучаю разработку игр на Android, а также основал свой первый проект на примере Lunar Lander. Я обнаружил, что проект SpriteMethodTest, созданный Крисом Прюэтом, реализует гораздо лучший подход с точки зрения управления потоками. Тем не менее, все об использовании уведомлений и методов ожидания. Я не мог сказать, лучше ли это, чем ваше решение, или нет.