整体实现思路
主要分为以下步骤
1.实现循环背景滚动
2.添加玩家飞机
3.玩家飞机发射子弹
4.添加Boss飞机
5.Boss飞机发射子弹
6.飞机被击中血量减少及无敌状态
7.玩家飞机和子弹碰撞,Boss和玩家飞机碰撞
8.子弹击中飞机爆炸效果
9.添加音效
10.添加游戏开始和结束界面
如何绘制循环滚动的背景图片
先是定义一个X和Y坐标,然后把图片在画布上画出来,获取背景。
然后做一个判断语句,当背景图片长度小于屏幕长度时 重置图片。
代码如下:
/**
* 背景
*/
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
public class BackGroud {
private int y1;
private int y2;
private Bitmap bitmap;
public BackGroud(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+=10;y2+=10;if(y1>=bitmap.getHeight()){y1 = y2-bitmap.getHeight(); //移动在第二张 上面}if(y2>=bitmap.getHeight()){y2=y1-bitmap.getHeight();}
}
}
如何绘制飞机
创建一个飞机类,玩家飞机比较简单直接绘制出来,然后添加到画布上,但和背景图片的顺序不能颠倒
Boos飞机要用到裁剪,canvas.clip() 这个方法裁剪出一个Boss飞机的大小,然后再添加到画布上。
代码如下:
`/**
*玩家飞机
*/
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
public class Myplane {
private Bitmap bitmap;
private Bitmap bitmapHp;
private int x, y;
private int width, height;
private boolean noCollision;
private int noCollisionCount;
private int Hp = 3;
public Myplane(Bitmap bitmap, Bitmap bitmapHp) {this.bitmapHp = bitmapHp;this.bitmap = bitmap;x = MySurfaceView.width / 2 - bitmap.getWidth() / 2;//中间y = MySurfaceView.height - bitmap.getHeight();width = bitmap.getWidth();height = bitmap.getHeight();
}public void draw(Canvas canvas, Paint paint) {if(Hp<=0){MySurfaceView.Game_start = 3;}if (noCollision) {noCollisionCount++;if (noCollisionCount % 10 == 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);//HP位置}}public void touchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_MOVE) {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;}}}
}
//我方飞机与boss子弹
public boolean isCollision(Bullet bullet) {if (noCollision) {return false;}if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {noCollision = true;if (Hp > 0) {Hp--;}return true;}return false;}
//我方飞机与boss
public boolean Attack(Bossplane bossplane) {if (noCollision) {return false;}if(y<bossplane.getY()+bossplane.getFrameH()&&y+height>bossplane.getY() ){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.getFrameW()) {//我方飞机中间碰撞noCollision = true;if (Hp > 0) {Hp--;}return true;}if (x < bossplane.getX() && x+width > bossplane.getX()+bossplane.getFrameW()) {//我方飞机右边碰撞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;
}public int getHeight() {return height;
}
}
`
如何绘制子弹
创建一个子弹类,同样的也需要把子弹绘制到画布上,子弹需要跟随玩家或者boss移动,所以要获取玩家飞机的位置或者Boss飞机的位置,子弹的速度不能比背景滚动的速度慢,否则当Boss向冲刺的时候就会出现子弹静止不动的情况。
子弹类需要用到数组把要发射的子弹数组放到里面,但是发射的子弹如果不删除就会一直占着内存,导致内存占用一直增大,所以在每一组子弹消失在屏幕的顶端时,就要从数组中删除这组子弹的数据。
代码如下:
public class Bullet {
private int speed=10;
private int x;
private int y;
private Bitmap bitmap;
private int type;
private boolean isDead;
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);logic();
}public void setDead(boolean dead) {isDead = dead;
}public Bitmap getBitmap() {return bitmap;
}public int getX() {return x;
}public int getY() {return y;
}public void logic() {switch (type){//玩家子弹case 0:y -= speed;if (y < 0) {isDead = true;}break;//boos子弹case 1:y += speed;if (y < 0) {isDead = true;}break;}}public boolean isDead() {return isDead;
}
}
如何判断碰撞
当飞机的坐标和子弹的坐标重合时即判定为碰撞,同理玩家飞机和Boss飞机的坐标重合也判定为碰撞
if (noCollision) {return false;}if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {noCollision = true;if (Hp > 0) {Hp--;}return true;}return false;}}
玩家飞机与Boss子弹碰撞
if (noCollision) {return false;}if(y<bossplane.getY()+bossplane.getFrameH()&&y+height>bossplane.getY() ){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.getFrameW()) {//我方飞机中间碰撞noCollision = true;if (Hp > 0) {Hp--;}return true;}if (x < bossplane.getX() && x+width > bossplane.getX()+bossplane.getFrameW()) {//我方飞机右边碰撞noCollision = true;if (Hp > 0) {Hp--;}return true;}}return false;}
如何绘制爆炸效果
首先创建一个Boom类,需要爆炸效果资源图,获取爆炸效果的位置坐标
爆炸效果的构造函数,爆炸效果绘制,爆炸效果的逻辑
代码如下:
mport android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;public class Boom {private Bitmap bitmap;private int x,y;private int totalFrame;private int currentFrame;private int frameW,frameH;private boolean isEnd;//爆炸效果的构造函数public Boom(Bitmap bitmap, int x, int y, int totalFrame) {this.bitmap = bitmap;this.x = x;this.y = y;this.totalFrame = totalFrame;frameW = bitmap.getWidth()/totalFrame;frameH = bitmap.getHeight();}//爆炸效果绘制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();logic();}//爆炸效果的逻辑public void logic(){if(currentFrame<totalFrame){currentFrame++;}else{isEnd = true;}}public boolean isEnd() {return isEnd;}
}
如何添加音效
首先在res文件夹下创建raw文件夹用来存放音频文件,然后要用到SoundPoll,
SoundPool提供了一个构造器,该构造器可以指定它总共支持多少个声音。
SoundPool提供的播放指定声音的方法:
int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate):该方法的第一个参数指定播放哪个声音;leftVolume、rightVolume指定左、右的音量:priority指定播放声音的优先级,数值越大,优先级越高;loop指定是否循环,0为不循环,-1为循环;rate指定播放的比率,数值可从0.5到2, 1为正常比率。
代码如下:
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);this.soundPool = new SoundPool(1,AudioManager.STREAM_MUSIC,0);s1 = soundPool.load(context,R.raw.shoot,1);s2 = soundPool.load(context,R.raw.button,1);}public void playSound(){soundPool.play(s1,1,1,1,1,1.0f);soundPool.play(s2,1,1,1,1,1.0f);}
}
哪些地方用到封装,继承,多态,接口,方法重载
在项目中的每个类都用到了封装,
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{//继承和实现接口
方法的重载
画布裁剪的时候用到了方法的重载
多态
在玩家飞机和子弹碰撞时,玩家飞机和Boss碰撞时,做出不同的反应
我的收获与感悟
四个星期的实训不知不觉中已经到了尾声,前两个星期基本上都时教的java基础,由于学校老师教的课听的不是很懂,所以听的很认真,没天虽然有些疲惫但每天的都有收获,说实话在实训课之前,在学校JAVA基本上等于没学,但经过前两个星期的课程对JAVA的基本知识和结构不敢说都会但也能看懂代码了,但由于基础不是很好,所以有些知识掌握的还不是很全面,后两个星期就时主要在Andrio Studio中做飞机大战这个项目,刚开始的时候老师演示项目成品的时候,心想这是我们能做出来的吗?,经过两个星期课程里面大部分都是和JAVA相关的知识,项目刚刚开始的时候勉强能够跟上,由于对一些代码不熟悉,和代码的行数越来越多,越往后感觉越吃力。总之在这四个星期中收获很多,不仅仅是在知识上,学习的方法和一些以后会遇到的事都有了一些了解,虽然努力和收获不一定成正比,但努力一定会有收获。