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 を呼び出すことです。しかし、それが良いか悪いかはわかりません。
レンダリング スレッドを制御するより良い方法はありますか?