Android游戏开发之SurfaceView与游戏开发

来源:互联网 发布:prezi for mac 中文版 编辑:程序博客网 时间:2024/05/29 13:04

Android中SurfaceView,是不使用游戏引擎,开发一款游戏的常用view控件。

SurfaceView常常被用来显示那些更新速度比较快(这个速度通常人眼无法识别)的图像,常常被用来显示照相机的当前效果,视频的播放,游戏界面的播放。

SurfaceView的创建:

继承SurfaceView就可以使用构造方法创建了。

所要从新写的方法也只不过一个构造方法,这里使用的构造常常有两种,一种使用只有一个参数的构造方法,参数为context,如果使用这样的构造方法,则创建SurfaceView的Activity不能加载layout文件夹中的xml文件,只能加载new出来的view如

public class GameMainActivity extends Activity {    public static GameView Game;    public static AssetManager assets;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Assets.mContentResolver=getContentResolver();               Game=new GameView(GameMainActivity.this);        setContentView(Game);             assets=getAssets();    }}

这里的GameView继承自SurfaceView

如果使用两个参数的构造方法:

Context context, AttributeSet attrs
则可以将自己View类当做Activity布局文件中的一个空间,当布局文件显示时会自动调用这个构造方法,第二参数用于返回相应的指令给View。

但是这里建议使用第一个方法构造,因为在游戏中的界面跳转与外部Activity的跳转逻辑完全不同,所以在布局文件中加载会有一定的弊端。但是好处是这样可以使用Android封装好的控件(如button)。


SurfaceView有一个特点:

他并不是当Activity创建 就会可以调用的,里面的那些控件,并不是真的控件,当Activity创建完成就可以使用了,而是当SurfaceView创建,并出现在屏幕上之后才可以开始绘画(即伪控件的加载)。

这时就需要一个监听器监听SurfaceView的创建,改变和销毁。

使用监听器

SurfaceHolder.Callback
这里要实现这个接口,重写其中的三个主要方法:

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) public void surfaceDestroyed(SurfaceHolder holder) 这三个方法代表了SurfaceView生命周期,注意只有在这三个声明周期中才可以进行其中的操作,在Activity中的操作要与之区分。当创建时自动调用createed和changed方法,在home键,back键返回时调用destroyed方法,但是注意home键返回再回来依次调用created方法,和changed方法,但是back键返回再回来就会调用构造方法和created方法,changed方法。
设置监听时要先初始化SurfaceView的管家类SurfaceHolder,通过在View中调用父类SurfaceView的方法getholder就可以简单的获取管家。
再使用holder.addCallBack()进行设置监听声明周期

SurfaceView的绘画,一般在线程中进行绘画操作。
绘画之前要得到View的主画布,通过holder来实现,这时体现了如果线程在View类中就可以很好地得到主画布,所以GameView通常可以实现Runnable接口。
Canvas的得到使用holder.lockCanvas()的返回值得到,得到主画布后就可以使用canvas中的各种绘画方法进行绘画了。
如果想不断地更新,就要使用循环,也就是死循环进行一遍一遍地render和update进行绘画,与逻辑更新,这里就是游戏主循环。

SurfaceView的事件监听使用OnTouchListener和MotionEvent,这里由于不能使用Android的诸多控件,只能使用这种触控事件。诸多组件也是画上去的再通过坐标的对比,进行事件的响应。
这里由于游戏代码所涉及的类诸多,只展示一个Demo,一个画板的实现(没有适配不同机型)
public class MyView extends SurfaceView implements Runnable,SurfaceHolder.Callback,View.OnTouchListener {    Context main;    SurfaceHolder holder;//主holder    Canvas canvas;//主画布    Paint p;    Thread t;    Bitmap buffer=null;//二级缓存    Path mpath;//触控中的轨迹    float startX;    float startY;    Rect window;    Rect bufferRect;    boolean run=false;    public MyView(Context context) {        super(context);        init(context);        setOnTouchListener(this);    }    private void init(Context context){        holder=getHolder();        holder.addCallback(this);//勿忘addcallback        this.main=context;        p=new Paint();        p.setAntiAlias(true);//消除锯齿        p.setStyle(Paint.Style.STROKE);//设置画笔风格        p.setAlpha(255);//画笔的不透明度        p.setStrokeWidth((float)2);//设置笔触宽度        p.setColor(Color.WHITE);        mpath=new Path();        buffer= Bitmap.createBitmap(1440,2256, Bitmap.Config.ARGB_8888);//很重要创建二级缓存的必要方法        t=new Thread(this);    }    @Override    public void run() {    while(run){        canvas=holder.lockCanvas();        window=canvas.getClipBounds();        Canvas c=new Canvas(buffer);        c.drawRect(window,p);        p.setColor(Color.rgb(new Random().nextInt(255),new Random().nextInt(255),new Random().nextInt(255)));        c.drawPath(mpath,p);        bufferRect=new Rect(0,0,buffer.getWidth(),buffer.getHeight());        canvas.drawBitmap(buffer,bufferRect,window,new Paint());        holder.unlockCanvasAndPost(canvas);        try {            Thread.sleep(50);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    }    @Override    public void surfaceCreated(SurfaceHolder holder) {     run=true;        Log.i("Created", "surfaceCreated: ");    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        Log.i("Changed", "surfaceChanged: ");         t=new Thread(this);         t.start();    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        run=false;        try {            t.join();        } catch (InterruptedException e) {            e.printStackTrace();        }        Log.i("Destroyed", "surfaceDestroyed: ");    }    private void onTouchDown(MotionEvent event){        startX=event.getX();        startY=event.getY();        mpath.reset();        mpath.moveTo(startX,startY);    }    private void onTouchMove(MotionEvent event){        float touchX=event.getX();        float touchY=event.getY();        float dx=Math.abs(touchX-startX);//移动的距离        float dy =Math.abs(touchY-startX);//移动的距离        if(dx>3||dy>3){            float cX=(touchX+startX)/2;            float cY=(touchY+startY)/2;            mpath.quadTo(startX, startY, cX, cY);//绘制贝塞尔曲线            startX=touchX;            startY=touchY;//改变开始绘制的点        }//这里巧妙地进行筛选过于短的移动    }    @Override    public boolean onTouch(View v, MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:          this.onTouchDown(event);                break;            case MotionEvent.ACTION_MOVE:          this.onTouchMove(event);                break;            case MotionEvent.ACTION_UP:                break;        }        return true;    }}





0 0
原创粉丝点击