一、整体实现思路
1、背景:通过图片循环滚动实现飞机在前进的视觉体验。
2、图片移动:通过改变贴图的x,y坐标实现图片移动,玩家飞机通过屏幕感应实现操作。
3、碰撞判定:通过两张图片x,y坐标是否重合判断碰撞,并添加碰撞效果。
4、胜利失败:为玩家和电脑飞机添加hp,hp为零判定负方。
二、如何绘制滚动的背景图片
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
public class BackGround {
private int y1;
private int y2;//定义两张图片的坐标,方便实现循环
private Bitmap bitmap;//定义图片类
public BackGround(Bitmap bitmap){
this.bitmap = bitmap;
y1 = 0;//第一张图片充满屏幕
y2 = y1-bitmap.getHeight();//第二张图片从屏幕上方金街第一张图片
}
public void draw(Canvas canvas){
logic();
Paint paint = new Paint();
canvas.drawBitmap(bitmap,0,y1,paint);
canvas.drawBitmap(bitmap,0,y2,paint);
}
public void logic(){
y1+=5;
y2+=5;//图片滚动速度
if(y1>=MySurfaceView.Height){
y1=y2-bitmap.getHeight();//如果第一张图滚出屏幕,坐标自动变到第二张图上方
}
if(y2>=MySurfaceView.Height){
y2=y1-bitmap.getHeight();//第二张图原理同上
}
}
}
BackGround backGround = new BackGround(BitmapFactory.decodeResource(getResources(), R.mipmap.bk));//在run方法中添加绘制
三、如何绘制飞机
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;
import android.view.MotionEvent;
public class MyPlane {
private Bitmap bitmapHP;//玩家飞机hp图片
private Bitmap bitmap;//玩家飞机图片
private int x, y;//图片x,y坐标
private int width, height;//图片宽度,高度
private boolean noCollision;//判断碰撞
private int noCollisionCount;//碰撞次数
private int hp = 3;//玩家血量
public MyPlane(Bitmap bitmap, Bitmap bitmapHP) {
this.bitmap = bitmap;
x = MySurfaceView.Wide / 2 - bitmap.getWidth() / 2;
y = MySurfaceView.Height - bitmap.getHeight();//玩家飞机初始坐标位于屏幕下方中间位置
width = bitmap.getWidth();//获取图片宽度
height = bitmap.getHeight();//获取屏幕高度
this.bitmapHP = bitmapHP;
}
public void draw(Canvas canvas, Paint paint) {
if (hp<=0){
MySurfaceView.GAME_STATE=2;//玩家hp归零,游戏结束
}
if (noCollision) {
noCollisionCount++;//如果碰撞,碰撞次数加一
if (noCollisionCount % 5 == 0) {
canvas.drawBitmap(bitmap, x, y, paint);
}
if (noCollisionCount > 100) {
noCollision = false;
noCollisionCount = 0;
}
} else {
canvas.drawBitmap(bitmap, x, y, paint);
}
for (int i = 0; i < hp; i++) {
canvas.drawBitmap(bitmapHP, i * bitmapHP.getWidth(), MySurfaceView.Height - bitmapHP.getHeight(), paint);
}
}
public void touchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
// x = (int) event.getX();
// y = (int) event.getY();
float ex = event.getX();
float ey = event.getY();
if (ex > x && ex < x + width && ey > y && ey < y + height) {
x = (int) ex - width / 2;
y = (int) ey - height / 2;
if (y < 0) {
y = 0;
}
if (y + height > MySurfaceView.Height) {
y = MySurfaceView.Height - height;
}
}
}
}
public boolean isCollision(Bullet bullet) {
if (noCollision) {
return false;
} else {
if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {
Log.e("AAA", "isCollision: .................................");
noCollision = true;
if (hp >0) {
hp--;
}
return true;
}
}
return false;
}
public boolean isCollision(BossPlane bossPlane) {
if (noCollision) {
return false;
} else {
if (bossPlane.getY() + bossPlane.getH() > y && bossPlane.getY() + bossPlane.getH() < y + height) {
if (x < bossPlane.getX() && x + width > bossPlane.getX()) {
noCollision = true;
if (hp > 0) {
hp--;
}
return true;
}
if (x>bossPlane.getX()&&x+width<bossPlane.getX()+bossPlane.getX()){
noCollision = true;
if (hp > 0) {
hp--;
}
return true;
}
if(x<bossPlane.getX()&&x+width>bossPlane.getX()+bossPlane.getW()){
noCollision = true;
if (hp > 0) {
hp--;
}
return true;
}
}
return false;
}
}
public int getX () {
return x;
}
public int getY () {
return y;
}
public int getWidth () {
return width;
}
}
plane = new MyPlane( BitmapFactory.decodeResource(getResources(), R.mipmap.myplane),BitmapFactory.decodeResource(getResources(),R.mipmap.myhp));//在run方法中添加绘制
电脑飞机同理
四、如何绘制子弹
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
public class Bullet {
private Bitmap bitmap;
private int x,y;
private int speed=10;//定义子弹滚动速度
private boolean isOut;//定义子弹状态
private int type;//定义子弹类型
public Bullet(Bitmap bitmap,int x,int y,int type) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
this.type = type;
}
public void draw(Canvas canvas, Paint paint){
canvas.drawBitmap(bitmap,x,y,paint);
lg();
}
private void lg(){
switch (type){
//玩家子弹
case 0:
y-=speed;
if(y<0){
isOut = true;//如果子弹坐标离开屏幕,判断为isout状态
}
break;
case 1:
//Boss子弹
y+=speed;
if (y<0){
isOut = true;
}
break;
default:
break;
}
}
public boolean isOut() {
return isOut;
}
public Bitmap getBitmap() {
return bitmap;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setOut(boolean out) {
isOut = out;
}
}
private Vector<Bullet> bulletVector = new Vector<>();//添加子弹数组
if(count%20==0){
gameSoundpool.playSound(1);
Bullet bullet = new Bullet(BitmapFactory.decodeResource(getResources(),R.mipmap.mybullet),plane.getX()+plane.getWidth()*2/5,plane.getY(),0);
bulletVector.add(bullet);//每绘制一次子弹,往数组里添加一次
for(int i=0;i<bulletVector.size();i++){
if(bulletVector.elementAt(i).isOut()){
bulletVector.remove(i);//如果子弹状态为isout则删除它
}
}
五、如何判断碰撞
public boolean isCollision(Bullet bullet) {
if (noCollision) {
return false;
} else {
if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {
Log.e("AAA", "isCollision: .................................");
noCollision = true;
if (hp >0) {
hp--;
}
return true;
}
}
return false;
}//如果飞机图片与子弹图片相交判断为碰撞
public boolean isCollision(BossPlane bossPlane) {
if (noCollision) {
return false;
} else {
if (bossPlane.getY() + bossPlane.getH() > y && bossPlane.getY() + bossPlane.getH() < y + height) {
if (x < bossPlane.getX() && x + width > bossPlane.getX()) {
noCollision = true;
if (hp > 0) {
hp--;
}
return true;
}
if (x>bossPlane.getX()&&x+width<bossPlane.getX()+bossPlane.getX()){
noCollision = true;
if (hp > 0) {
hp--;
}
return true;
}
if(x<bossPlane.getX()&&x+width>bossPlane.getX()+bossPlane.getW()){
noCollision = true;
if (hp > 0) {
hp--;
}
return true;
}
}
return false;
}
}//如果玩家飞机与电脑飞机图片相加判断碰撞
六、如何绘制爆炸效果
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
public class Boom {
private Bitmap bitmap;
private int x,y;
private int currentFrame;//当前显示的第几副画面
private int totalFrame;
private int frameW,frameH;
private boolean isOut;
public Boom(Bitmap bitmap, int x, int y, int totalFrame) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
this.totalFrame = totalFrame;
frameH = bitmap.getHeight();
frameW = bitmap.getWidth()/totalFrame;
}
public void draw(Canvas canvas, Paint paint){
canvas.save();
canvas.clipRect(x,y,x+frameW,y+frameH);
canvas.drawBitmap(bitmap,x-currentFrame*frameW,y,paint);
canvas.restore();
lg();
}
public void lg(){
if(currentFrame<totalFrame){
currentFrame++;//当前帧数小于总帧数,帧数加一
}else {
isOut = true;//爆炸效果状态判断为isout
}
}
public boolean isOut() {
return isOut;
}
}
//爆炸效果逻辑与子弹逻辑基本相同判断子弹与电脑飞机碰撞时产生爆炸效果
七、如何添加音效
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
public class GameSoundpool {
private SoundPool soundPool;
private int s1;
private int s2;
public GameSoundpool(Context context) {
this.soundPool = new SoundPool(2, AudioManager.STREAM_MUSIC,0);
s1 = soundPool.load(context, R.raw.shoot,1);
s2 = soundPool.load(context, R.raw.explosion2,1);
}
public void playSound(int s){
switch (s){
case 1:
soundPool.play(s1,1,1,0,1,1.0f);
break;
case 2:
soundPool.play(s2,1,1,0,1,1.0f);
break;
}
}
}//添加case情况,在需要的时候插入音效即可
哪些地方用到封装、继承、多态、方法重载、接口等
在每个子类中实现不同属性的封装
在玩家飞机类与Boss飞机类位置的方法在Mysurfaceview里实现继承
在玩家飞机生命值与Boss生命值范围使用多态
在玩家飞机与Boss飞机范围碰撞使用了方法重载
我的收获与感悟
这次飞机大战的编写,感觉还是有点吃力。代码逻辑理解方面没什么问题,但是要新记好多代码及用法,看着一份逻辑可以实现很多其他功能,但要完全自己写,感觉还需要假以时日。