Używam SurfaceView i wątku renderowania do opracowania gry opartej na strukturze takiej jak LunarLander.Programowanie za pomocą SurfaceView i strategii wątków dla tworzenia gier
Jednak stanąłem w obliczu wielu problemów i tutaj chcę je wszystkie wskazać. Chciałbym, aby każdy, kto chce rozwinąć grę, nie musiał już z nią walczyć. I każdy, kto ma lepszy pomysł na strukturę, może dzielić się swoimi doświadczeniami, ponieważ wciąż jestem nowicjuszem dla Androida i chcę się uczyć :)
[1] Funkcja thread.start()
nie powinna być wywoływana więcej niż jeden raz.
Wiele artykułów wymienionych stworzyć wątek, gdy powierzchnia jest stworzony, aby ponownie uczynić po aktywność wstrzymana za pomocą metody:
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();
}
Widać, że jeśli wątek nie jest zakończona, a funkcja ta jest wywoływane, działanie ulega awarii.
[2] Jeśli naciśniesz przycisk "zasilanie" lub "czerwony telefon" lub telefon będzie nieaktywny przez kilka minut, aktywność będzie wynosić onPause()
, ale wątek nadal działa. To jest naprawdę zła praktyka, więc muszę znaleźć sposób na zatrzymanie wątku i zacząć od nowa, gdy onResume()
.
[3] Jeśli blokada ekranu jest ustawiona pionowo/pozioma, a twoja gra jest naklejona na inną orientację, blokada ekranu zmusiła Cię do "orientowania" raz. Oznacza to, że chcesz rozpocząć działanie jeszcze raz. Nadal nie mogę znaleźć rozwiązania. (Jak wspomniano w Android screen orientation bug)
Oto mój kod, aby rozwiązać te problemy:
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;
}
}
Oczywisty
<activity android:name=".UIThread"
android:screenOrientation="landscape"
android:configChanges="orientation">
Używam onResume()
zamiast surfaceCreated()
do nowego wątku. I ustawiłem boolean surfaceCreated
, aby wiedzieć, że onResume()
pochodzi z pierwszej aplikacji lub pochodzi z "wyłączenia ekranu".
Wątek umiera za każdym razem, gdy wywoływana jest nazwa onPause()
. Wydaje się być dobrą praktyką. Innym sposobem na zatrzymanie wątku i ponowne wznowienie jest synchronizacja obiektu i wywołanie oczekiwania/powiadomienie. Ale nie wiem, czy to lepiej, czy nie.
Czy istnieje lepszy sposób kontrolowania wątku renderowania?
Ewentualnie istotne: http://stackoverflow.com/questions/21567641/ powinieneśponownieprzeczytać-widok-powierzchni-mieć-ten-sam-cykl-jak-widzenia-/ 21684399 # 21684399 – fadden