device-2017-01-05-170825.png上一篇文章已经是去年的事情了,去年我们把主角和敌机都已经完美的绘制到了画布,并且做了对应的移动动画和手势操作效果,敌机和主角都配置了对应的武器,但是还没能发挥效果。所以今天这里就来实现一下主角子弹打中敌机,敌机死亡并且显示爆炸效果。
1.既然要有死亡爆炸效果就需要实现一个爆炸的类,新建一个DrawBoom类。
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.factory.Animation;
import com.tangyx.game.util.ScreenUtils;
/**
* Created by tangyx on 2017/1/5.
*
*/
public class DrawBoom extends DrawGame {
final static int TYPE_A=1;
final static int TYPE_B=2;
private float mBoomX, mBoomY;
private float mSpeedX, mSpeedY;
private float mAddX = 0.03f;
private float mAddY =0.03f;
/**
* 爆炸效果慢镜头时长,不然可能看不见效果就消失了。
*/
private int mBoomDuration =30;//慢劲头特效
/**
* 爆炸动画
*/
private Animation mAnimation;
/**
* 爆炸类型
*/
public int mBoomType;
/**
* 爆炸图
*/
private Bitmap bitmap;
private Matrix mMatrix;
private float mMaxScale = -1;
private boolean isEnd;
private int mCurrentFrameIndex = 0;
public DrawBoom(Context context, Bitmap[] deadBitmap, float x, float y, int duration, int type) {
super(context);
mAnimation = new Animation(deadBitmap, false);
this.mBoomX = x;
this.mBoomY = y;
this.mBoomDuration = duration;
this.mBoomType = type;
}
public DrawBoom(Context context, Bitmap deadBitmap, float x, float y, int duration, boolean isWidth, int type) {
super(context);
this.bitmap = deadBitmap;
this.mBoomX = x;
this.mBoomY = y;
mMatrix = new Matrix();
this.mBoomDuration = duration;
if(isWidth){//最大膨胀到全屏宽度
mMaxScale = ((float) ScreenUtils.getScreenWidth(getContext()))/deadBitmap.getWidth();
}
this.mBoomType = type;
}
@Override
void onDraw(Canvas canvas) {
if(mBoomType ==TYPE_A){
mAnimation.DrawAnimation(canvas, mPaint, mBoomX, mBoomY);
}else if(mBoomType ==TYPE_B){
float bmw,bx,by;
Bitmap bm = getBitmap();
bmw= mSpeedX *100;
if(mBoomX >=ScreenUtils.getScreenWidth(getContext())/2){
bmw = bm.getWidth()/2;
}
bx = mBoomX -bmw;//偏移计算
by = mBoomY -bm.getHeight()/2;//偏移计算
canvas.drawBitmap(bm,bx,by,mPaint);
}
}
/**
* 图片由小变大
* @return
*
*/
private Bitmap getBitmap(){
mSpeedX += mAddX;
mSpeedY += mAddY;
if(mMaxScale !=-1&& mSpeedX >= mMaxScale){
isEnd =true;
}
mMatrix.reset();
mMatrix.postScale(mSpeedX, mSpeedY);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mMatrix, true);
}
@Override
void updateGame() {
if(mCurrentFrameIndex < mBoomDuration){
mCurrentFrameIndex++;
if(mAnimation !=null&& mAnimation.mIsend){
mAnimation.reset();
}
}else{
mCurrentFrameIndex =0;
isEnd = true;
}
}
public boolean isEnd() {
return isEnd;
}
}
代码不多,只提供了两种爆炸模式,一种是持续暴涨效果,一种是单一爆炸效果。
2.上面的代码用到了一个Animation的类,是一个自定义的类,主要用于持续播放爆炸效果,一帧一帧的播放。
package com.tangyx.game.factory;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* Created by tangyx on 2017/1/5.
*/
public class Animation {
/** 上一帧播放时间 **/
private long mLastPlayTime = 0;
/** 播放当前帧的ID **/
private int mPlayID = 0;
/** 动画frame数量 **/
private int mFrameCount = 0;
/** 用于储存动画资源图片 **/
private Bitmap[] mframeBitmap = null;
/** 是否循环播放 **/
private boolean mIsLoop = false;
/** 播放结束 **/
public boolean mIsend = false;
/** 动画播放间隙时间 **/
private static final int ANIM_TIME = 100;
public Animation(Context context, int [] frameBitmapID, boolean isloop) {
mFrameCount = frameBitmapID.length;
mframeBitmap = new Bitmap[mFrameCount];
mIsLoop = isloop;
}
public Animation(Bitmap [] frameBitmap, boolean isloop) {
mFrameCount = frameBitmap.length;
mframeBitmap = frameBitmap;
mIsLoop = isloop;
}
//重置动画
public void reset() {
mLastPlayTime = 0;
mPlayID =0;
mIsend= false;
}
/**
* 绘制动画中的其中一帧
* @param paint
* @param x
* @param y
* @param frameID
*/
public void DrawFrame(Canvas canvas, Paint paint, int x, int y, int frameID) {
canvas.drawBitmap(mframeBitmap[frameID], x, y, paint);
}
/**
* 绘制动画
* @param paint
* @param x
* @param y
*/
public void DrawAnimation(Canvas canvas, Paint paint, float x, float y) {
//如果没有播放结束则继续播放
if (!mIsend) {
canvas.drawBitmap(mframeBitmap[mPlayID], x, y, paint);
long time = System.currentTimeMillis();
if (time - mLastPlayTime > ANIM_TIME) {
mPlayID++;
mLastPlayTime = time;
if (mPlayID >= mFrameCount) {
//标志动画播放结束
mIsend = true;
if (mIsLoop) {//设置循环播放
mIsend = false;
mPlayID = 0;
}
}
}
}
}
}
3.打开敌机类DrawEnemy新增一个方法用于判断敌机是否和主角的子弹进行碰撞。
Paste_Image.png主角每一颗子弹可以看做一个运动的对象,敌机也是一个运动对象,每次绘制敌机和子弹的时候调用该方法在屏幕的位置来判断出现坐标重叠,如果重叠表示敌机被打中,当敌机被打中时会有一个闪烁的效果(isCollision变量),表示敌机打中了但是并没有死亡(比如高级将领有10滴血)
4.回到GameView类新增一个判断敌机是否和主角碰撞的方法。
Paste_Image.png5.循环绘制主角子弹,把每一颗子弹都传入上面的方法,循环绘制敌机判断是否和该子弹进行了碰撞。在GameView类的addPlayerBullet循环绘制方法中调用。
Paste_Image.png主角子弹一旦和敌机碰撞,主角该子弹立刻死亡并且移除画布。
敌机被击中,敌机掉一滴血(现在敌机基本都是一滴血),如果敌机血量<=0敌机死亡并且移除画布。
6.其中有爆炸资源和一个音效,是为了保证游戏的体验,当敌机死亡时候显示爆炸效果和爆炸声音。
在GameView类的initGame方法中初始化音效。
//初始化音效
GameSoundPool.getInstance(getContext()).addMusic(GameSoundPool.ENEMYCLEARA, R.raw.enemyclear1,1);
GameSoundPool.getInstance(getContext()).addMusic(GameSoundPool.ENEMYCLEARB, R.raw.enemyclear2,1);
GameSoundPool.getInstance(getContext()).addMusic(GameSoundPool.ENEMYCLEARC, R.raw.enemydie,1);
爆炸资源的初始化
//初始化爆炸资源
mBoom01 = BitmapUtils.ReadBitMap(getContext(), R.drawable.boom_1);
Bitmap temp = BitmapUtils.ReadBitMap(getContext(), R.drawable.boom_0);
mEneyBoom01 = BitmapUtils.widthSplit(temp,6);
temp = BitmapUtils.ReadBitMap(getContext(), R.drawable.boom_2);
mEneyBoom02 = BitmapUtils.widthSplit(temp,6);
mBooms = new ArrayList<>();```
######7.在onGameDraw中绘制爆炸的效果
![Paste_Image.png](https://img.haomeiwen.com/i3982371/79a06d0b1e692a72.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
主角子弹和敌机碰撞的内容不是很多,主要实现逻辑和动画效果比较麻烦,如果需要更多的爆炸效果,可以自行拓展DrawBoom类。
这里敌机是可以被消灭了,但是主角还是无敌的,对于公平公正来说这明显不符合逻辑,所以下一篇就是针对主角挨炮的处理以及设置主角的血量增减。
<a href="https://github.com/tangyxgit/GameCanvas">持续更新的源码</a>
![enemy.gif](https://img.haomeiwen.com/i3982371/e4b4eae6c952a055.gif?imageMogr2/auto-orient/strip)
<a href="http://www.jianshu.com/p/b4c2d19a4f9f">上一篇</a> <a href="http://www.jianshu.com/p/e77701c67f47">下一篇</a>
网友评论