zoukankan      html  css  js  c++  java
  • SurfaceView 绘图覆盖刷新及脏矩形刷新方法

    SurfaceView在Android中用作游戏开发是最适宜的,本文就将演示游戏开发中常用的两种绘图刷新策略在SurfaceView中的实现方法。

    首先我们来看一下本例需要用到的两个素材图片:

    image

    image

    bj.jpg就是一个渐变图,用作背景。

    question.png是一个半透明的图像,我们希望将它放在上面,围绕其圆心不断旋转。

    实现代码如下:

    package SkyD.SurfaceViewTest;
     
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.os.Bundle;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
     
    public class Main extends Activity {
     
        @Override
        public void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(new MySurfaceView(this));
        }
     
        // 自定义的SurfaceView子类
        class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
     
           // 背景图
           private Bitmap BackgroundImage;
           // 问号图
           private Bitmap QuestionImage;
     
           SurfaceHolder Holder;
     
           public MySurfaceView(Context context) {
               super(context);
               BackgroundImage = BitmapFactory.decodeResource(getResources(),
                      R.drawable.bg);
               QuestionImage = BitmapFactory.decodeResource(getResources(),
                      R.drawable.question);
     
               Holder = this.getHolder();// 获取holder
               Holder.addCallback(this);
           }
     
           @Override
           public void surfaceChanged(SurfaceHolder holder, int format, int width,
                  int height) {
               // TODO Auto-generated method stub
     
           }
     
           @Override
           public void surfaceCreated(SurfaceHolder holder) {
               // 启动自定义线程
               new Thread(new MyThread()).start();
           }
     
           @Override
           public void surfaceDestroyed(SurfaceHolder holder) {
               // TODO Auto-generated method stub
     
           }
     
           // 自定义线程类
           class MyThread implements Runnable {
     
               @Override
               public void run() {
                  Canvas canvas = null;
                  int rotate = 0;// 旋转角度变量
                  while (true) {
                      try {
                         canvas = Holder.lockCanvas();// 获取画布
                         Paint mPaint = new Paint();
                         // 绘制背景
                         canvas.drawBitmap(BackgroundImage, 0, 0, mPaint);
                         // 创建矩阵以控制图片旋转和平移
                         Matrix m = new Matrix();
                         // 设置旋转角度
                         m.postRotate((rotate += 48) % 360,
                                QuestionImage.getWidth() / 2,
                                QuestionImage.getHeight() / 2);
                         // 设置左边距和上边距
                         m.postTranslate(47, 47);
                         // 绘制问号图
                         canvas.drawBitmap(QuestionImage, m, mPaint);
                         // 休眠以控制最大帧频为每秒约30帧
                         Thread.sleep(33);
                      } catch (Exception e) {
                      } finally {
                         Holder.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
                      }
                  }
               }
     
           }
     
        }
    }
    

      

    模拟器中的运行效果:

    image

    (注:图中的问号图形是在不断旋转中的)

    这看起来不错,但是有一个问题:我们在代码中设置的帧频最大值是每秒30帧,而实际运行时的帧频根据目测就能看出是到不了30帧的,这是因为程序在每一帧都要对整个画面进行重绘,过多的时间都被用作绘图处理,所以难以达到最大帧频。

    脏矩形刷新

    接下来我们将采取脏矩形刷新的方法来优化性能,所谓脏矩形刷新,意为仅刷新有新变化的部分所在的矩形区域,而其他没用的部分就不去刷新,以此来减少资源浪费。

    我们可以通过在获取Canvas画布时,为其指派一个参数来声明我们需要画布哪个局部,这样就可以只获得这个部分的控制权:

    这样很简单,但是改后直接运行的话你会发现一个奇怪的状况:

    问号图案会变得有残影了。

    啊哈,这正是我使用半透明图案做范例的目的,通过这个重影,我们就能看出,覆盖刷新其实就是将每次的新的图形绘制到上一帧去,所以如果图像是半透明的,就要考虑重复叠加导致的问题了,而如果是完全不透明的图形则不会有任何问题。

    背景会在背景图和黑色背景之间来回闪。

    这个问题其实是源于SurfaceView的双缓冲机制,我理解就是它会缓冲前两帧的图像交替传递给后面的帧用作覆盖,这样由于我们仅在第一帧绘制了背景,第二帧就是无背景状态了,且通过双缓冲机制一直保持下来,解决办法就是改为在前两帧都进行背景绘制:

    现在就没有问题了(如果换成个不透明的图形的话就真没问题了):

    现在虽然还是达不到最大帧频,但是也算不错啦,在真机上跑的会更快些,接近最大帧频了。

    转帖自:http://www.cnblogs.com/SkyD/archive/2010/11/08/1871423.html

  • 相关阅读:
    codeforces 616B Dinner with Emma
    codeforces 616A Comparing Two Long Integers
    codeforces 615C Running Track
    codeforces 612C Replace To Make Regular Bracket Sequence
    codeforces 612B HDD is Outdated Technology
    重写父类中的成员属性
    子类继承父类
    访问修饰符
    方法的参数
    实例化类
  • 原文地址:https://www.cnblogs.com/jqyp/p/2309692.html
Copyright © 2011-2022 走看看