Android Canvas打飛機之超級BOSS

年底了巍膘,各種事情糅合在一起厂财,不過還是磨磨嘰嘰的把Canvas學習的最后一部分寫完了,這一篇文章應該是Canvas學習的最后一篇文章了峡懈,也是整個小游戲的結束篇璃饱。

本篇文章包主要包含BOSS類,BOSS子彈類肪康,由于是終極BOSS所以不能像前面的敵機一樣簡單配置武器荚恶,所以這篇文章寫的有點多,如果沒有仔細看看前面子彈的實現磷支,這里看起來可能有點蒙圈谒撼,但是我可以明確的告訴大家本篇BOSS的武器類就是通過前面敵機簡單武器類的融合,最后才能實現出BOSS武器的炫酷效果雾狈。

device-2017-01-19-130322.png
1.首先創(chuàng)建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的血量來判斷當前應該發(fā)射的武器和Boss移動動畫效果。實現移動動畫主要通過Matrix配合善榛,之前已經說過這個類很重要辩蛋,自行查看API。

2.Boss出場完畢移盆,需要給Boss配置常用武器悼院,創(chuàng)建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在對戰(zhàn)钮呀,所以邏輯處理上主需要針對彼此實現。

3.怎么去使用上面的兩個類昨凡?打開Level1類,如果看了之前的文章就知道在關卡有一個變量用來控制當前關卡敵機的出場次數哦蚁署。
/**
     * 當前關卡最多出現多少波敵機
     */
    private int maxEnemy=1;

這里為了直接演示便脊,我把敵機次數改成1,就是說一波敵機出現后就開始主角和Boss對戰(zhàn)光戈,在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.新增一個游戲狀態(tài)该酗,用來控制主角打敗Boss的時候游戲勝利。
private final static int WIN=4;//Boss死亡游戲結束士嚎。
9.在GameView類onGameDraw方法中調用Boss相關的邏輯方法呜魄。
圖片.png

其中需要新增一個方法用來處理Boss和主角之間對戰(zhàn)。

/**
     * 繪制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 以及畫布的學習就此告一段落趟庄,最后就是在回顧一下成長的道路,首先確定學習目標伪很,定下學習思路戚啥,其次將思路分割并且模塊化,然后分模塊學習锉试,最后分模塊去實現代碼猫十。

真正的游戲開發(fā)有對應的游戲框架,比如cocos2d跨平臺框架呆盖,或者一些java游戲框架拖云,肯定比我們這個高端多了,但是無論什么框架的底層核心或者底層邏輯思路都是最簡單的代碼累加起來的应又,只有把最簡單的東西寫好了宙项,最后才能組成一個趨近完美的東西。

最后還是要說一下我們的重點Canvas和SurfaceView畫布株扛,整個游戲都是在這個基礎上實現的,包括怎么去合理分配資源以及性能上的優(yōu)化都是基于畫布來完成席里,而canvas可以在這布上畫出你任何想要的東西叔磷,比如動畫,多張圖片組合效果奖磁。

說了這么多就是想讓大家知道你能玩轉canvas改基,那么在很多自定義需求對你來說都不再是讓你迷茫的感覺了,至少能為你的成神的路上增加一大段功力咖为。

<b>本文或者各主題文章都屬于原創(chuàng)秕狰,禁止商業(yè)用途,歡迎各路喜歡技術的初級躁染,中級鸣哀,高級,高高高...級的朋友一起分享學習吞彤。</b>

如果你喜歡請點擊喜歡告訴我我衬,后面將會帶來更多Android自己搭建的輕量級高效率框架以及更多實用,強大饰恕,高性能的自定義控件挠羔。

<a >源碼在此,不服來戰(zhàn)埋嵌。</a>

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

<a href="http://www.reibang.com/nb/8490176">Canvas打飛機成長主題</a>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末破加,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子雹嗦,更是在濱河造成了極大的恐慌范舀,老刑警劉巖眼五,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夏志,死亡現場離奇詭異,居然都是意外死亡姻蚓,警方通過查閱死者的電腦和手機暇赤,發(fā)現死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門已骇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宇植,“玉大人兑徘,你說我怎么就攤上這事∑茫” “怎么了踊餐?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵吝岭,是天一觀的道長窜管。 經常有香客問我,道長获搏,這世上最難降的妖魔是什么常熙? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任裸卫,我火速辦了婚禮墓贿,結果婚禮上聋袋,老公的妹妹穿的比我還像新娘舱馅。我一直安慰自己代嗤,他們只是感情好,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布宜猜。 她就那樣靜靜地躺著姨拥,像睡著了一般叫乌。 火紅的嫁衣襯著肌膚如雪憨奸。 梳的紋絲不亂的頭發(fā)上排宰,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音详炬,去河邊找鬼呛谜。 笑死呻率,一個胖子當著我的面吹牛礼仗,可吹牛的內容都是我干的。 我是一名探鬼主播韭脊,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了琅豆?” 一聲冷哼從身側響起茫因,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤冻押,失蹤者是張志新(化名)和其女友劉穎洛巢,沒想到半個月后次兆,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蚤认,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年砰琢,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挚冤。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡训挡,死狀恐怖澜薄,靈堂內的尸體忽然破棺而出肤京,到底是詐尸還是另有隱情忘分,我是刑警寧澤饭庞,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布绸狐,位于F島的核電站寒矿,受9級特大地震影響符相,放射性物質發(fā)生泄漏啊终。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望例衍。 院中可真熱鬧佛玄,春花似錦梦抢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽靴迫。三九已至,卻和暖如春名挥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背主守。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工禀倔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人参淫。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓救湖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涎才。 傳聞我的和親對象是個殘疾皇子鞋既,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內容