Я использую 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
Я использую onResume ( )
вместо surfaceCreated ()
в новый поток. И я установил логическое значение surfaceCreated
, чтобы знать, что onResume ()
исходит от первого создания приложения или от ситуации «выключен экран».
Таким образом, поток умирает каждый раз, когда вызывается onPause ()
. Кажется, это хорошая практика. Другой способ позволить потоку остановиться, а затем возобновить его снова - это синхронизировать объект и вызвать ожидание / уведомление. Но я не знаю, лучше это или нет.
Есть ли лучший способ управлять потоком рендеринга?