3D开发学习-初识SurfaceView

在android上开发已经有三年多了,此次跳槽来到的是一个作VR的公司,可是我却对3D几乎等因而0基础,一跳漫长的学习道路必然不能少了.java

在实际开发中,一把那是用view直接去作动画的,可是基于3D的学习,咱们如今用SurfaceView来作一个简单的2D动画.对于图SurfaceView通常是去继承他,而后还须要实现SurfaceHolder.Callback接口.onDraw方法是SurfaceView的绘制方法,没触发一次绘制一帧.android

在SurfaceHolder.Callback中有2D界面的3个生命周期回调方法:git

1.surfaceCreated(SurfaceHolder holder);该方法在SurfaceView建立的时候被调用;github

2.surfaceChanged(SurfaceHolder holder, int format, int width, int height);该方法在SurfaceView变化时被调用,在建立后至少调用一次;canvas

3.surfaceDestroyed(SurfaceHolder holder);该方法在SurfaceView销毁的时候调用;ide

此动画首先作X作匀速移动,Y轴上抛运动,而后爆炸,效果以下图:学习


接着对下列实现代码作介绍:动画

1.控制类MainActivity.java:主要做为SurfaceView的控制类this

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         * 设置window没有标题并且全屏
         */
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN , WindowManager.LayoutParams.FLAG_FULLSCREEN);
        //设置屏幕的方向为横向
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        mCustomSurfaceView = new CustomSurfaceView(this);
        /tContentView(R.layout.activity_main);
        setContentView(mCustomSurfaceView);
    }

2.CustomSurfaceView显示类:绘制是由onDeaw方法实现,另外对于实现的Callback方法以下:spa

DrawThread mDrawThread; //用于实现绘制的线程
    Bitmap     mBgBitmap; //背景图
    Bitmap     mBulletBitmap; //炮弹位图
    Bitmap[]   mExplodeBmps;//爆炸效果图
    Bullet     mBullet;//炮弹实体类

@Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * 首先绘制本身的背景
         * 而后绘制炮弹本身
         */
        canvas.drawBitmap(mBgBitmap , 0 , 0 , mPaint);
        mBullet.drawSelf(canvas , mPaint);
    }
@Override
    public void surfaceCreated(SurfaceHolder holder) {
        mPaint = new Paint();
        //抗锯齿
        mPaint.setAntiAlias(true);
        //加载炮弹图片
        mBulletBitmap = BitmapFactory.decodeResource(getResources() , R.mipmap.bullet);
        mBgBitmap = BitmapFactory.decodeResource(getResources() , R.mipmap.bg);
        mExplodeBmps = new Bitmap[]{
                BitmapFactory.decodeResource(getResources() , R.mipmap.explode0) ,
                BitmapFactory.decodeResource(getResources() , R.mipmap.explode1) ,
                BitmapFactory.decodeResource(getResources() , R.mipmap.explode2) ,
                BitmapFactory.decodeResource(getResources() , R.mipmap.explode3) ,
                BitmapFactory.decodeResource(getResources() , R.mipmap.explode4) ,
                BitmapFactory.decodeResource(getResources() , R.mipmap.explode5)
        };
        //建立炮弹对象
        mBullet = new Bullet(this , mBulletBitmap , mExplodeBmps , 200 , 290 , 1.3f , -5.9f );
        mDrawThread  = new DrawThread(this);
        mDrawThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mDrawThread.setFlag(false);
    }

3.DrawThread绘制线程类run方法以下:

@Override
    public void run() {
        super.run();
        Canvas canvas;
        while (mFlag){
            canvas = null;
            //锁定画布
            try {
                canvas = mSurfaceHolder.lockCanvas(null);
                synchronized (mSurfaceHolder){
                    //绘制每一帧
                    mCustomSurfaceView.onDraw(canvas);
                }
            } finally {
                if (canvas != null){
                    //释放锁
                    mSurfaceHolder.unlockCanvasAndPost(canvas);
                }
            }

            try {
                //睡眠一下子
                Thread.sleep(mSleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

4.炮弹实体类Bullet类:

public class Bullet {
    CustomSurfaceView mCustomSurfaceView;
    //位图
    private Bitmap   mBulletBitmap;
    //爆炸动画图组
    private Bitmap[] mExplodeBmps;
    //X轴位置
    float mX;
    float mY;
    //X轴速度
    float mVx;
    float mVy;
    //生存时间
    private float mLiveTime;
    //时间间隔
    private float mSpanTime = 0.5f;
    //炮弹尺寸
    private int mBulletSize;
    //是否绘制炮弹标记位
    private boolean isExplosion;
    //爆炸对象的引用
    private Explosion mExplosion;


    public Bullet(CustomSurfaceView customSurfaceView,
                  Bitmap bulletBitmap,
                  Bitmap[] explodeBmps,
                  float x,
                  float y,
                  float vx,
                  float vy)
    {
        mCustomSurfaceView = customSurfaceView;
        mBulletBitmap = bulletBitmap;
        mExplodeBmps = explodeBmps;
        mX = x;
        mY = y;
        mVx = vx;
        mVy = vy;
        mBulletSize = bulletBitmap.getHeight();
    }

    /**
     * 绘制本身
     * @param canvas 画板
     * @param paint 画笔
     */
    public void drawSelf(Canvas canvas, Paint paint) {
        if (isExplosion && mExplosion != null){
            mExplosion.drawSelf(canvas , paint);
        }else {
            go();
            canvas.drawBitmap(mBulletBitmap , mX , mY , paint);
        }

    }

    /**
     * 绘制炮弹前进的方法
     */
    private void go() {
        //在水平方向上作匀速运动
        mX += mVx * mLiveTime;
        //在竖直方向上作上抛运动
        mY += mVy * mLiveTime + 0.5f + Constant.G * mLiveTime * mLiveTime;
        //爆炸点
        if (mX >= Constant.EXPLOSION_X || mY >= Constant.SCREEN_HEIGHT){
            mExplosion = new Explosion(mCustomSurfaceView , mExplodeBmps , mX , mY);
            //不在绘制炮弹
            isExplosion = true;
            return;
        }
        //更新生存时间
        mLiveTime += mSpanTime;
    }
}


此项目仅做为学习用,github项目地址:https://github.com/ynztlxdeai/Bullet-anim