一.飞机大战的整体思路:

飞机大战的主要使用的方法大纲:

1.概略:

Android的飞机大战用的是SurfaceView()来写,那么首先我们要继承SurfaceView这个类,然后我们还需要用多线程的来运行,那么还要实现Runnable以及SurfaceHolder.CallBack接口。实现多线程就必须要用到run()方法。
由于飞机大战的大部分工作是需要画图片到app里,那么我们又会用到Canvas这个类,这个类是画布类,所有的图片都需要画在Canvas的对象上。
然后,我们需要把图片转换成Bitmap格式。
那么,总结一下:飞机大战使用的最重要的一些类,接口和方法分别是
SurfaceView();Runnable;SurfaceHolder.CallBack;Canvas;Bitmap以及run()方法。

2.规划大概要写的类以及要实现的效果

(1)进入界面的类(Start):

构建一个Start类,这个界面上会有三张图片:背景图,logo图,开始游戏的按钮图。
那么,我们就要定义三张图片的X,Y坐标变量,还有Bitmap变量,这些变量都用private进行修饰,这是用了Java的封装,提高了代码的安全性。
然后,开始游戏按钮需要点击屏幕然后进入游戏界面,这里就用到了onTouchEvent()这个方法,那么我们就需要在SurfaceView的子类里复写这个方法,然后把start类的touchEvent()方法调用过去。

(2)进入游戏界面(需要多个类)

在进入到游戏界面时,我们需要建背景类(Background)我的飞机类(MyPlan)
boss飞机类(BossPlan)子弹类(MyBullet)爆炸类(Boom)
音效类(GameSoundPool) ,一共6个类。
首先,游戏界面的背景需要滚动,那么要在背景类(Background)将图片进行无限的循环
在游戏界面,我们要移动自己的飞机和Boss飞机对战,那么自己飞机就需要可移动,那么同样要在MyPlan类里写一个touchEvent()方法。
boss飞机会进入疯狂模式,那么要在boss飞机类(BossPlan)写一个方法来判断它什么时候进入这个模式以及持续的时间。
子弹发射出去有它的速度和频率,那么在子弹类(MyBullet)里要对这些进行判断。
子弹击中飞机以及飞机撞到飞机会产生爆炸效果,我们需要在MyPlanBossPlan类里分别判断飞机是否被击中或者是否被撞到。
子弹发射会有声音,以及爆炸时的爆炸声,这时我们要在音效类(GameSoundPool)里使用load()方法调用音效,然后再用play()方法播放。在使用音效前要先实例化SoundPool的对象,SoundPool是返回一个int类型的值,那么要先int一个整数来接受它,这些变量的声明都用private修饰

3.分步进行详细操作

(1)如何绘制循环滚动背景图片

当第一张图片的y轴大于屏幕的高度时,说明第一张图片滚动结束了,用第二张图片的y轴减去图片高度,这时第一张图片下一次的y轴就在这。
滚动逻辑代码:

public void logic() {y1 += 3;y2 += 3;if (y1 > MySurfaceView.height) {y1 = y2 - bitmap1.getHeight();  //当y轴大于手机屏幕高度,下一张图的y轴减去图片高度,第一张图片下一次的y轴就在这}if (y2 > MySurfaceView.height) {y2 = y1 - bitmap1.getHeight();}}

(2)如何绘制飞机

绘制飞机的图片用Canvas的对象调用draw()方法就行了,由于飞机需要根据手指移动,那么就要判断当手指的坐标在飞机内移动,飞机才会跟随移动,否则飞机不动。
触摸事件就要用toTouchEveny()方法来写,boss飞机有疯狂模式,要定义一个计数器来判断它进入疯狂模式的时间
触摸事件逻辑代码:

   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;//起始坐标(0,0)在左上角,移动的话会向反方向,把起始坐标调整到它中间y = (int) ey - height / 2;if (y < 0) {y = 0;}if (y > MySurfaceView.height - height) {y = MySurfaceView.height - height;}if (x < 0) {x = 0;}if (x > MySurfaceView.width - width) {x = MySurfaceView.width - width;}}}}

判断boss飞机是否进入疯狂模式代码

private int count;             //疯狂模式计数器
private int crazySpeed = 45;   //疯狂模式速读
private int time = 200;        //疯狂模式时间
private boolean isCrazy;       //是否进入疯狂模式public void logic(){count++;if(isCrazy){                        //判断boss飞机是否进入疯狂模式y = y+crazySpeed;crazySpeed--;if(y==0){isCrazy = false;crazySpeed = 50;}}else{if(count%time==0){isCrazy = true;}x = x+speed;if(x < 0){speed = -speed;}if(x > MySurfaceView.width - oneW){speed = -speed;}}}

(3)如何绘制子弹

子弹是连续发射的,那么不光要将它画出来,在MysurfaceView里面还要定义两个Vector数组,分别用来添加我的飞机和Boss飞机射出的子弹,将每一发子弹都add进去,然后将子弹画到界面里,而且要判断子弹是否飞出界面,一旦飞出界面,立马将它删除
定义数组代码:

 private Vector<MyBullet> bulletVector = new Vector<>();             //用Vector数组定义一个子弹类数组private Vector<MyBullet> bossBulletVector = new Vector<>();       //用Vector数组定义一个boss子弹类数组

绘制boss子弹代码:

if (count % 50 == 0) {MyBullet bossBullet = new MyBullet(BitmapFactory.decodeResource(getResources(), R.mipmap.bossbullet), bossPlane.getX(), bossPlane.getY() + bossPlane.getOneH(), 1);MyBullet bossBullet1 = new MyBullet(BitmapFactory.decodeResource(getResources(), R.mipmap.bossbullet), bossPlane.getX() + bossPlane.getOneW(), bossPlane.getY() + bossPlane.getOneH(), 1);bossBulletVector.add(bossBullet);           //把boss子弹对象加到boss子弹数组里bossBulletVector.add(bossBullet1);}for (int i = 0; i < bossBulletVector.size(); i++) {bossBulletVector.elementAt(i).draw(canvas, paint);myPlane.isCollision(bossBulletVector.elementAt(i));
}

绘制我的子弹代码:

if (count % 10 == 0) {MyBullet myBullet = new MyBullet(BitmapFactory.decodeResource(getResources(), R.mipmap.mybullet), myPlane.getX(), myPlane.getY(), 0);MyBullet myBullet1 = new MyBullet(BitmapFactory.decodeResource(getResources(), R.mipmap.mybullet), myPlane.getX() + myPlane.getWidth(), myPlane.getY(), 0);bulletVector.add(myBullet);bulletVector.add(myBullet1);gameSoundPool.playSound(1);//添加射击音效}
for (int i = 0; i < bulletVector.size(); i++) {bulletVector.elementAt(i).draw(canvas, paint);if (bossPlane.isCollision(bulletVector.elementAt(i))){      //判断我的子弹是否击中boss飞机,击中就画一张爆炸图Boom boom = new Boom(BitmapFactory.decodeResource(getResources(),R.mipmap.boom),bossPlane.getX(),bossPlane.getY(),7);boomVector.add(boom);gameSoundPool.playSound(2); //在爆炸时添加爆炸音效}}                        

移除子弹代码

//移除消失的boss子弹for (int i = 0; i < bossBulletVector.size(); i++) {if (bossBulletVector.elementAt(i).isDead()) {bossBulletVector.remove(i);}}
//移除消失我的的子弹for (int i = 0; i < bulletVector.size(); i++) {if (bulletVector.elementAt(i).isDead()) {bulletVector.remove(i);}}

判断子弹是否超出边界代码

public void logic(){switch (temp){case 0:y -= speed + 3;               //我的子弹的坐标if(,y < 0){                //对我的子弹是否超过屏幕边界判断isDead = true;}break;case 1:y += Bspeed + 3;                       //boss子弹的坐标if(y > MySurfaceView.height){         //对boss子弹是否超过屏幕边界判断isDead = true;}break;}}

(4)如何判断碰撞(子弹与飞机碰撞,飞机与飞机碰撞)

我的飞机如果受到了碰撞,那么会进入一段时间的无敌状态,要先定义一个boolean值,然后进行判断,当碰撞到时,让飞机闪烁,不然就不闪烁,这里要定义一个计数器
判断飞机是否碰撞也是先定义一个Boolean值,然后对坐标是否重合进行判断,
判断我的飞机是否是无敌时间代码:

private boolean noCollision;    //判断是否进入无敌时间
private int noCollisionCount;  //无敌时间计数public void draw(Canvas canvas, Paint paint) {if (hp <= 0){MySurfaceView.GameStart = 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);}}

判断我的飞机是否被碰撞代码

/*** 判断子弹是否击中飞机** @param* @return*/public boolean isCollision(MyBullet 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;}/*** 判断我的飞机是否撞上boss飞机*/public boolean isCollision(BossPlane bossPlane) {if (noCollision){return false;}else {if(y > bossPlane.getY()+bossPlane.getOneH()||y+height  < bossPlane.getY()||x+width < bossPlane.getX()||x >bossPlane.getX()+bossPlane.getOneW()){}else {noCollision = true;if (hp>0){hp--;}return true;}}return false;}

判断boss飞机是否被我的子弹击中代码

public boolean isCollision(MyBullet bullet){if (bullet.getX() > x&&bullet.getX()+bullet.getBitmap().getWidth() < x+oneW&&bullet.getY() > y&&bullet.getY() < y+oneH){bossHp--;bullet.setDead(true);if (bossHp < 0){MySurfaceView.GameStart = 2;}return true;}return false;}

(5)如何绘制爆炸效果

首先,爆炸的图片不止一帧,要一帧一帧依次播放,先要定义两个整数 帧数和播放第几帧,
然后再用Vector数组实例化一个爆炸数组,把一帧一帧的图片add进去,然后在绘制我的子弹时,进行判断,如果我的子弹击中boss飞机,那么就将爆炸数组里的图片画一次,然后将结束爆炸的图删去。
显示爆炸图片的逻辑代码

public void logic() {if (currentFrame < totalFrame) {currentFrame++;} else {isEnd = true;}}

定义爆炸数组

private Vector<Boom>boomVector = new Vector<>();                //爆炸图的数组,显示图片的每一帧画面

判断我的子弹是否击中boss飞机

if (bossPlane.isCollision(bulletVector.elementAt(i))){      //判断我的子弹是否击中boss飞机,击中就画一张爆炸图Boom boom = new Boom(BitmapFactory.decodeResource(getResources(),R.mipmap.boom),bossPlane.getX(),bossPlane.getY(),7);boomVector.add(boom);}

(6)如何添加音效

这里音效有两种,一种是游戏内的子弹声和爆炸声,还有一种是背景音乐,游戏内声音用的是
SoundPool来写,背景音乐用MediaPlayer写。游戏内的音乐建一个类来写,
先用load方法添加,再用play方法播放,最后用这个类的对象来调用play方法,再将它插入需要播放的地方,
背景音乐直接在 主类的run方法里写。
游戏内音效代码

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.explosion3,1);s3 = soundPool.load(context,R.raw.bgm_zhuxuanlv,1);}public void playSound(int s){switch (s){case 1:/*** 第一个参数是 音效对象,第二和第三个参数是左,右声道音量,第四个是优先级,第五个是是否循环,第六个是播放倍速*/soundPool.play(s1,1,1,2,0,2f);//break;case 2:soundPool.play(s2,1,1,1,0,1f);break;case 3:soundPool.play(s3,1,1,3,0,2f);}}}

将游戏内音效添加到需要的地方
射击声:在绘制子弹里添加

if (count % 10 == 0) {MyBullet myBullet = new MyBullet(BitmapFactory.decodeResource(getResources(), R.mipmap.mybullet), myPlane.getX(), myPlane.getY(), 0);MyBullet myBullet1 = new MyBullet(BitmapFactory.decodeResource(getResources(), R.mipmap.mybullet), myPlane.getX() + myPlane.getWidth(), myPlane.getY(), 0);bulletVector.add(myBullet);bulletVector.add(myBullet1);gameSoundPool.playSound(1);//添加射击音效}

爆炸声:在画出爆炸图时

for (int i = 0; i < bulletVector.size(); i++) {bulletVector.elementAt(i).draw(canvas, paint);if (bossPlane.isCollision(bulletVector.elementAt(i))){      //判断我的子弹是否击中boss飞机,击中就画一张爆炸图Boom boom = new Boom(BitmapFactory.decodeResource(getResources(),R.mipmap.boom),bossPlane.getX(),bossPlane.getY(),7);boomVector.add(boom);gameSoundPool.playSound(2); //在爆炸时添加爆炸音效}}

背景音乐代码

/*** 添加背景音乐*/mediaPlayer = MediaPlayer.create(getContext(),R.raw.balu);mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {mediaPlayer.start();mediaPlayer.setVolume(1,1);}});

(7)有哪些地方使用了封装,继承,多态,方法重载等

方法重载:这里判断我的飞机是被子弹击中,还是被boss飞机撞击用了方法重载
代码

/*** 判断子弹是否击中飞机** @param* @return*/public boolean isCollision(MyBullet 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;}/*** 判断我的飞机是否撞上boss飞机*/public boolean isCollision(BossPlane bossPlane) {if (noCollision){return false;}else {if(y > bossPlane.getY()+bossPlane.getOneH()||y+height  < bossPlane.getY()||x+width < bossPlane.getX()||x >bossPlane.getX()+bossPlane.getOneW()){}else {noCollision = true;if (hp>0){hp--;}return true;}}return false;}

继承和接口:主类继承了SurfaceView,实现了Runnable和SurfaceHolder.Callback接口。

封装:所有的类里定义的变量都是用private修饰,都用到了封装,体现了Java的安全性
比如:我的飞机类里定义的变量都是private型。
代码:

    private int x;private int y;private Bitmap bitmap;private Bitmap bitmapHp;private int height, width;private boolean noCollision;    //判断是否进入无敌时间private int noCollisionCount;  //无敌时间计数private int hp = 3;            //血量初始值为三

如果别的类想要调用封装的变量,可以用set,get’方法,比如:
get,set方法代码

 public int getX() {return x;}public int getY() {return y;}public int getWidth() {return width;}
}

二.对于飞机大战的收获与感悟

经过一个月的学习,对以前学习过的和没有学习过的Java知识进行了全面的复习和总结,在前几周,没有写飞机大战这个项目之前,我以为自己的基础学习的还可以,对于基本的概念以经可以流畅的应用了,但是我也知道我自己的缺点在于不能把这些知识点串联起来使用,我只时在每一小节的运用上比较熟练,但是当项目复杂以及涉及的内容和知识点过多时,就会产生一种力不从心的感觉,特别是让我自己去写一个项目的时候,常常是没有任何的头绪,不知道该从哪写起,程序报错了,也不会学着去看错误提示,不会自己试着改正。
通过这个项目的编写,我学会了自我学习的习惯,知道要自己先思考问题,自己先解决错误,到最后在和别人讨论,这样才能收获到更多的东西,才能吸取到精华,如果只是单单把别人的东西拿过来抄一遍,效果是没什么用。一定是自己思考过后。再讨论才有更多自己的想法,而且有时候我觉得我不行,我写不了,但是多想,多思考,然后再到网上学 ,这个问题说不定就能被我自己给解决了。这时,一种满足感油然而生,这种满足感会促使着我不断的去学习,然后不断地进步。
这一次写飞机大战这个项目,我有学会了使用AndroidStudio这个编译工具,说起AndroidStudio的安装,我还真费了好大的劲,最后重置了系统才把它搞定,但是有好多的报错都是我自己一个一个去网上百度,自己解决的,这也加深了我对这些错误的理解,以后遇到了可以更好的去解决它们。
这一次的学习中,不光学到了技术,最重要的是还学到了一些态度,对待学习的态度,一定要多学,多思考,多问。不光是学习,很多方面都是如此。
最后,希望自己在接下来的时间里,能把这个飞机大战的项目多写几遍,把各种知识的串联使用的熟练一点,然后再写一些小项目来提升自己的实力。

Android 飞机大战详解与感悟相关推荐

  1. android 飞机大战详解

    一. 整体实现思路 飞机是一个对象,这个对象的属性包括血量.x,y轴,图片 飞机在飞行中会发射子弹,所以飞机应该对应着一个子弹的线程 因为子弹飞行过程中,以及飞机飞行过程中都会碰到障碍物(子弹.敌机) ...

  2. 【18.5.31 日常】Android项目——飞机大战详解

    整体实现思路 通过两张背景图片实现背景滚动,同时做出能根据用户触摸位置不同而改变位置的飞机,能够不停地射出子弹,Boss同理,Boss移动方式随机,同时添加小飞机以增强游戏的表现力,外加例如激光之类的 ...

  3. 飞机大战详解 C语言

    小游戏就以飞机大战为例吧 首先说一下我对游戏的理解,游戏主要就是由动画.交互两大部分组成, 而动画则是由一帧一帧的图片组成. 所以要想在控制台中实现动画,那就要实现屏幕的刷新,就是把上一帧 的图片给清 ...

  4. 《Android游戏开发详解》——第1章,第1.6节函数(在Java中称为“方法”更好)...

    本节书摘来自异步社区<Android游戏开发详解>一书中的第1章,第1.6节函数(在Java中称为"方法"更好),作者 [美]Jonathan S. Harbour,更 ...

  5. JMessage Android 端开发详解

    JMessage Android 端开发详解 目前越来越多的应用会需要集成即时通讯功能,这里就为大家详细讲一下如何通过集成 JMessage 来为你的 App 增加即时通讯功能. 首先,一个最基础的 ...

  6. 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...

  7. Android事件流程详解

    Android事件流程详解 网络上有不少博客讲述了android的事件分发机制和处理流程机制,但是看过千遍,总还是觉得有些迷迷糊糊,因此特地抽出一天事件来亲测下,向像我一样的广大入门程序员详细讲述an ...

  8. Android Studio 插件开发详解二:工具类

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78112856 本文出自[赵彦军的博客] 在插件开发过程中,我们按照开发一个正式的项 ...

  9. 《Android游戏开发详解》一2.16 区分类和对象

    本节书摘来异步社区<Android游戏开发详解>一书中的第2章,第2.16节,作者: [美]Jonathan S. Harbour 译者: 李强 责编: 陈冀康,更多章节内容可以访问云栖社 ...

最新文章

  1. Python中值传递和引用传递区别
  2. C++ 的语言杂谈(一)--C++不是新手友好的
  3. 福建高职单招计算机基础知识,福建高职单招计算机类试题及标准答案
  4. java中的boolean_java中boolean的用法
  5. python爬虫与数据分析实战27_Python网络爬虫与文本数据分析
  6. Ubuntu 20.04 LTS(Focal Fossa)发布
  7. CentOS发行版本介绍
  8. ubuntu或者fedora下编译淘宝tair key-value-db的开源内存数据库
  9. Shell脚本8种字符串截取方法总结
  10. 主题背景_游戏背景音乐的种类—主题曲
  11. c++实现八大排序算法
  12. fences(桌面整理软件)与eDiary3.3.3下载链接
  13. 第二次作业-时事点评
  14. 【解密】PDF文档忘记编辑密码 照样编辑
  15. 怎么使计算机桌面整洁,如何管理电脑桌面,让桌面清洁,干净,大气......
  16. 途牛2021年第三季度营收约1亿元,同比、环比均有所下降
  17. 算数右移逻辑右移java的表示_java的算术右移()与逻辑右移()
  18. 服务器项目报备什么意思,报备项目是什么意思
  19. 【金融量化】期货中的对手价、市价、排队价、最新价分别表示什么价位
  20. Springboot(编程不良人)

热门文章

  1. GPT-3杀入漫威宇宙!二次元小伙用它生成蜘蛛侠续集
  2. 反渗透处理设备采用海水淡化膜时注意事项
  3. Cinema 4D 办公楼建筑效果图表现
  4. linux希捷移动硬盘驱动,Seagate移动硬盘驱动程序
  5. html css布局作品,130个漂亮CSS布局站点参考_CSS/HTML
  6. 金融行业数字化转型应该如何进行?
  7. 如何使用 Python 对 Excel 截图
  8. Android直播开发之旅(18):FFmpeg中滤镜(filter)的工作原理
  9. 特斯拉柏林超级工厂又突发火灾;多模态人工智能产业联合体第二次大会召开;奇瑞汽车战略投资AI芯片公司 | 每日大事件...
  10. OpenWRT配置WAN口和LAN口