SurfaceView的应用

来源:互联网 发布:软件授权许可协议 编辑:程序博客网 时间:2024/06/11 02:48

一,SurfaceView的初识

       android游戏开发中常用的三种视图是:view、SurfaceView和GLSurfaceView
  View:显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件函数等;必须在UI主线程内更新画面,速度较慢
  SurfaceView:基于view视图进行拓展的视图类,更适合2D游戏的开发;是view的子类,类似使用双缓机制,在新的线程中更新画面所以刷新界面速度比view快
  GLSurfaceView:基于SurfaceView视图再次进行拓展的视图类,专用于3D游戏开发的视图;是SurfaceView的子类,openGL专用
     View可以在UI的主线程中更新画面,但可能存在无法响应按键,触屏等消息。使用surfaceView 不会阻塞UI线程,但涉及到线程同步。

二,SurfaceView的使用

1,核心类:
       a.继承SurfaceView
       b.实现SurfaceHolder.Callback接口


2,重写方法:
 

     (1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}  //在surface的大小发生改变时激发     (2)public void surfaceCreated(SurfaceHolder holder){}  //在创建时激发,一般在这里调用画图的线程。     (3)public void surfaceDestroyed(SurfaceHolder holder) {}  //销毁时激发,一般在这里将画图的线程停止、释放。

3,主业务逻辑实现--SurfaceHolder
       SurfaceHolder:surface的控制器,用来控制surface。处理Holder上Canvas的效果和动画,控制表面,大小,像素等。
   (1)、abstract void addCallback(SurfaceHolder.Callback callback);// 给SurfaceView当前的持有者一个回调对象。   (2)、abstract Canvas lockCanvas();// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。   (3)、abstract Canvas lockCanvas(Rect dirty);// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。   (4)、abstract void unlockCanvasAndPost(Canvas canvas);// 结束锁定画图,并提交改变。

4,整理整体使用步骤:
   继承SurfaceView并实现SurfaceHolder.Callback接口   SurfaceView.getHolder()获得SurfaceHolder对象   SurfaceHolder.addCallback(callback)添加回调函数【子线程中优化实现】   SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布Canvas绘画   SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。

三、基础使用  --- 绘制文字、圆形、矩形【基础实现

public class TestSurfaceViewActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        View view = new TextSurfaceView(this);        view.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                startActivity(new Intent(TestSurfaceViewActivity.this, VideoPlayorActivity.class));            }        });        setContentView(view);    }    /**     * 继承SurfaceView并实现SurfaceHolder.Callback接口     */    class TextSurfaceView extends SurfaceView implements SurfaceHolder.Callback {        /**         * 控制器         */        SurfaceHolder holder = null;        /**         * 子线程,用于更新界面内容         */        TextThread textThread;        public TextSurfaceView(Context context) {            super(context);            holder = getHolder();            holder.addCallback(this);            textThread = new TextThread(holder);        }        @Override        public void surfaceCreated(SurfaceHolder holder) {            textThread.isRun = true;            textThread.start();        }        @Override        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        }        @Override        public void surfaceDestroyed(SurfaceHolder holder) {            textThread.isRun = false;        }        @Override        protected void onDraw(Canvas canvas) {            super.onDraw(canvas);            canvas = holder.lockCanvas();            Paint paint = new Paint();//            paint.setColor(Color.GREEN);            paint.setColor(Color.argb(1, (int) (Math.random()), (int) (Math.random()), (int) (Math.random())));            canvas.drawColor(Color.BLUE);            canvas.drawCircle(50, 100, 80, paint);            holder.unlockCanvasAndPost(canvas);        }    }    class TextThread extends Thread {        /**         * 是否正在运行         */        private boolean isRun;        /**         * 控制器         */        private final SurfaceHolder holder;        /**         * 左上角坐标点位         */        private int x = 0;        private int y = 0;        public TextThread(SurfaceHolder holder) {            this.holder = holder;            isRun = true;        }        @Override        public void run() {            super.run();            int count = 0;            while (isRun) {                /**                 * 子线程具体实现,修改界面内容                 */                Canvas canvas = null;                try {                    synchronized (holder) {                        canvas = holder.lockCanvas();                        canvas.drawColor(Color.BLACK);                        Paint paint = new Paint();                        paint.setColor(Color.RED);                        canvas.drawRect(x, y, x + 100, y + 200, paint);//                        canvas.drawRect(0, 0f, 100f, 200f, paint);                        paint.setTextSize(40);                        canvas.drawText("这是第" + (count++) + "秒", x + 160, y + 260, paint);                        move();                        Thread.sleep(1000);                    }                } catch (Exception e) {                    e.printStackTrace();                } finally {                    if (canvas != null) {                        holder.unlockCanvasAndPost(canvas);                    }                }            }        }        /**         * 目标对象运动轨迹控制         */        private void move() {            if (x > 480) {                x = 10;            } else {                x += 10;            }            if (y > 720) {                y = 20;            } else {                y = x + y - 5;            }        }    }}

四、拖拽图片实现【触控事件

/** * 功能描述:拖动展示图片 * 时间:2016/8/4 * 作者:vision */public class DragActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        DragImage view = new DragImage(this);        setContentView(view);    }    private class DragImage extends SurfaceView implements SurfaceHolder.Callback, Runnable, View.OnTouchListener {        private Context context;        private SurfaceHolder holder;        private Bitmap icon;        private Paint paint;        private boolean running = true;        //      Region region=new Region();        private Point point = new Point();//点击点        private Rect rect = new Rect(40, 40, 200, 200);//图片的rect        private boolean canDrag = false;//判断是否点击在图片上,否则拖动无效        private int offsetX = 0, offsetY = 0;//点击点离图片左上角的距离        public DragImage(Context context) {            super(context);            this.context = context;            holder = this.getHolder();//获取holder            holder.addCallback(this);            this.setOnTouchListener(this);        }        @Override        public void surfaceCreated(SurfaceHolder holder) {            icon = BitmapFactory.decodeResource(context.getResources(), R.mipmap.e);            paint = new Paint();            running = true;            new Thread(this).start();        }        @Override        public void surfaceChanged(SurfaceHolder holder, int format, int width,                                   int height) {        }        @Override        public void surfaceDestroyed(SurfaceHolder holder) {            running = false;        }        @Override        public void run() {            int SLEEP_TIME = 100;            while (running) {                //开始画的时间    long start=System.currentTimeMillis();                Canvas canvas = holder.lockCanvas();//获取画布                canvas.drawColor(Color.BLACK);                canvas.drawBitmap(icon, rect.left, rect.top, null);                holder.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像                //结束的时间   long end=System.currentTimeMillis();            }        }        @Override        public boolean onTouch(View v, MotionEvent event) {            // TODO Auto-generated method stub            switch (event.getAction()) {                //手按下的时候                case MotionEvent.ACTION_DOWN:                    point.x = (int) event.getX();                    point.y = (int) event.getY();                    if (rect.contains(point.x, point.y)) {                        canDrag = true;                        offsetX = point.x - rect.left;                        offsetY = point.y - rect.top;                    }                    break;                //移动的时候                case MotionEvent.ACTION_MOVE:                    if (canDrag) {                        /**                         * 控制不出边框                         */                        rect.left = (int) event.getX() - offsetX;                        rect.top = (int) event.getY() - offsetY;                        rect.right = rect.left + icon.getWidth();                        rect.bottom = rect.top + icon.getHeight();                        if (rect.left < 0) {                            rect.left = 0;                            rect.right = rect.left + icon.getWidth();                        }                        if (rect.right > getMeasuredWidth()) {                            rect.right = getMeasuredWidth();                            rect.left = rect.right - icon.getWidth();                        }                        if (rect.top < 0) {                            rect.top = 0;                            rect.bottom = rect.top + icon.getHeight();                        }                        if (rect.bottom > getMeasuredHeight()) {                            rect.bottom = getMeasuredHeight();                            rect.top = rect.bottom - icon.getHeight();                        }                    }                    break;                case MotionEvent.ACTION_UP:                    canDrag = false;                    break;                default:                    break;            }            return true;        }    }}

五、游戏动画实现

       借鉴网络信息,实现基本控制。

       具体实现如源码,其中推荐实现,通过JPG图片加载运行动画的不同状态。

其下部分所需图片原件,下载即可使用。


public class GameSurfaceView extends SurfaceView implements        SurfaceHolder.Callback {    //屏幕宽高    public static int SCREEN_WIDTH;    public static int SCREEN_HEIGHT;    private Context mContext;    private SurfaceHolder mHolder;    //最大帧数 (1000 / 30)    private static final int DRAW_INTERVAL = 30;    private DrawThread mDrawThread;    private FrameAnimation[] spriteAnimations;    private Sprite mSprite;    private int spriteWidth = 0;    private int spriteHeight = 0;    private float spriteSpeed = (float) ((500 * SCREEN_WIDTH / 480) * 0.001);    private int row = 4;    private int col = 4;    public GameSurfaceView(Context context) {        super(context);        this.mContext = context;        mHolder = this.getHolder();        mHolder.addCallback(this);        initResources();        mSprite = new Sprite(spriteAnimations, 0, 0, spriteWidth, spriteHeight, spriteSpeed);    }    private void initResources() {  <span style="color:#6600CC;">     <strong> Bitmap[][] spriteImgs = generateBitmapArray(mContext, R.drawable.sprite, row, col);</strong></span>        spriteAnimations = new FrameAnimation[row];        for (int i = 0; i < row; i++) {            Bitmap[] spriteImg = spriteImgs[i];            FrameAnimation spriteAnimation = new FrameAnimation(spriteImg, new int[]{150, 150, 150, 150}, true);            spriteAnimations[i] = spriteAnimation;        }    }    public Bitmap decodeBitmapFromRes(Context context, int resourseId) {        BitmapFactory.Options opt = new BitmapFactory.Options();        opt.inPreferredConfig = Bitmap.Config.RGB_565;        opt.inPurgeable = true;        opt.inInputShareable = true;        InputStream is = context.getResources().openRawResource(resourseId);        return BitmapFactory.decodeStream(is, null, opt);    }    public Bitmap createBitmap(Context context, Bitmap source, int row,                               int col, int rowTotal, int colTotal) {        Bitmap bitmap = Bitmap.createBitmap(source,                (col - 1) * source.getWidth() / colTotal,                (row - 1) * source.getHeight() / rowTotal, source.getWidth()                        / colTotal, source.getHeight() / rowTotal);        return bitmap;    }    public Bitmap[][] generateBitmapArray(Context context, int resourseId,                                          int row, int col) {        Bitmap bitmaps[][] = new Bitmap[row][col];        Bitmap source = decodeBitmapFromRes(context, resourseId);        this.spriteWidth = source.getWidth() / col;        this.spriteHeight = source.getHeight() / row;        for (int i = 1; i <= row; i++) {            for (int j = 1; j <= col; j++) {                bitmaps[i - 1][j - 1] = createBitmap(context, source, i, j,                        row, col);            }        }        if (source != null && !source.isRecycled()) {            source.recycle();            source = null;        }        return bitmaps;    }    public void surfaceChanged(SurfaceHolder holder, int format, int width,                               int height) {    }    public void surfaceCreated(SurfaceHolder holder) {        if (null == mDrawThread) {            mDrawThread = new DrawThread();            mDrawThread.start();        }    }    public void surfaceDestroyed(SurfaceHolder holder) {        if (null != mDrawThread) {            mDrawThread.stopThread();        }    }    private class DrawThread extends Thread {        public boolean isRunning = false;        public DrawThread() {            isRunning = true;        }        public void stopThread() {            isRunning = false;            boolean workIsNotFinish = true;            while (workIsNotFinish) {                try {                    this.join();// 保证run方法执行完毕                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                workIsNotFinish = false;            }        }        public void run() {            long deltaTime = 0;            long tickTime = 0;            tickTime = System.currentTimeMillis();            while (isRunning) {                Canvas canvas = null;                try {                    synchronized (mHolder) {                        canvas = mHolder.lockCanvas();                        //设置方向                        mSprite.setDirection();                        //更新精灵位置                        mSprite.updatePosition(deltaTime);                        drawSprite(canvas);                    }                } catch (Exception e) {                    e.printStackTrace();                } finally {                    if (null != mHolder) {                        mHolder.unlockCanvasAndPost(canvas);                    }                }                deltaTime = System.currentTimeMillis() - tickTime;                if (deltaTime < DRAW_INTERVAL) {                    try {                        Thread.sleep(DRAW_INTERVAL - deltaTime);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                tickTime = System.currentTimeMillis();            }        }    }    private void drawSprite(Canvas canvas) {        //清屏操作        canvas.drawColor(Color.BLACK);        mSprite.draw(canvas);    }}

这里是源码~_~



若不是情到深处难自禁


                             又怎会柔肠百转冷如霜


0 0
原创粉丝点击