飞机大战游戏详解
1.整体实现思路
先创建类,主类,子弹类,我方和敌方飞机类,背景类,血量类,爆炸类等等。
vector数组写我方小飞机和boss飞机的子弹和爆炸的效果,循环。
onTouchEvent方法移动小飞机,手指点到小飞机上,手指往哪里移动小飞机就往哪里移动,永远监听屏幕触摸事件。
小飞机与boss飞机碰撞的时候,小飞机被大boss子弹打中的时候血量会减少一。可以自由设定血量减少的时候无敌状态的时间。
画背景图,小飞机,boss飞机,血量,子弹,爆炸效果。需要用到canvas和drawBitmap。
定义了三个音效,子弹打中的时候、子弹爆炸的时候和飞机与boss战斗的时候,利用的soundpool的方法实现了。
当小飞机没有生命会显示你输掉了,boss没有血量你显示你赢了
2.如何绘制背景
定义一个 y1,y2,来确定坐标。
写出图片移动的速度。
利用logic让两张一样的图片反复循环,当第一张图片开始向下走的时候第二张图片接上去,当第一张图片彻底结束的时候,瞬间补位到第二张图片上面,依次执行下去。
package com.example.myapplication; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; 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,Paint paint){ logic(); canvas.drawBitmap(bitmap,0,y1,paint); canvas.drawBitmap(bitmap,0,y2,paint); } public void logic() { y1+=10; y2+=10; if (y1>=MySurfaceView.height){ y1=y2-bitmap.getHeight();//移动到第二张图片的顶部 } if (y2>=MySurfaceView.height){ y2=y1-bitmap.getHeight(); } } }
3.如何绘制飞机
定义一个x,y 长度,宽度。
定义出我方飞机的血量,高度,宽度
再定义boss飞机的飞行速度,疯狂模式的速度,每隔多长时间进行一次疯狂模式,一个计时器,和boss飞机的血量
小飞机和boss飞机的代码原理类似,小飞机没有疯狂模式
package com.example.myapplication; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.util.Log; public class BossPlane { private Bitmap bitmap; private int x,y; private int frameW,frameH; private int speed=5;//boos飞机的速度 private int crazySpeed=50;//疯狂速度 private int count;//计数器 private int time=500;//疯狂模式间隔 private boolean isCrazy; private int bossHp = 100; public BossPlane(Bitmap bitmap) { this.bitmap = bitmap; this.frameW = bitmap.getWidth()/10; this.frameH = bitmap.getHeight(); x=MySurfaceView.width/2-frameH/2; } public void draw(Canvas canvas, Paint paint){ canvas.save(); canvas.clipRect(x,y,x+frameW,y+frameH); canvas.drawBitmap(bitmap,x,y,paint); canvas.restore(); logic(); } public void logic(){ count++; if (isCrazy){ y = y+crazySpeed; crazySpeed--; if (y==0){ isCrazy = false; crazySpeed = 50; } }else { if (count%time==0){ isCrazy=true; } x = x+speed; if (x>MySurfaceView.width-frameH){ speed = -speed; } if (x<0){ speed = -speed; } } } public boolean isCollision(Bullet bullet){ if(bullet.getX()>x&&bullet.getX()+bullet.getBitmap().getWidth()<x+frameW&&bullet.getY()>y&&bullet.getY()<y+frameH){ bossHp--; bullet.setDead(true); if (bossHp<0){ MySurfaceView.GAME_STATE = 1; } return true; } return false; } public int getX() { return x; } public int getY() { return y; } public int getFrameW() { return frameW; } public int getFrameH() { return frameH; } }
package com.example.myapplication; 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.bitmap = bitmap; this.bitmapHp = bitmapHp; 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_STATE = 2; } 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); } } public void touchEvent(MotionEvent event){ if (event.getAction()==MotionEvent.ACTION_MOVE){ float ex = (int) event.getX(); float ey = (int) 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){ noCollision = true; if (hp>0){ hp--; } return true; } } return false; } public boolean isCollision(BossPlane bossPlane) { if (noCollision){ return false; }else{ if(bossPlane.getY()+bossPlane.getFrameH()>y&&bossPlane.getY()+bossPlane.getFrameH()<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.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; } }
4.如何绘制子弹
子弹的速度为10,
用到了switch if判断
如果子弹没有打中boss,当飞到顶面的时候就删除子弹
打出去的子弹不需要考虑x,只需要考虑y的变动,还有是否击中了boss或者没有飞出了屏幕
package com.example.myapplication; 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 isDead; 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 Bullet() { } public void draw(Canvas canvas, Paint paint) { canvas.drawBitmap(bitmap, x, y, paint); logic(); } public void logic() { switch (type){ //玩家子弹 case 0: y -= speed+5; if (y < 0) { isDead = true; } break; //Boss子弹 case 1: y += speed+8; if (y < 0) { isDead = true; } break; default: break; } } public boolean isDead() { return isDead; } public Bitmap getBitmap(){ return bitmap; } public int getX(){ return x; } public int getY() { return y; } public void setDead(boolean dead) { isDead = dead; } }
5.如何判断碰撞(子弹与飞机的碰撞,飞机与飞机的碰撞)如何绘制爆炸效果
需要数组的帮助。
子弹击中boss的时候,爆炸图片分为了七部分,但不是同时显示出来,需要修一下图片,让它依次出现,当最后一个boom出现的时候就不再显示。等到下个boom出现。
package com.example.myapplication; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; public class Boom extends Bullet { 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) { super(); 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; } }
6.如何添加音效
背景音乐,新建一个raw,然后插入音乐
定义一个值为s
给s赋值
之后再调用就完成了
package com.example.myapplication; import android.content.Context; import android.media.AudioManager; import android.media.SoundPool; public class GameSoundPool { private SoundPool soundPool; private int s1; private int s2; private int s3; 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); s3 = soundPool.load(context,R.raw.bgm_zhandou2,1); } public void playSound(int s) { switch (s){ case 1: soundPool.play(s1,1,1,1,1,1.0f); break; case 2: soundPool.play(s2,1,1,1,1,1.0f); break; case 3: soundPool.play(s3,1,1,1,1,1.0f); break; } } }
7.那个地方用到了继承,封装,接口,多态,方法重载等
MySurfaceView用到了继承
所有的类都用了封装
MySurfaceView实现了接口
没用到多态
重载在判断是boss子弹击中还是boss撞的时候用到重载
8.我的收获与感悟
经过了一个月的学习,收获颇多。原来java老师讲的非常的好,也很乐于给我们解答我们不会的疑难。可惜的是我却错过了他,在他的两个月授课中,我可以说是一点没有学到,开始两节课我还听讲,后来因为一些琐事上课就只顾着玩qq微信,和朋友聊天。上课根本就是玩。原来是小白现在还是小白。
一个月前,联想企业派了一位优秀的讲师来到我的学校,从头开始叫我们java 安卓。我心想,这次上课一定要好好的,不能再继续放纵自己不学习了。上第一节课的时候,老师讲了一些java非常基础的东西,比如八种基础类型。我原来还是不会这些的,幸好我哥哥发了一些资料给我,我看了一点。加上老师的复习巩固,我对于自己已经会的知识又复习了一遍。开始的一个星期老师知道我们学的不好,所以讲的非常的慢,这对于学习好的同学有点不公平,但我们班还是学的不好的占了大多数。所以老师还是为了我们考虑。
第二个星期,老师开始教我们做项目。一个图书馆里系统, 开始学的时候我感觉有点吃力了,加上老师让我上去改题目。我像个傻子一样站在上面什么都不会,然后艰难的说出了三个字“我不会”。那时候的感觉真的很难过。于是我便更加努力的学习图书管理系统。为的是老师再次叫我的时候我不再说出那几个字。
那些代码虽然看的明白,但是要是脱离了老师的代码模板,我感觉我写不出什么实质性的东西。可是我感觉我还是比以前有进步了,至少现在还肯自己去写,哪怕是借鉴的老师的代码。最后老师考核我们,让我们做一个和图书馆里系统差不多的自动售水机系统。老师说了不要看之前的代码,自己写。但我没有做到。虽然我看了之前的代码,但是我至少也把这个系统当差不差的写了出来。在规定的时间内也完成了任务。那是的我真的很开心。
时间过去一半,我们迎来了我们的实训一个月最大的难关,就是用以前从来没用过的android studio写一个小游戏。飞机大战。
在这不到两个星期的时间,我感觉我的状态虽然和以前一样,但是上课所听的东西却比以前难了,老师也知道,所以每次教完都留好多时间让我们自己消化。我就靠着自己上课录下来的视频,一步一步的打。最终也打了出来,但终究没有自己创新的成分再其中,感觉有瑕疵,很大的瑕疵,还是需要自己以后多练习,多理解其中的意思。
一个月的联想课程虽然结束了,但是我们的学习路程还没结束,还有好长的一段路要走。以后的日子里,我们还是需要一步一个脚印的加油。将来成功的自己会感谢以前发奋拼命的自己。