15

LunarLander のような構造に基づくゲームを開発するために、SurfaceView とレンダリング スレッドを使用しています。

しかし、私は多くの問題に直面しました。ここでそれらをすべて指摘したいと思います。ゲームを開発したい人が、もう苦労する必要がなくなることを願っています。そして、私はまだアンドロイドに慣れていないので、構造についてより良いアイデアを持っている人なら誰でも経験を共有できます:)

[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の画面の向きのバグで述べたように)

これらの問題を修正するための私のコードは次のとおりです。

UIスレッド

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());
        }
    }
}

ゲームビュー

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()そして、アプリケーションが初めて作成されたとき、または「画面オフ」の状況から来るsurfaceCreatedことを知るために、ブール値を設定しました。onResume()

そのため、毎回スレッドダイonPause()が呼び出されます。良い習慣のようです。スレッドを停止して再開するもう 1 つの方法は、オブジェクトを同期し、wait / notify を呼び出すことです。しかし、それが良いか悪いかはわかりません。

レンダリング スレッドを制御するより良い方法はありますか?

4

3 に答える 3

3

それが役立つことを願っています

@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();
    }
于 2013-06-13T19:03:32.587 に答える
3

解決策はここにあります

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();
            }
        }
于 2012-04-29T19:36:45.847 に答える
1

私は同じ問題を扱ってきました。私は Android でのゲーム開発について学んでおり、最初のプロジェクトは Lunar Lander の例に基づいています。Chris Pruett によって作成されたSpriteMethodTestプロジェクトでは、スレッド管理に関してはるかに優れたアプローチが実装されていることがわかりました。ただし、notify メソッドと wait メソッドを使用することがすべてです。それがあなたのソリューションよりも優れているかどうかはわかりませんでした。

于 2011-01-18T12:06:07.030 に答える