Я использую 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
<activity android:name=".UIThread"
android:screenOrientation="landscape"
android:configChanges="orientation">
Я использую onResume()
вместо surfaceCreated()
для новой темы. И я установил логическое значение surfaceCreated
, чтобы знать, что onResume()
появляется при первом создании приложения или из ситуации «выключения экрана».
Таким образом, нить умирает каждый раз, когда вызывается onPause()
. Кажется, это хорошая практика. Еще один способ остановить поток и возобновить его снова - синхронизировать объект и вызвать wait / notify. Но я не знаю, лучше это или нет.
Есть ли лучший способ управления потоком рендеринга?