Android Canvas打飞机之超级BOSS

年底了,各种事情糅合在一起,不过还是磨磨叽叽的把Canvas学习的最后一部分写完了,这一篇文章应该是Canvas学习的最后一篇文章了,也是整个小游戏的结束篇。

本篇文章包主要包含BOSS类,BOSS子弹类,由于是终极BOSS所以不能像前面的敌机一样简单配置武器,所以这篇文章写的有点多,如果没有仔细看看前面子弹的实现,这里看起来可能有点蒙圈,但是我可以明确的告诉大家本篇BOSS的武器类就是通过前面敌机简单武器类的融合,最后才能实现出BOSS武器的炫酷效果。

device-2017-01-19-130322.png
1.首先创建BOSS类
package com.tangyx.game.holder;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;

import com.tangyx.game.util.ScreenUtils;

import java.util.Random;

/**
 * Created by tangyx on 2017/1/10.
 *
 */

public class DrawBoss extends DrawGame {
    /**
     * Boss资源
     */
    public Bitmap mBoss;
    /**
     * Boss配置的僚机
     */
    private Bitmap mTurn;
    /**
     * Boss特别武器
     */
    private Bitmap bmpBossBulletC;
    /**
     * Boss生命值
     */
    public int mLife = 100;
    /**
     * Boss的移动坐标
     */
    public float mBossX, mBossY;
    private int mSpeedX = 2;
    private int mSpeedY = 3;
    public boolean isCrazy;
    private int mCountBoos;
    private static int YTime = 1;
    public boolean mAttackLaser;
    /**
     * 激光武器
     */
    boolean mLaser;
    private Random mRandom;
    /**
     * Boss旋转设置
     */
    private float mAngle, mTurnAngle;
    private Matrix mMatrix;
    private int mBossType;
    private int mFireTime;
    public boolean mFireBullet;
    private int mRotaTime;

    public DrawBoss(Context context, Bitmap bitmap,int cos) {
        super(context);
        this.mBoss = bitmap;
        mBossX = ScreenUtils.getScreenWidth(getContext()) / 2 - mBoss.getWidth();
        mBossY = -mBoss.getHeight()*2;
        mRandom = new Random();
        mMatrix = new Matrix();
        this.mBossType = cos;
        mLife = (cos+1)*50;
    }

    public DrawBoss(Context context, Bitmap bitmap,Bitmap turnmap,int cos) {
        super(context);
        this.mBoss = bitmap;
        this.mTurn = turnmap;
        mBossX = ScreenUtils.getScreenWidth(getContext()) / 2 - mBoss.getWidth()/2;
        mBossY = -mBoss.getHeight()*2;
        mRandom = new Random();
        mMatrix = new Matrix();
        this.mBossType = cos;
        mLife = (cos+1)*50;
    }

    @Override
    void onDraw(Canvas canvas) {
        if(mLife <=0){
            return;
        }
        Bitmap bm;
        if(mBossType ==0){
            canvas.drawBitmap(mBoss, mBossX, mBossY, mPaint);
            bm = getTurnMax(mTurn,10);
            float cx = mBossX - mTurn.getWidth();
            float cy = mBossY;
            if(mTurnAngle %90!=0){
                cx = cx-13;
                cy = cy-13;
            }
            canvas.drawBitmap(bm, cx, cy, mPaint);//左边
            canvas.drawBitmap(bm, cx+ mBoss.getWidth()+ mTurn.getWidth(), cy, mPaint);//右边
        }else if(mBossType ==2){
            if(mFireBullet){
                bm = getTurnMax(mBoss,2);
            }else{
                bm = getMatrixBitmap(mBoss);
            }
            canvas.drawBitmap(bm, mBossX, mBossY, mPaint);
        }else{
            canvas.drawBitmap(mBoss, mBossX, mBossY, mPaint);
        }
    }

    @Override
    void updateGame() {
        if(mLife <=0|| mLaser){
            return;
        }
        if(mBossType ==0){
            mBossX += mSpeedX;
            mBossY += mSpeedY;
            if(mBossX + mBoss.getWidth()>=ScreenUtils.getScreenWidth(getContext())|| mBossX <=0){
                mSpeedX =-mSpeedX;
            }
            if(mBossY >=ScreenUtils.getScreenHeight(getContext())/8){
                mSpeedY = -mSpeedY;
            }
            if(mBossY + mBoss.getHeight()*2<=ScreenUtils.getScreenHeight(getContext())/16){
                mSpeedY = -mSpeedY;
            }
        }else if(mBossType ==2){
            if(!mFireBullet){
                mFireTime++;
            }
            if(mFireTime %1000==0){
                mFireBullet = true;
                mFireTime =0;
            }
            MyLogic();
        }else if(mBossType ==3){
            if(!mFireBullet){
                mFireTime++;
            }
            if(mFireTime %1000==0){
                mFireBullet = true;
                mFireTime =0;
            }
            if(mFireBullet){
                mFireTime++;
                if(mFireTime %100==0){
                    mFireBullet =false;
                    mFireTime =0;
                }
            }
            MyLogic();
        }else if(mBossType ==4){
            MyLogic();
        }else{
            int crazyTime = 300;
            if(mLife >30&& mLife <40){
                crazyTime = 30;
            }else{
                crazyTime = 300;
            }
            if(!mFireBullet &&!mAttackLaser){
                mFireTime++;
            }
            if (mFireTime % crazyTime ==0) {
                mFireBullet = true;
                mSpeedX = 10;
                isCrazy = true;
                mFireTime =0;
            }
            if (!isCrazy) {
                mCountBoos++;
                mBossX += mSpeedX;
                if (mCountBoos % YTime == 0) {
                    mBossY += mSpeedY;
                }
                if ((mBossX + mBoss.getWidth() >= ScreenUtils.getScreenWidth(getContext())-bmpBossBulletC.getWidth() || mBossX <= 0)&&!mLaser) {
                    mSpeedX = -mSpeedX;
                    int mRandLaser = 10;
                    if(mRandom.nextInt(100)< mRandLaser){
                        mLaser =true;
                        mAttackLaser =true;
                    }
                }
                if (mBossY >= 100) {
                    mSpeedY = -1;
                }
                if (mBossY <= 0) {
                    mSpeedY = 1;
                }
            }else{
                mSpeedX -= 1;
                mBossY += mSpeedX;
                if (mBossY <= 0) {
                    isCrazy = false;
                    mSpeedX = 4;
                    mCountBoos = 0;
                }
            }
        }
    }
    /**
     * 图像旋转
     */
    private Bitmap getTurnMax(Bitmap bm,int rotaspeed){
        mRotaTime++;
        mMatrix.reset();
        if(mRotaTime %rotaspeed==0){
            mTurnAngle +=60;
        }
        mMatrix.postRotate(mTurnAngle);
        if(mTurnAngle >=360){
            mTurnAngle =0;
        }
        return Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), mMatrix, true);
    }
    private void MyLogic(){
        mCountBoos++;
        mBossX += mSpeedX;
        if (mCountBoos % YTime == 0) {
            mBossY += mSpeedY;
        }
        if ((mBossX + mBoss.getWidth() >= ScreenUtils.getScreenWidth(getContext())-bmpBossBulletC.getWidth() || mBossX <= 0)) {
            mSpeedX = -mSpeedX;
        }
        if (mBossY >= 100) {
            mSpeedY = -1;
        }
        if (mBossY <= 0) {
            mSpeedY = 1;
        }
    }
    /**
     * 图片相对于主角方向旋转
     */
    private Bitmap getMatrixBitmap(Bitmap bmpMap){
        if(mAngle ==0){
            return bmpMap;
        }
        mMatrix.reset();
        mMatrix.setRotate(mAngle);
        Bitmap tb = Bitmap.createBitmap(bmpMap,0, 0, bmpMap.getWidth(), bmpMap.getHeight(), mMatrix, true);
        return tb;
    }
    /**
     * 面向主角方向 重新计算移动坐标
     * isTack 是否需要去追杀主角
     */
    public void getAngleRotate(float px,float py){
        float cx = px- mBossX;
        float cy = py- mBossY;
        float k = Math.abs(cy/cx);//计算偏移量 斜率
        mAngle = (float) (90-Math.toDegrees(Math.atan(k)));//把弧度转换成角度
        if(cx>0){
            mAngle = -mAngle;
        }
    }
    /**
     *
     * @return
     */
    public boolean isCollisionWith(DrawPlayerBullet bullet) {
        if(mBossY<0){
            return false;
        }
        float bx = bullet.getBulletX();
        float by = bullet.getBulletY();
        int bw = bullet.getWidth();
        int bh = bullet.getHeight();
        if(mBossX + mBoss.getWidth()<bx|| mBossX >bx+bw){
            return false;
        }
        if(mBossY + mBoss.getHeight()<by|| mBossY >by+bh){
            return false;
        }
        return true;
    }

    public float getWidth(){
        return mBoss.getWidth();
    }

    public float getHeight(){
        return mBoss.getHeight();
    }

    public float getBossX(){
        return mBossX;
    }

    public float getBossY(){
        return mBossY;
    }

    public void setBmpBossBulletC(Bitmap bmpBossBulletC) {
        this.bmpBossBulletC = bmpBossBulletC;
    }
}

Boss类最特别的地方是特殊武器就是激光武器还有僚机,其中比较复杂一点的地方就是通过Boss的血量来判断当前应该发射的武器和Boss移动动画效果。实现移动动画主要通过Matrix配合,之前已经说过这个类很重要,自行查看API。

2.Boss出场完毕,需要给Boss配置常用武器,创建Boss的武器类DrawBossBullet
package com.tangyx.game.holder;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;

import com.tangyx.game.util.ScreenUtils;

/**
 * Created by tangyx on 2017/1/11.
 *
 */

public class DrawBossBullet extends DrawGame {
    /**
     * 自由落体
     */
    public final static int BULLET_A=2;
    /**
     * 跟踪弹
     */
    public final static int BULLET_C=3;
    /**
     * boss重型武器
     */
    public final static int BULLET_BOOS=1;
    /**
     * 激光武器
     */
    public final static int BULLET_D=4;
    public final static int DIR_UP=5;
    public final static int DIR_DOWN=6;
    public final static int DIR_LEFT=7;
    public final static int DIR_RIGHT=8;
    public final static int DIR_UP_LEFT=9;
    public final static int DIR_UP_RIGHT=10;
    public final static int DIR_DOWN_LEFT=11;
    public final static int DIR_DOWN_RIGHT=12;
    /**
     * 子弹资源
     */
    private Bitmap mBullet;
    private int mDir;
    private float mBulletX, mBulletY;
    private int mBulletType;
    private Matrix mMatrix;
    private float mSpeed;
    private float mSpeedX;
    private float mSpeedY;
    private boolean isDead;
    private float mScaleSy;
    private float mSy =0.008f;
    private int mLaserAlpha =220;
    private int mAlpha =-10;
    private int mLaserTime;
    /**
     * Boss重型活力
     * @param bmpBullet
     * @param bulletX
     * @param bulletY
     * @param bulletType
     * @param dir
     */
    public DrawBossBullet(Context context,Bitmap bmpBullet, float bulletX, float bulletY, int bulletType, int dir) {//boss子弹
        super(context);
        this.mBullet = bmpBullet;
        this.mBulletX = bulletX;
        this.mBulletY = bulletY;
        this.mBulletType = bulletType;
        this.mDir = dir;
        mMatrix = new Matrix();
        mSpeed = 16;
    }


    /**
     * 普通子弹模式
     */
    public DrawBossBullet(Context context,Bitmap bmpBullet,float x,float y,int bulletType){
        super(context);
        this.mBullet = bmpBullet;
        this.mBulletX = x;
        this.mBulletY = y;
        this.mBulletType = bulletType;
        mMatrix = new Matrix();
        mSpeed =((float)ScreenUtils.getScreenHeight(context))/80;
    };

    /**
     * 子弹自动追踪模式
     */
    public DrawBossBullet(Context context,Bitmap bmpBullet,DrawPlayer player,float ex,float ey,int bulletType) {
        super(context);
        this.mBullet = bmpBullet;
        this.mBulletX = ex;
        this.mBulletY =ey;
        this.mBulletType = bulletType;
        float cx = player.getPlayerX() - mBulletX;
        float cy = player.getPlayerY() - mBulletY;
        mSpeedY =((float)ScreenUtils.getScreenHeight(getContext()))/160;
        if(cy<0){
            mSpeedY =-mSpeedY;
        }
        float runTime = cy/ mSpeedY;
        mSpeedX = cx / runTime;
        if(cx>0&& mSpeedX >=5){
            mSpeedX =1;
        }else if(cx<0&& mSpeedX <=-5){
            mSpeedX =-1;
        }
        mMatrix = new Matrix();
    }



    @Override
    void onDraw(Canvas canvas) {
        mPaint.setAlpha(255);
        switch (mBulletType){
            case BULLET_D:
                mPaint.setAlpha(mLaserAlpha);
                Bitmap bm = getBitmap();
                canvas.drawBitmap(bm, mBulletX, mBulletY, mPaint);
                break;
            default:
                canvas.drawBitmap(mBullet, mBulletX, mBulletY,mPaint);
                break;
        }
    }

    /**
     * 激光长短变化
     */
    private Bitmap getBitmap(){
        mMatrix.reset();
        mScaleSy += mSy;
        float scaleSx = 1;
        mMatrix.postScale(scaleSx, mScaleSy);
        if(mScaleSy >=1){
            mSy =0;
        }
        return Bitmap.createBitmap(mBullet, 0, 0, mBullet.getWidth(), mBullet.getHeight(), mMatrix, true);
    }

    @Override
    void updateGame() {
        switch (mBulletType){
            case BULLET_A://自由落体轨迹
                mBulletY += mSpeed;
                if(mBulletY >ScreenUtils.getScreenHeight(getContext())){
                    isDead=true;
                }
                break;
            case BULLET_C://跟踪
                mBulletY += mSpeedY;
                mBulletX += mSpeedX;
                if(mBulletY <0|| mBulletY >ScreenUtils.getScreenHeight(getContext())|| mBulletX >ScreenUtils.getScreenWidth(getContext())|| mBulletX <0){
                    isDead=true;
                }
                break;
            case BULLET_D://激光武器
                if(mSy ==0){
                    mLaserAlpha += mAlpha;
                    if(mLaserAlpha >220|| mLaserAlpha <=50){
                        mAlpha = -mAlpha;
                    }
                    mLaserTime++;
                    if(mLaserTime >=100){
                        mBulletY += mSpeed;
                        if(mBulletY >ScreenUtils.getScreenHeight(getContext())){
                            isDead = true;
                        }
                    }
                }
            case BULLET_BOOS:
                switch (mDir) {
                    case DIR_UP:
                        mBulletY -= mSpeed;
                        break;
                    case DIR_DOWN:
                        mBulletY += mSpeed;
                        break;
                    case DIR_LEFT:
                        mBulletX -= mSpeed;
                        break;
                    case DIR_RIGHT:
                        mBulletX += mSpeed;
                        break;
                    case DIR_UP_LEFT:
                        mBulletY -= mSpeed;
                        mBulletX -= mSpeed;
                        break;
                    case DIR_UP_RIGHT:
                        mBulletY += mSpeed;
                        mBulletX += mSpeed;
                        break;
                    case DIR_DOWN_LEFT:
                        mBulletY += mSpeed;
                        mBulletX -= mSpeed /3;
                        break;
                    case DIR_DOWN_RIGHT:
                        mBulletY += mSpeed;
                        mBulletX += mSpeed /3;
                        break;
                    default:
                        mBulletY += mSpeed;
                        break;
                }
                if(mBulletY > ScreenUtils.getScreenHeight(getContext())|| mBulletY <0
                        || mBulletX >ScreenUtils.getScreenWidth(getContext())|| mBulletX <0){
                    isDead = true;
                }
                break;
        }
    }

    public float getBulletX() {
        return mBulletX;
    }

    public float getBulletY() {
        return mBulletY;
    }

    public float getWidth(){
        return mBullet.getWidth();
    }

    public float getHeight(){
        return mBullet.getHeight();
    }

    public int getBulletType() {
        return mBulletType;
    }

    public boolean isDead() {
        return isDead;
    }
}

Boss武器类的逻辑和敌机武器类异曲同工,只是Boss武器类增加更多的效果以及针对主角的跟踪设置,因为在Boss出场后,整个画布只有主角和Boss在对战,所以逻辑处理上主需要针对彼此实现。

3.怎么去使用上面的两个类?打开Level1类,如果看了之前的文章就知道在关卡有一个变量用来控制当前关卡敌机的出场次数哦。
/**
     * 当前关卡最多出现多少波敌机
     */
    private int maxEnemy=1;

这里为了直接演示,我把敌机次数改成1,就是说一波敌机出现后就开始主角和Boss对战,在Level1中新增一个方法告诉画布是否Boss出场。

/**
     * 判断关卡敌机出现的场次已经结束,如果结束 需要BOSS出场
     * @return
     */
    public boolean isEnemyArrayOver(){
        return enemyArrayIndex>=maxEnemy;
    }
4.根据最开始整理的思路,模拟关卡,所以Boss类应该放到对应的关卡中去使用,不同的关卡出现的Boss不一样。在Level1中新增初始化Boss的方法。
/**
     * 初始化当前关卡的Boss
     * @param selectLevel
     */
    public void initBoss(int selectLevel){
        if(selectLevel==1||selectLevel==4){
            bmpBossBulletA = BitmapUtils.ReadBitMap(getContext(), R.drawable.bullet3);
        }else{
            bmpBossBulletA = BitmapUtils.ReadBitMap(getContext(), R.drawable.bullet2);
        }
        bmpBossBulletB = BitmapUtils.ReadBitMap(getContext(), R.drawable.bossbullet1);
        bmpBossBulletC = BitmapUtils.ReadBitMap(getContext(), R.drawable.bulletlaser);
        bmpBossBulletC = BitmapUtils.getBitmap(getContext(),bmpBossBulletC, 4);
        bmpBossBulletD = BitmapUtils.ReadBitMap(getContext(),"boss/bbullet1.png");
        bmpBossBulletE = BitmapUtils.ReadBitMap(getContext(),"boss/bbullet2.png");
        bmpBossBulletF = BitmapUtils.ReadBitMap(getContext(),"boss/bbullet3.png");
        bmpBossBulletF = BitmapUtils.getBitmap(bmpBossBulletF, 0.3f, 0.3f);
        //初始化boss
        Bitmap mBoss = BitmapUtils.ReadBitMap(getContext(), getBoss(selectLevel));
        bmpTurntable = BitmapUtils.ReadBitMap(getContext(), "boss/truntableyellow.png");
        if(selectLevel==1){
            mDrawBoss = new DrawBoss(getContext(),mBoss, bmpTurntable,selectLevel);
        }else{
            mDrawBoss = new DrawBoss(getContext(),mBoss,selectLevel);
        }
        mDrawBoss.setBmpBossBulletC(bmpBossBulletC);
        mBulletBoss = new ArrayList<>();
    }

selectLevel参数就是通过在进入游戏的时候一个左右滑动选择场景的地方获取选择的某个场景的标示。

device-2017-01-19-104336.png
5.在Level1中新增一个增加Boss子弹的方法
/**
     * 添加boss子弹攻击
     */
    public void addBossBullet(int selectLevel){
        mCountBossBullet++;
        if(mCountBossBullet % mAddBossBulletTime ==0&&getBoss().mLife >0&&!getBoss().isCrazy && getBoss().getBossY()>0){//添加一次boss子弹
            if(selectLevel==2){
                if(getBoss().mFireBullet){
                    isTurntable =true;
                }else{
                    mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletA,mPlayer, getBoss().mBossX +getBoss().getWidth()/2-bmpBossBulletA.getWidth()-bmpBossBulletA.getWidth()/2,getBoss().mBossY +getBoss().getHeight(), DrawBossBullet.BULLET_C));//左边
                    mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletA,mPlayer, getBoss().mBossX +getBoss().getWidth()/2+bmpBossBulletA.getWidth()/2,getBoss().mBossY +getBoss().getHeight(), DrawBossBullet.BULLET_C));//右边
                    if(new Random().nextBoolean()){
                        mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletF,getBoss().mBossX +getBoss().getWidth()/2-bmpBossBulletF.getWidth()/2,getBoss().mBossY +getBoss().getHeight(), DrawBossBullet.BULLET_A));//中间
                    }
                }
            }else if(selectLevel==3){
                mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletE,mPlayer, getBoss().mBossX +getBoss().getWidth()/2-bmpBossBulletE.getWidth()*3,getBoss().mBossY +getBoss().getHeight(), DrawBossBullet.BULLET_C));//左边
                mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletE,mPlayer, getBoss().mBossX +getBoss().getWidth()/2+bmpBossBulletE.getWidth()*2,getBoss().mBossY +getBoss().getHeight(), DrawBossBullet.BULLET_C));//右边
                if(getBoss().mLife <500&&new Random().nextInt(100)>50&&!isTurntable){
                    isTurntable =true;
                }
            }else{
                mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletA,mPlayer, getBoss().mBossX +getBoss().getWidth()/2-bmpBossBulletA.getWidth()/2,getBoss().mBossY +getBoss().getHeight(), DrawBossBullet.BULLET_C));
            }
            if(getBoss().mBossY <0&&getBoss().mLife <(selectLevel*0.2)&&selectLevel==1){
                if(new Random().nextInt(100)>30){
                    mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletE, getBoss().mBossX +getBoss().getWidth()/2-bmpBossBulletD.getWidth()/2,getBoss().mBossY +getBoss().getHeight(), DrawBossBullet.BULLET_A));
                }
            }
            if(mBulletBoss.size()>10){
                mAddBossBulletTime = 100;
            }else{
                mAddBossBulletTime =15;
            }
        }
        if(selectLevel==1&&!isTurntable &&mEnemyList.size()<=0){
            mCountTurntableTime++;
            if(mCountTurntableTime %1000==0){
                isTurntable =true;
            }
        }
        if(isTurntable){
            mTurntableTime++;
            int createFire=5;
            if(selectLevel==2){
                createFire=createFire*10;
                if(mTurntableTime %createFire==0){
                    mEnemyList.add(new DrawEnemy(getContext(),mEnemyG, mPlayer.getPlayerX(), mPlayer.getPlayerY(), getBoss().mBossX, getBoss().mBossY, DrawEnemy.TYPE_V, 1));
                    mEnemyList.add(new DrawEnemy(getContext(),mEnemyG, mPlayer.getPlayerX(), mPlayer.getPlayerY(), getBoss().mBossX +getBoss().getWidth(), getBoss().mBossY, DrawEnemy.TYPE_W, 1));
                }
            }else if(selectLevel==3){
                createFire=createFire*10;
                if(mTurntableTime %createFire==0){
                    Bitmap temp = BitmapUtils.getBitmap(bmpTurntable,0.5f,0.5f);
                    mEnemyList.add(new DrawEnemy(getContext(),temp, mPlayer.getPlayerX(), mPlayer.getPlayerY(), getBoss().mBossX, getBoss().mBossY, DrawEnemy.TYPE_V, 1));
                    mEnemyList.add(new DrawEnemy(getContext(),temp, mPlayer.getPlayerX(), mPlayer.getPlayerY(), getBoss().mBossX +getBoss().getWidth(), getBoss().mBossY, DrawEnemy.TYPE_W, 1));
                }
            }else{
                if(mTurntableTime %createFire==0){
                    Bitmap temp =BitmapUtils.getBitmap(bmpTurntable,0.5f,0.5f);
                    mEnemyList.add(new DrawEnemy(getContext(),temp, mPlayer.getPlayerX(), mPlayer.getPlayerY(), getBoss().mBossX, getBoss().mBossY, DrawEnemy.TYPE_V, 1));
                    mEnemyList.add(new DrawEnemy(getContext(),temp, mPlayer.getPlayerX(), mPlayer.getPlayerY(), getBoss().mBossX +getBoss().getWidth(), getBoss().mBossY, DrawEnemy.TYPE_W, 1));
                }
            }
            if(mTurntableTime >=createFire*5){
                mTurntableTime =0;
                isTurntable =false;
                getBoss().mFireBullet =false;
            }
        }
        if(getBoss().mAttackLaser){
            mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletC,getBoss().mBossX +getBoss().getWidth()/6,getBoss().mBossY +getBoss().getHeight()/2,DrawBossBullet.BULLET_D));//左边
            mBulletBoss.add(new DrawBossBullet(getContext(),bmpBossBulletC,getBoss().mBossX +getBoss().getWidth()-getBoss().getWidth()/6-bmpBossBulletC.getWidth(),getBoss().mBossY +getBoss().getHeight()/2, DrawBossBullet.BULLET_D));//右边
            getBoss().mAttackLaser =false;
        }
        if(getBoss().mFireBullet){
            if(selectLevel==1){
                addBossBulletFire(selectLevel,bmpBossBulletB);
            }else if(selectLevel==3){
                addBossBulletFire(selectLevel,bmpBossBulletA);
            }
        }
    }

Boss增加武器的方法通过不同场景出场不同Boss,Boos完全显示,Boss血量大于0,Boss子弹增加的间隔时间各个值的判断来决定Boss武器在画布中的实现。
上面的方法除了增加Boss子弹还有实现了僚机增加,其实僚机也可以看做是武器的一部分,只是把子弹换成了敌机的模式来出现,一样具有杀伤力。

6.上面的方法有一段代码用来实现Boss的暴力武器,有种火力全开的感觉。
/**
     * 增加Boss超级武器,火力全开
     * @param selectLevel
     * @param bitmap
     */
    private void addBossBulletFire(int selectLevel,Bitmap bitmap){
        float bx,by;
        if(selectLevel==3){
            bx = mDrawBoss.getBossX() + mDrawBoss.getWidth()/2-bitmap.getWidth()/2;
            by = mDrawBoss.getBossY()+mDrawBoss.getHeight();
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx, by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_UP));
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx, by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_UP_RIGHT));
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx, by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_RIGHT));
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx, by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_DOWN_RIGHT));
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx,by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_DOWN));
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx,by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_DOWN_LEFT));
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx, by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_LEFT));
            mBulletBoss.add(new DrawBossBullet(getContext(),bitmap,
                    bx, by,
                    DrawBossBullet.BULLET_BOOS,DrawBossBullet.DIR_UP_LEFT));
        }else{
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_UP));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 3, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 1.5f, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_LEFT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_RIGHT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_UP_LEFT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_UP_RIGHT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN_LEFT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY()-bitmap.getHeight()*2,
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN_LEFT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY()-bitmap.getHeight()*3,
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN_LEFT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY(),
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN_RIGHT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY()-bitmap.getHeight()*2,
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN_RIGHT));
            mBulletBoss.add(new DrawBossBullet(getContext(),
                    bitmap, getBoss().getBossX() + getBoss().getWidth() / 2, getBoss().getBossY()-bitmap.getHeight()*3,
                    DrawBossBullet.BULLET_BOOS, DrawBossBullet.DIR_DOWN_RIGHT));
            getBoss().mFireBullet=false;
        }
    }
device-2017-01-19-105518.png

以上部分就是关卡类新增的逻辑和方法。

7.回到GameView中调用关卡中跟Boss相关的方法。实例关卡类并且初始化Boss
//初始化关卡
        mLevel = new Level1(getContext(),mPlayer);
        mLevel.initBoss(mSelectLevel);
8.新增一个游戏状态,用来控制主角打败Boss的时候游戏胜利。
private final static int WIN=4;//Boss死亡游戏结束。
9.在GameView类onGameDraw方法中调用Boss相关的逻辑方法。
图片.png

其中需要新增一个方法用来处理Boss和主角之间对战。

/**
     * 绘制BOSS
     * 判断BOSS子弹是否失效  Boss子弹和主角碰撞
     */
    private void drawBossBulletCollPlayerIsDecide(){
        if(mSelectLevel ==2){
            mLevel.getBoss().getAngleRotate(mPlayer.getPlayerX(),mPlayer.getPlayerY());
        }
        mLevel.getBoss().onDraw(mCanvas);//绘制boss
        List<DrawBossBullet> mBulletBoss = mLevel.getBulletBoss();
        for (int i = 0; i < mBulletBoss.size(); i++){
            DrawBossBullet b = mBulletBoss.get(i);
            if(mPlayer.isCollisionWith(b)){//主角和boss子弹碰撞 主角掉血 子弹失效
                collPlayerLife(1);
                if(b.getBulletType()!=DrawBossBullet.BULLET_D){
                    mBulletBoss.remove(b);
                }
            }
            if(b.isDead()){//判断boss子弹是否失效
                mBulletBoss.remove(b);//清除
                if(b.getBulletType() == DrawBossBullet.BULLET_D){//是否是激光
                    mLevel.getBoss().mLaser =false;
                }
            }else{
                b.updateGame();
                b.onDraw(mCanvas);
            }
        }
    }

其实这个方法的逻辑处理和敌机处理的思路一致,只不过Boss的碰撞处理需要增加Boss特殊武器的处理,比如激光武器。

Boss类暂时就简单实现了4种模式模式,更多的Boss效果就留给学习者去拓展了。

boss.gif

Canvas 以及画布的学习就此告一段落,最后就是在回顾一下成长的道路,首先确定学习目标,定下学习思路,其次将思路分割并且模块化,然后分模块学习,最后分模块去实现代码。

真正的游戏开发有对应的游戏框架,比如cocos2d跨平台框架,或者一些java游戏框架,肯定比我们这个高端多了,但是无论什么框架的底层核心或者底层逻辑思路都是最简单的代码累加起来的,只有把最简单的东西写好了,最后才能组成一个趋近完美的东西。

最后还是要说一下我们的重点Canvas和SurfaceView画布,整个游戏都是在这个基础上实现的,包括怎么去合理分配资源以及性能上的优化都是基于画布来完成,而canvas可以在这布上画出你任何想要的东西,比如动画,多张图片组合效果。

说了这么多就是想让大家知道你能玩转canvas,那么在很多自定义需求对你来说都不再是让你迷茫的感觉了,至少能为你的成神的路上增加一大段功力。

<b>本文或者各主题文章都属于原创,禁止商业用途,欢迎各路喜欢技术的初级,中级,高级,高高高...级的朋友一起分享学习。</b>

如果你喜欢请点击喜欢告诉我,后面将会带来更多Android自己搭建的轻量级高效率框架以及更多实用,强大,高性能的自定义控件。

<a href="https://github.com/tangyxgit/GameCanvas">源码在此,不服来战。</a>

<a href="http://www.jianshu.com/p/e77701c67f47">上一篇</a>

<a href="http://www.jianshu.com/nb/8490176">Canvas打飞机成长主题</a>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容