Программирование с помощью SurfaceView и стратегии потоков для разработки игр
Я использую SurfaceView и поток рендеринга для разработки игры на основе структуры, такой как LunarLander.
Однако у меня возникло много проблем, и здесь я хочу указать на них все. Я желаю, чтобы любой, кто хочет развить игру, больше не должен бороться с ними. И любой, кто лучше разбирается в структуре, может поделиться своим опытом, потому что я все еще новичок в андроиде и очень хочу учиться:)
[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] Если вы нажали кнопку "power" или "red phone", или телефон простаивает в течение нескольких минут, это будет состояние 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;
}
}
манифеста
<activity android:name=".UIThread"
android:screenOrientation="landscape"
android:configChanges="orientation">
Я использую onResume()
вместо surfaceCreated()
для нового потока. И я установил boolean surfaceCreated
, чтобы знать, что onResume()
поступает с момента создания приложения в первый раз или происходит из ситуации "выключить экран".
Таким образом, нить умирает каждый раз, когда вызывается onPause()
. Кажется, это хорошая практика. Другой способ, чтобы поток остановить, а затем возобновить снова, это синхронизировать объект и вызвать wait/notify. Но я не знаю, что это лучше или нет.
Есть ли лучший способ управлять потоком рендеринга?
Ответы
Ответ 1
решение здесь
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();
}
}
Ответ 2
Я надеюсь, что это поможет
@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();
}
Ответ 3
Я занимался той же проблемой. Я изучаю разработку игр на Android, а также основал свой первый проект на примере Lunar Lander. Я обнаружил, что проект SpriteMethodTest, созданный Крисом Прюэтом, реализует гораздо лучший подход с точки зрения управления потоками. Тем не менее, все об использовании уведомлений и методов ожидания. Я не мог сказать, лучше ли это, чем ваше решение, или нет.