使用SurfaceView编程和用于游戏开发的线程策略

Ste*_*hih 15 multithreading android surfaceview android-activity

我正在使用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();
}
Run Code Online (Sandbox Code Playgroud)

您可以看到,如果线程未终止且函数被调用,则活动崩溃.

[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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

表现

<activity android:name=".UIThread"
          android:screenOrientation="landscape"
          android:configChanges="orientation">
Run Code Online (Sandbox Code Playgroud)

我使用onResume()而不是surfaceCreated()新线程.我设置了一个布尔值surfaceCreated,知道它onResume()来自第一次创建应用程序,或来自"屏幕关闭"情况.

所以每次onPause()调用线程都会被调用.似乎是一个很好的做法.让线程停止然后再次恢复的另一种方法是同步对象并调用wait/notify.但我不知道它是好还是不好.

有没有更好的方法来控制渲染线程?

小智 1

我一直在处理同样的问题。我正在学习 Android 上的游戏开发,并且我的第一个项目也基于 Lunar Lander 示例。我发现Chris Pruett 创建的SpriteMethodTest项目在线程管理方面实现了更好的方法。不过,这都是关于使用通知和等待方法的。我无法判断它是否比您的解决方案更好。