[java] view plain copy
SurfaceView是基于View视图进行扩展的视图类,适用于2D游戏开发,主要特点有:
【1】surfaceView中对于画布的重绘是由一个新的线程去绘制,因此可以处理一些耗时的操作
【2】surfaceView具有双重缓冲机制(view没有)
适用于动态实时更新的画面,比如游戏处理中就算主角啥事不做,旁边流水会动,飞行射击类,抽奖转盘的制作都是动态,需要不断的绘制元素状态,通常view更加适合被动更新的如棋牌类
1、SurfaceView基本框架
SurfaceView使用也比较好掌握,基本框架见如下代码:
[java] view plain copy
- /**
- *
- * @author ELVIS
- *surfaceView 常用编写模式
- */
- public class SurfaceViewTemplate extends SurfaceView implements Callback, Runnable {
- private SurfaceHolder mHolder;
- private Canvas mCanvas;
- private Thread t;// 用于绘制的子线程
- private boolean isRunning; // 线程的控制开关
- public SurfaceViewTemplate(Context context) {
- this(context, null);
- // TODO Auto-generated constructor stub
- }
- public SurfaceViewTemplate(Context context, AttributeSet attrs) {
- super(context, attrs);
- mHolder = getHolder();
- mHolder.addCallback(this); // 添加回调结构
- setFocusable(true);// 可获得焦点
- setFocusableInTouchMode(true);
- setKeepScreenOn(true);// 设置常亮
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- // TODO Auto-generated method stub
- isRunning = true;
- t = new Thread(this);
- }
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- // TODO Auto-generated method stub
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- // TODO Auto-generated method stub
- isRunning = false;
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- while(isRunning){
- draw();//进行绘制
- }
- }
- private void draw() {
- //获取canvas
- try {
- mCanvas = mHolder.lockCanvas();
- if(mCanvas!=null){
- //draw
- }
- } catch (Exception e) {
- /*// TODO Auto-generated catch block
- e.printStackTrace();*/
- }
- finally{
- //canvas 释放
- if(mCanvas!=null){
- mHolder.unlockCanvasAndPost(mCanvas);
- }
- }
- }
- }
这里做一些补充解释
【1】继承SurfaceView
【2】重要的SurfaceHolder,此类提供控制SurfaceView的大小,格式等等,并且监听其状态,因而实现Callback接口重写函数
SurfaceCreated:当surfaceView创建完成时响应的函数
surfaceChanged:当surfaceView状态发生改变时候响应函数
surfaceDetroy:当surfaceView状态摧毁时响应函数
【3】由于surfaceView不同于view,前者需要一个线程来完成更新,框架都差不多,不同的只是draw里面的东西复杂度(这里是核心)
【4】SurfaceView是通过SurfaceHolder来修改其数据,所以在SurfaceView上不再通过onDraw来绘图,而是通过surfaceHolder取到surfaceView的canvas,然后再进行绘制
因此即使重写view的ondraw函数在SurfaceView启动时也不会执行到
【5】在进行绘制的时候一般都是lockCanvas获取canvas同时对画布进行加锁,与之对应的还有unlockCanvasAndPost函数用于解锁画布和提交
2、刷屏方式
这里也是跟view绘图的区别所在。在view绘图中,View类本身提供俩种重绘函数(invalidate和postInvalidate),其内部已经封装了对画布的刷屏操作,所以每次在ondraw中重绘画布永远看不到之前绘制过的图形,但是在SurfaceView是自定义的绘制函数,而且每次获取到的canvas仍然是上次的画布,因此在使用surfaceView视图时,得到画布canvas之后首先做的事刷屏操作,否则界面状态是无法更新的,这点千万要留意
一般刷屏有以下几种方式
(1)每次绘图前,绘制一个等同于屏幕大小的图形覆盖在画布上面
(2)没次绘图前在此画布上填充一种颜色
(3)每次绘图前指定RGB来填充画布
[java] view plain copy
- public void myDraw(){
- Canvas canvas = mHolder.lockCanvas();
- //绘制矩形
- canvas.drawRect(0, 0,this.getWidth(),this.getHeight(),paint);
- //canvas.drawColor(Color.BLACK);//画布填充颜色
- //canvas.drawRGB(0, 0, 0);//指定RGB来填充颜色
- canvas.drawText("surfaceViewTest", textX, textY, paint);
- mHolder.unlockCanvasAndPost(canvas);
- }
3、surfaceVAiew 添加线程的一些要点
3.1线程
在上面也说过了,surfaceView靠自己的线程去绘制画布以及游戏逻辑,往往需要一个线程标志位 boolean flag,主要有以下两点说明
【1】便于消亡线程
线程启动就会执行其run函数,run函数结束后线程随之消亡。在游戏开发中使用的线程一般都会在run函数中使用一个while死循环,在其中来执行绘图或者其他逻辑,如果游戏暂停或者结束,为了便于销毁线程需要设置一个标志位来控制
【2】防止重复创建线程及程序异常
主要涉及到back和home操作
按back时的surfaceView状态变化 surfaceDestroyed——构造函数——surfaceCreated——surfaceChanged
按home时的surfaceView状态变化 surfaceDestroyed——surfaceCreated——surfaceChanged
即按back键视图会被重新加载,而且千万不要把线程初始化放在surfaceCreate之前否则玩家点击home,再回到游戏就会抛出异常,这是从home恢复时会直接进入surfaceCreate再次启动线程
通俗做法:线程的初始化和线程的启动都写在视图的surfaceCreateed创建函数中,并且将线程的标志位flag在视图摧毁的时候置为fasle,这样既可以避免“线程已经启动“的异常,还可以避免点击back按键无线增加线程数目的问题
3.2 刷新帧时间尽可能保持一致
一般是通过系统函数获取到一个时间戳start;处理函数之后再次获取一个时间戳end,假设游戏线程的休眠时间为X,则按照如下房事编写
[java] view plain copy
- if((end-start)<X){
- Thread.sleep(X-(end-start));
- }
最后用一串显示hello world代码来总结一下
[java] view plain copy
- public class MySurfaceView extends SurfaceView implements Callback, Runnable {
- // 用于控制surfacView
- private SurfaceHolder mHolder;
- // 声明一个画笔
- private Paint paint;
- // 文本的坐标
- private int textX = 10, textY = 10;
- // 声明一个线程
- private Thread th;
- // 线程消亡的标志位
- private boolean flag;
- // 声明一个画布
- private Canvas canvas;
- // 声明屏幕的宽高
- private int screenW, screenH;
- public MySurfaceView(Context context) {
- super(context);
- // 实例化mHolder
- mHolder = this.getHolder();
- // 为surfaceView添加监听器
- mHolder.addCallback(this);
- // 实例化画笔
- paint = new Paint();
- // 实例化画笔颜色为白色
- paint.setColor(Color.WHITE);
- // 设置焦点
- setFocusable(true);
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- screenW = this.getWidth();
- screenH = this.getHeight();
- flag = true;
- // 实例化线程
- th = new Thread(this);
- // 启动线程
- th.start();
- }
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- // TODO Auto-generated method stub
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- flag = true;
- }
- @Override
- public void run() {
- while (flag) {
- long start = System.currentTimeMillis();
- myDraw();
- logic();
- long end = System.currentTimeMillis();
- try {
- if (end - start < 50) {
- Thread.sleep(50 - (end - start));
- }
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- <pre name="code" class="java"> /* 游戏处理逻辑 */
- private void logic() {
- // 处理游戏逻辑部分
- }
- private void myDraw() {
- try {
- canvas = mHolder.lockCanvas();
- if (canvas != null) {
- // 这里采用绘制矩形方式刷屏
- // 绘制矩形
- canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), paint);
- canvas.drawText("Hello World", textX, textY, paint);
- }
- } catch (Exception e) {
- } finally {
- if (canvas != null)
- mHolder.unlockCanvasAndPost(canvas);
- }
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- textX = (int) event.getX();
- textY = (int) event.getY();
- return true;
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- return super.onKeyDown(keyCode, event);
- }
- }
转载:http://blog.csdn.net/xsf50717/article/details/48676919