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

  • 相关阅读:
    模拟城市:我是市长
    IOTA私有链简单搭建
    SOUL软件小结
    ubuntu 16.04 安装node.js 8.x
    Ubuntu下Hyperledger Fabric v0.6安装部署
    区块链关键术语与概念
    Windows Server 2019安装OpenSSH Server简明教程
    Windows10和Windows Server 2019支持OpenSSH
    TypeError: __init__() got an unexpected keyword argument 'serialized_options'
    无法从路径’NuGet.CommandLine.2.7.1.nupkg’读取包
  • 原文地址:https://www.cnblogs.com/jqyp/p/2309692.html
Copyright © 2011-2022 走看看