植物大战僵尸一:多线程修改UI界面,游戏必备API

时间:2021-12-08 20:31:36

                    本博文适合刚刚学完android基础准备做做项目实战一下的人看,在我的博文中,我会将这个游戏的开发过程讲得非常详细,所以非常容易理解,植物大战僵尸这个游戏我会出一系列的博文详细解释,所以有兴趣的人可以持续跟进哦!

             一:制作游戏必备的三个API

                     (1)SurfaceView:类似于于展示电影的屏幕,这个API是一个非常强大的API,它的内部是一个双缓冲机制,显示界面的效率非常快。那么什么

是双缓冲机制呢?

        例如有一个A和一个B两个线程,

                 A:如果A先加载数据,加载数据完成之后显示界面

             

                 B:同时B先显示界面,显示完成时候B再加载数据

这个双缓冲机制的意思就是这两个线程可以同时存在,一个加载数据,另一个显示界面,这样的交叉加载显示会是游戏的运行效率非常快。

                SurfaceView有两个主要的功能:

                             ①提供一个可以绘制的surface

                             ②可以在多个线程同时修改界面,如果想要在多个线程中修改界面,就要注意两个前提条件:

                                     1.将所有的surface在主线程中被调用

                                     2..将所有的surfaceHolder.callback在主线程中被调用

         

                    

                    (2)surfaceHolder:类似于展示电影的内容,
                    (3)Thread:类似于工作人员,
                 
                 二:多线程同时修改界面UI的前提:
                            (1)实现调用SurfaceView API的两个前提 
                           第一步就是创建一个GameUI类,用于进行游戏界面的更新,那么 要实现在多个线程中同时修改界面,我们必须要保证surface和
         surfaceHolder.callback 在主线程中被调用,要实现这个前提,我们可以将GameUI 继承surface类,并实现surfaceHolder.callback,然后我们
         再在 主函数中调用GameUI,然而 要想要 surfaceHolder.callback生效,我们必须要调用一下surfaceHolder.addcallback 方法,所以我们在刚刚
         的构造方法 中使用getHolder()方法得到一个surfaceHolder 对象,然后我们再用这个对象调用。

             注意: 当软件运行起来,我们的界面是一片黑色,现在我们 看日志,当软件运行起来的时候我们的LogCat中打印出了surfaceCreated,             surfaceChanged 的日志,当我们点击返回键的时候会调用销毁的那个方法,但是当我们点击Home键的时候 ,日志中同样会打印销毁的方法,然
后重新进入软件的时候又会重新打印一次创建和改变的 方法,这是因为surface对我们的CPU和内存消耗非常大,所以我们的google工程师为了
约资源,就设置了这样一个机制,每次重新进入的时候都要重新加载。
      
                           (2)创建线程的两个条件:  
            (1)我们必须要保证线程是有效的,怎么保证线程是有效的呢?
       就是我们必须保证我们的线程在  surfaceHolder.callback.surfaceCreated() surfaceHolder.callback.surfaceDestroyed()方法之间,意思就是
      我们必须保证 我们的线程必须在   surfaceHolder.callback.surfaceCreated()之后创建,在 surfaceHolder.callback.surfaceDestroyed()之前停止,
      就相当于我们的线程作用 范围在这两个方法之间,这样才是一个有效的线程,这样才能够去修改界面。
          
           (2) 这样我们 再去新建一个RenderThread内部类,实现Thread,这样我们就创建了一个新的线程,然后我们在surfaceCreated()方法中新建
一个 RenderThread对象,再开启线程,在surfaceDestroyed中销毁,由于stop方法存在一些安全隐患,所以google工程师已经不在建议我们使用
stop方法去 停止线程了,现在我们可以通过一个线程循环来停止线程,通过循环停止线程很简单,我们现在 RenderThread的run方法中新建一个while(true),然后在新建一个flag标记,这个标记代表 一个线程运行的标记,然后在开启线程的时候将标记变成true,然后在关闭线程的时候直接将
标记变成false就关闭线程了。
  
        GameUI类:
package game.qiu.com.game;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * 这是游戏的UI类
 * 如果想让SurfaceHolder.Callback生效,我们必须要去调用
 * SurfaceHolder.addCallback(SurfaceHolder.Callback)
 * 这样的一个方法,这样就可以保证实现SurfaceHolder.Callback的这
 * 三个方法能够生效
 */
public  class GameUI extends SurfaceView implements SurfaceHolder.Callback{
     private RenderThread renderThread;
    private boolean flag;// 线程运行的一个标记

    public GameUI(Context context) {
        super(context);
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);//保证surfaceCreated,surfaceChanged,surfaceDestroyed能够生效
    }
    private class RenderThread extends Thread{
        @Override
        public void run() {
           while(flag){

           }
        }
    }
    //当surface创建的时候调用
    @Override
        public void surfaceCreated(SurfaceHolder holder) {
        Log.d("surfaceCreated----->","surface创建的时候调用");
        renderThread = new RenderThread();
        flag=true;
        renderThread.start();//开启线程.....
    }

    //当surface的大小改变的时候调用,一般的改变是当前显示的界面的改变
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.d("surfaceCreated----->","surface大小改变的时候调用");
    }

    //当surface销毁的时候调用
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d("surfaceCreated----->","surface销毁的时候调用");
        //renderThread.stop();//停止线程,因为这个方法有一些安全隐患,所以java工程师
        //已经不建议我们通过这个方法去停止线程了,所以我们停止线程都是通过线程的一个循环,让线程自动停止
        flag=false;//停止一个线程只要直接将标记定义为false就行了
    }
}


 MainActivity类:

package game.qiu.com.game;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //因为当前的gameUI是继承了surfacevuew,实现了SurfaceHolder.Callback,
        // 所以我们认为这行代码在
        //主线程中调用了surfaceview,同时也是调用了SurfaceHolder.Callback,
        // 这样就可以在多个线程中同时修改界面
        GameUI gameUI = new GameUI(getApplicationContext());
        setContentView(gameUI);
    }
}

                  

       这样我们就将开发游戏的前提全部写完了,然后我们运行软件,出现的界面是一片全黑,如图:

                                            植物大战僵尸一:多线程修改UI界面,游戏必备API  

         然后我们看到LogCat看到有日志打印,到这里准备工作就全部做完了,自己回去试一试吧!!!
                                     植物大战僵尸一:多线程修改UI界面,游戏必备API   
           
                                     植物大战僵尸一:多线程修改UI界面,游戏必备API