年底了,各种事情糅合在一起,不过还是磨磨叽叽的把Canvas学习的最后一部分写完了,这一篇文章应该是Canvas学习的最后一篇文章了,也是整个小游戏的结束篇。
本篇文章包主要包含BOSS类,BOSS子弹类,由于是终极BOSS所以不能像前面的敌机一样简单配置武器,所以这篇文章写的有点多,如果没有仔细看看前面子弹的实现,这里看起来可能有点蒙圈,但是我可以明确的告诉大家本篇BOSS的武器类就是通过前面敌机简单武器类的融合,最后才能实现出BOSS武器的炫酷效果。
device-2017-01-19-130322.png1.首先创建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.png5.在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.gifCanvas 以及画布的学习就此告一段落,最后就是在回顾一下成长的道路,首先确定学习目标,定下学习思路,其次将思路分割并且模块化,然后分模块学习,最后分模块去实现代码。
真正的游戏开发有对应的游戏框架,比如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>
网友评论
http://www.jianshu.com/p/05aa77075fe5