Android 使用SurfaceView进行2D动画的开发
来源:互联网 发布:历史时间轴软件 编辑:程序博客网 时间:2024/06/05 21:02
SurfaceView介绍
SurfaceView是View的子类,可以直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图容器。它的特性是:可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。
这个视图里内嵌了一个专门用于绘制的Surface,Surface可以这样理解:它是内存中一块区域,它是Surfaceview不可见那个部分,绘图操作作用于它,然后它就会被显卡之类的显示控制器绘制到屏幕上。使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始。因此我们需要实现SurfaceHolder.Callback接口。通过SurfaceHolder接口可以访问这个surface,getHolder()方法可以得到这个接口。Surface对应了一个内存区,大家都知道,内存区的对象是有生命周期的,可以动态的申请创建和销毁,当然也可能会更新。于是,就有了作用于这个内存区的操作,这些操作就是surfaceCreated/Changed/Destroyed。三个操作放在一起,就是Callback。以上三个生命周期回调方法都有其各自的用途,具体如下:
- public void surfaceCreated(SurfaceHolder holder):该方法在SurfaceView被创建时调用,每次创建界面时需要初始化图片、线程等资源,这些代码一般写在surfaceCreated中。
- public void surfaceChanged( SurfaceHolder holder , int format , int width , int height ) : 该方法在SurfaceView变化时被调用(如自动横竖屏切换时),在surfaceCreated方法被调用后,该方法至少会被调用一次。当SurfaceView变化时,如果需要改变一些值,这些代码应该放在surfaceChanged方法中。
- public void surfaceDestroyed( SurfaceHolder holder ) : 该方法在SurfaceView销毁时被调用。当SurfaceView被销毁时,有些与界面相关的资源应该被释放掉,这些代码应写在surfaceDestroyed方法中。
所以,我们只需继承SurfaceView来开发2D动画效果,并实现SurfaceHolder.Callback接口。
案例演示
下面通过一个2D动画的简单案例来具体演示,动画的场景是:一枚炮弹从屏幕的左下角发射,以抛物线的轨迹划过天空,并在一定的位置爆炸。
MainActivity
package com.surfaceviewdemo;import android.content.pm.ActivityInfo;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.Window;import android.view.WindowManager;public class MainActivity extends AppCompatActivity { //游戏界面 private MySurfaceView gameView ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //设置全屏模式 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置为横屏模式 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); gameView = new MySurfaceView(this); setContentView(gameView); }}
MySurfaceView
package com.surfaceviewdemo;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.view.SurfaceHolder;import android.view.SurfaceView;/** * Created by Administrator on 2017/9/5. */public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{ //Activity的引用 Activity activity ; //画笔引用 Paint paint ; //绘制线程引用 DrawThread drawThread ; //背景图片 Bitmap bgBmp ; //炮弹位图 Bitmap bulletBmp ; //爆炸位图数组 Bitmap[] explodeBmps ; //炮弹对象引用 Bullet bullet ; public MySurfaceView(Activity activity){ super(activity); this.activity = activity ; //获取焦点 this.requestFocus(); //设置为可触控 this.setFocusableInTouchMode(true); //注册回调接口 getHolder().addCallback(this); } //重写onDraw方法 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制背景 canvas.drawBitmap(bgBmp,0,0,paint); //绘制炮弹 bullet.drawSelf(canvas,paint); } @Override public void surfaceCreated(SurfaceHolder holder) { //创建画笔 paint = new Paint(); //打开抗锯齿 paint.setAntiAlias(true); //加载图片资源 bulletBmp = BitmapFactory.decodeResource(getResources(),R.drawable.bullet); bgBmp = BitmapFactory.decodeResource(getResources(),R.drawable.bg); explodeBmps = new Bitmap[]{ BitmapFactory.decodeResource(getResources(),R.drawable.explode0), BitmapFactory.decodeResource(getResources(),R.drawable.explode1), BitmapFactory.decodeResource(getResources(),R.drawable.explode2), BitmapFactory.decodeResource(getResources(),R.drawable.explode3), BitmapFactory.decodeResource(getResources(),R.drawable.explode4), BitmapFactory.decodeResource(getResources(),R.drawable.explode5), }; //创建炮弹对象 bullet = new Bullet(this, bulletBmp , explodeBmps , 0 , 290 , 1.3f , -5.9f); //创建绘制线程 drawThread = new DrawThread(this); //启动绘制线程 drawThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { //停止绘制线程 drawThread.setFlag(false); }}
Bullet炮弹类
package com.surfaceviewdemo;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.transition.Explode;/** * Created by Administrator on 2017/9/5. */public class Bullet { MySurfaceView gameView ; //位图 private Bitmap bitmap ; //爆炸动画数组 private Bitmap[] bitmaps ; //x轴位置 float x ; //y轴位置 float y ; //x轴速度 float vx ; //y轴速度 float vy ; //生存时间 private float t = 0 ; //时间间隔 private float timeSpan = 0.5f ; //炮弹尺寸 int size; //是否绘制炮弹的标记 boolean explodeFlag = false ; //爆炸对象引用 Explosion mExplosion ; public Bullet( MySurfaceView gameView , Bitmap bitmap , Bitmap[] bitmaps, float x , float y , float vx , float vy){ this.gameView = gameView ; this.bitmap = bitmap; this.bitmaps = bitmaps ; this.x = x ; this.y = y ; this.vx = vx ; this.vy = vy ; size = bitmap.getHeight(); } /** * 绘制炮弹的方法 */ public void drawSelf(Canvas canvas, Paint paint) { //如果已经爆炸,绘制爆炸动画 if( explodeFlag && mExplosion != null ){ mExplosion.drawSelf(canvas,paint); }else { //炮弹前进 go(); //绘制炮弹 canvas.drawBitmap(bitmap,x,y,paint); } } /** * 炮弹前进的方法 */ public void go(){ x += vx * t ; y += vy * t + 0.5f * Constant.G * t * t ; //特定位置爆炸 if( x >= Constant.EXPLOSION_X || y >= Constant.SCREEN_HEIGHT ){ //创建爆炸对象 mExplosion = new Explosion(gameView,bitmaps,x,y); //不再绘制炮弹 explodeFlag = true; return; } t += timeSpan ; }}
Explosion类
package com.surfaceviewdemo;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;/** * Created by Administrator on 2017/9/5. */public class Explosion { MySurfaceView gameView; private Bitmap[] bitmaps ; float x; float y; //爆炸动画帧索引 private int anmiIndex = 0 ; public Explosion( MySurfaceView gameView , Bitmap[] bitmaps , float x , float y){ this.gameView = gameView ; this.bitmaps = bitmaps ; this.x = x ; this.y = y ; } //绘制背景的方法 public void drawSelf( Canvas canvas , Paint paint){ //如果动画播放完毕,不再绘制动画效果 if( anmiIndex >= bitmaps.length - 1 ){ return; } //绘制数组中某一幅图 canvas.drawBitmap(bitmaps[anmiIndex],x,y,paint); //当前下标加1 anmiIndex++; }}
DrawThread绘制线程
package com.surfaceviewdemo;import android.graphics.Canvas;import android.view.SurfaceHolder;/** * Created by Administrator on 2017/9/5. */public class DrawThread extends Thread { //线程工作标志位 private boolean flag = true ; //线程休眠时间 private int sleepSpan = 100 ; //父界面引用 MySurfaceView gameView ; //surfaceHolder引用 SurfaceHolder surfaceHolder ; //构造器 public DrawThread(MySurfaceView gameView){ this.gameView = gameView ; //创建SurfaceHolder对象 this.surfaceHolder = gameView.getHolder(); } @Override public void run() { //声明画布 Canvas c ; //循环执行刷帧任务 while( flag ){ c = null ; try { //锁定画布 c = surfaceHolder.lockCanvas(null); //锁定surfaceHolder synchronized ( surfaceHolder ){ //绘制一帧画面 gameView.onDraw(c); } }finally { //释放锁 if( c!= null){ surfaceHolder.unlockCanvasAndPost(c); } } try { Thread.sleep(sleepSpan); }catch ( Exception e){ e.printStackTrace(); } } } public void setFlag( boolean flag){ this.flag = flag ; }}
Constant常量类
package com.surfaceviewdemo;/** * 用于统一管理常量的类 */public class Constant { //屏幕宽度 public static final int SCREEN_WIDTH = 480 ; //屏幕高度 public static final int SCREEN_HEIGHT = 320 ; //爆炸x位置 public static final int EXPLOSION_X = 270 ; //重力加速度 public static final float G = 1.0f ;}
最后的效果如下面两幅图
- Android 使用SurfaceView进行2D动画的开发
- android中使用2D动画 — SurfaceView 转载
- Android使用SurfaceView进行涂鸦的开发实例
- Android游戏开发之SurfaceView动画
- Android游戏开发----动画SurfaceView详解
- Android开发学习SurfaceView显示动画效果
- Android游戏开发----动画SurfaceView详解
- Android的SurfaceView使用
- Android的SurfaceView使用
- Android SurfaceView的使用
- Android-使用SurfaceView多线程绘制动画
- Android开发简单使用surfaceview
- android 学习笔记 view和surfaceView的2D绘图
- 浅析SurfaceView使用surfaceview制作你想要的动画
- android中使用surfaceview进行视频播放
- 使用SurfaceView模拟下雪花的动画
- android 游戏开发 - 使用SurfaceView 创建你自己的View
- Android 游戏开发笔记一、入门之SurfaceView的使用
- Could not get lock /var/lib/dpkg/lock
- linux的nohup命令的用法。
- 吴恩达深度学习课程笔记 1.4为什么深度学习会兴起?
- Android设计模式之(23)----享元模式
- java类加载过程
- Android 使用SurfaceView进行2D动画的开发
- 全文检索的基本原理
- linux文件属性和身份权限的修改
- ExtJs 4.2 xtype: 'fileuploadfield'如何设置值
- eclipse启动调试时不能从自己设置的断点处开始运行的问题
- mysql高可用之PXC(Percona XtraDB Cluster)搭建
- Android调用基于cxf的WebService接口
- POJ
- 实训第一天