Java飞机大战

  • 序言
    • 一、项目需求分析
    • 二、各个对象类的设计
      • 加载图片类Images
      • 抽象类FlyingObject
      • 天空类Sky
      • 小敌机类Airplane
      • 大敌机类BigAirplane
      • 侦察机类Bee
      • boss机类BossAirplane
      • 英雄机类Hero
      • 子弹类Bullet
    • 主类World的设计
      • 功能分析
      • 设计World类属性
      • 生成敌人
        • 敌人发射子弹
        • 判断敌人的子弹是否击中英雄机和英雄机是否与敌人相撞
      • 英雄机发射子弹
        • 判断英雄机发射的子弹是否击中敌人
        • 对象都动起来
      • 清除状态为REMOVE和超出窗口的敌人和子弹
      • 英雄没命游戏结束
      • 在画板上画出所有对象
      • 游戏运行方法
      • 旋风无敌大大大招
      • 实现线程运行
    • main方法启动程序
    • 完结撒花
    • 源码百度云

序言

这是我最近开始学习Java接触的第一个正式的项目,前面有一个贪吃蛇的太简单了不算,那个后面优化一下再放上来,这篇文章我会从项目需求开始说起,再到类的设计,最后是主类的设计。写这篇文章也是为了整理我这几天所学的知识,加深我对面向对象基础的理解。

一、项目需求分析

运行基本界面

1)游戏包括
敌机:大敌机、小敌机、侦察机、boss机
我方:英雄机
背景:天空
2)各个对象所具备的功能和特征
大敌机:能发射单倍子弹,有三条生命,从天空上方出现往下走,被击毁后英雄机加三分
小敌机:能发射单倍子弹,有一条生命,从天空上方出现往下走,被击毁后英雄机加一分
侦察机:不能发射子弹,有一条生命,从天空上方出现往下斜着走、碰到边界改变x方向,被击毁后给英雄机随机增加一条生命或者火力
boss机:英雄机100分以后出现,能发射双倍子弹,从天空上方出现往下走,有十条生命,被击毁后英雄机加50分和给英雄机随机增加一条生命或者火力
英雄机:初始生命有三条,初始火力为零,英雄机随着鼠标的位置移动,火力大于零后能发射三发子弹、大于1000后能发射五发。
天空:一个向下移动的背景板什么功能也没有
注:
1.程序运行后有背景音,暂停时没有(鼠标移出游戏界面暂停)
2.一发子弹可以打去一条命
3.敌人在被击毁后有爆炸(包括声音和画面)
4.英雄机在被子弹击中后和死亡都有音效

二、各个对象类的设计

1)对各个类进行分析,以此来设计超类
大敌机:有坐标 x、y,宽,高,生命数,向下移动速度的属性。发射子弹,移动,越界,碰撞,返回分数等行为,具体下面会写。
小敌机:有坐标 x、y,宽,高,生命数,向下移动速度的属性。发射子弹,移动,越界,碰撞,返回分数等行为
侦察机:有坐标 x、y,宽,高,生命数,x、y方向移动速度的属性。发射子弹,移动,越界,碰撞,返会奖励等行为
boss机:有坐标 x、y,宽,高,生命数,向下移动速度的属性。发射子弹,移动,越界,碰撞,返回分数和奖励等行为
英雄机:有坐标 x、y,宽,高,生命数,分数,火力值属性。发射子弹,移动,碰撞等行为
天空:有坐标 x、y,宽,高,向下移动速度的属性。移动行为。
子弹:有坐标 x、y,宽,高,向下或者向上移动速度的属性。移动行为,碰撞,越界等。
可以看出上面的属性和行为有太多的重复,在此设计一个超类有上面共有的属性和方法

下面我直接贴代码了代码有注释的

首先确定,所有的飞机天空子弹都是一张张背景透明的图片,每一此改变它的坐标在将它画到画板上以此形成了连续移动的感觉,就和电影是一个原理。Java的画板类JPanel就为我们提供了将图片显示出来的功能。

加载图片类Images

设计一个加载图片的类,将图片加载到方法区,这样图片只用读取一次

/** 加载图片的类,实现了将各个对象的图片加载到方法区,不用每次都要去读取*/
public class Images {public static BufferedImage sky;public static BufferedImage[] bullets;public static BufferedImage[] bossairplanes;public static BufferedImage[] heros;public static BufferedImage[] airplanes;public static BufferedImage[] bigairplanes;public static BufferedImage[] bees;static{//天空图片的加载sky = readImage("background1.png");//英雄机图片的加载heros = new BufferedImage[2];heros[0] = readImage("hero0.png");heros[1] = readImage("hero1.png");//子弹图片的加载bullets = new BufferedImage[2];bullets[0] = readImage("bullet0.png");bullets[1] = readImage("bullet1.png");//boss机图片的加载bossairplanes = new BufferedImage[5];bossairplanes[0] = readImage("boss.png");//小敌机图片的加载airplanes = new BufferedImage[5];airplanes[0] = readImage("airplane0.png");//大敌机的加载bigairplanes = new BufferedImage[5];bigairplanes[0] = readImage("bigairplane0.png");//侦察机图片的加载bees = new BufferedImage[5];bees[0] = readImage("bee0.png");//爆破图片的加载for(int i=1;i<5;i++){bees[i] = readImage("bom"+i+".png");airplanes[i] = readImage("bom"+i+".png");bigairplanes[i] = readImage("bom"+i+".png");bossairplanes[i] = readImage("bom"+i+".png");}}//读取图片到内存public static BufferedImage readImage(String fileName){try{BufferedImage img = ImageIO.read(FlyingObject.class.getResource(fileName));return img;}catch(Exception e){e.printStackTrace();throw new RuntimeException();}}
}

抽象类FlyingObject


设计抽象类超类FlyingObject

public abstract class FlyingObject {
//共同属性protected int width;protected int height;protected int x;protected int y;protected int life;//状态常量public static final int LIFE = 0;public static final int DEAD = 1;public static final int REMOVE = 2;//当前状态protected int state = LIFE;//为敌人提供的构造方法,FlyingObject(int width,int height,int life){this.width = width;this.height = height;this.x = (int)(Math.random()*(World.WIDTH-width));this.y = -height;this.life = life;}//为天空和英雄机子弹提供的构造方法FlyingObject(int width,int height,int x,int y){this.width = width;this.height = height;this.x = x;this.y = y;}//生成子弹组数的方法public Bullet[] shoot(){return new Bullet[0];}//判断碰撞的方法public boolean hit(FlyingObject other){int x1 = other.x - this.width;int x2 = other.x + other.width;int y1 = other.y - this.height;int y2 = other.y + other.height;return x>=x1 && x<=x2 && y>=y1 && y<=y2;}//生命减一public void subtractLife(){life--;}//判断是否活着public boolean isLife(){return state==LIFE;}//判断是否死了,后面有用public boolean isDead(){return state==DEAD;}//判断状态是否为移除public boolean isRemove(){return state==REMOVE;}//将状态改为DEADpublic void goDead(){state = DEAD;}//在画板上画出图片,getImage()是后面自己写的一个获取图片数据的方法public void paintObject(Graphics g){g.drawImage(getImage(),x,y,null);}//移动抽象方法,因为每个对象移动的方法不一样,又都有移动,所以写为抽象方法public abstract void step();//获取图片的抽象方法,为什么设置为抽象方法如上public abstract BufferedImage getImage();//判断是否越界的抽象方法,如上public abstract boolean outBround();}

对碰撞方法的说明,结合图片和代码看

天空类Sky

/** 继承FlyingObject*/
public class Sky extends FlyingObject {//增加速度属性和y1坐标,因为要保证天空移动的连续,一张图片走了,另一张接着走要不然会出现空白private int speed;private int y1;/** 天空的构造方法,在画板中坐标是最坐上角的点,整个天空是作为背景的,所以坐标为(0,0)* 天空的的宽高既窗口的宽高,World.WIDTH(400)和World.HEIGHT(700),World类里确定*/Sky(){super(World.WIDTH,World.HEIGHT,0,0);y1 = -this.height;speed = 1;}//天空向下移动,y和y1都增加speed的值public void step() {y += speed;y1 += speed;//保证连续,有图片走出框后将它移到最上方if(y>=World.HEIGHT){y = -this.height;}if(y1>=World.HEIGHT){y1 = -this.height;}}//画两次天空图片,一张在下面,一张在上面,保证背景的连续public void paintObject(Graphics g){g.drawImage(getImage(), x, y, null);g.drawImage(getImage(), x, y1, null);}//获取图片public BufferedImage getImage() {return Images.sky;}//天空没有越界行为直接返回falsepublic boolean outBround() {return false;}}

两张图片都往下走当y大于等于框的高时立即移到上方

小敌机类Airplane

/** 小敌机类,继承FlyingObject,实现小敌机的移动,死亡后爆破*/
public class Airplane extends FlyingObject implements Enemy {private int speed;Airplane(){super(48,50,1);speed = 2;}public void step() {y += speed;}/** 获取小敌机的图片,状态为LIFE时返回小敌机图片* 状态为DEAD时返回4张爆破图片,全部返回后将状态改为REMOVE,返回null*/int index = 1;public BufferedImage getImage() {if(isLife()){return Images.airplanes[0];}else if(isDead()){if(index == 5){state = REMOVE;return null;}return Images.airplanes[index++];}return null;}//生成一颗子弹的子弹数组子弹的初始坐标为当前小敌机的下面,子弹方向向下public Bullet[] shoot(){Bullet[] res = new Bullet[1];res[0] = new Bullet(x+this.width/2,y+this.height+10,"down");return res;}//小敌机的y坐标大于窗口的高返回turepublic boolean outBround() {return y>=World.HEIGHT;}//返回小敌机的分数public int getScore() {return 1;}}

大敌机类BigAirplane

/** 大敌机类,实现大敌机的移动和生成子弹数组以及返回分数*/
public class BigAirplane extends FlyingObject implements Enemy {private int speed;BigAirplane(){super(66,89,3);speed = 2;}public void step() {y += speed;}/** 获取大敌机的图片,状态为LIFE时返回大敌机图片* 状态为DEAD时返回4张爆破图片,全部返回后将状态改为REMOVE,返回null*/int index = 1;public BufferedImage getImage() {if(isLife()){return Images.bigairplanes[0];}else if(isDead()){if(index==5){state = REMOVE;return null;}return Images.bigairplanes[index++];}return null;}//生成一颗子弹的子弹数组子弹的初始坐标为当前小敌机的下面,子弹方向向下public Bullet[] shoot(){Bullet[] res = new Bullet[1];res[0] = new Bullet(x+this.width/2,y+this.height+10,"down");return res;}//大敌机的y坐标大于窗口的高返回turepublic boolean outBround() {return y>=World.HEIGHT;}//直接返回大敌机的分数public int getScore() {return 3;}}

侦察机类Bee

/** 侦察机类,实现侦察机的移动*/public class Bee extends FlyingObject implements Award {private int xSpeed;private int ySpeed;private int awardType;Bee(){super(60,51,2);xSpeed = 1;ySpeed = 2;awardType = (int)(Math.random()*2);}//返回奖励的类型public int getType() {return awardType;}//当侦察机碰到边界时改变x方向的移动public void step() {x += xSpeed;y += ySpeed;if(x<=0 || x>=World.WIDTH-this.width){xSpeed = -xSpeed;}}/** 获取侦察机的图片,状态为LIFE时返回侦察机图片* 状态为DEAD时返回4张爆破图片,全部返回后将状态改为REMOVE,返回null*/int index = 1;public BufferedImage getImage() {if(isLife()){return Images.bees[0];}else if(isDead()){if(index==5){state = REMOVE;return null;}return Images.bees[index++];}return null;}//侦察机的y坐标大于窗口的高返回turepublic boolean outBround() {return y>=World.HEIGHT;}}

boss机类BossAirplane

/** boss机类,实现boss机的移动,生成子弹*/public class BossAirplane extends FlyingObject implements Enemy,Award {private int speed;BossAirplane(){super(150,113,10);speed = 2;}//返回boss机的分数public int getScore() {return 100;}//boss机的移动public void step() {y += speed;}/** 获取boss机的图片,状态为LIFE时返回boss机图片* 状态为DEAD时返回4张爆破图片,全部返回后将状态改为REMOVE,返回null*/int index = 1;public BufferedImage getImage() {if(isLife()){return Images.bossairplanes[0];}else if(isDead()){if(index==5){state = REMOVE;return null;}return Images.bossairplanes[index++];}return null;}//生成两颗子弹public Bullet[] shoot(){Bullet[] res = new Bullet[2];res[0] = new Bullet(x+this.width/3,y+this.height+10,"down");res[1] = new Bullet(x+2*this.width/3,y+this.height+10,"down");return res;}//判断是否越界public boolean outBround() {return y>=World.HEIGHT;}//返回奖励类型@Overridepublic int getType() {return (int)(Math.random()*2);}
}

英雄机类Hero

/** 英雄机类,实现了英雄机随鼠标的坐标移动* 根据火力发射不同火力的子弹*/
public class Hero extends FlyingObject {//火力值private int doubleFire;Hero(){super(46,66,170,400);life = 3;doubleFire = 10000;}//随着鼠标的x,y移动public void moveTo(int x,int y){this.x = x - this.width/2;this.y = y - this.height/2;}//根据火力生成想上的子弹数组public Bullet[] shoot(){int xStep = this.width/4;int yStep = -20;if(doubleFire>1000){Bullet[] b = new Bullet[5];for(int i=0;i<5;i++){b[i] = new Bullet(this.x+i*xStep,y + yStep,"up");}doubleFire -= 2;return b;}else if(doubleFire>0){Bullet[] b = new Bullet[3];for(int i=0;i<3;i++){b[i] = new Bullet(this.x+i*2*xStep,y + yStep,"up");}doubleFire -= 2;return b;}else{Bullet[] b = new Bullet[1];b[0] = new Bullet(this.x+2*xStep,this.y+yStep,"up");return b;}}//返回生命数public int getLife(){return life;}//返回火力值public int getDoubleFire(){return doubleFire;}//火力增加50public void addDoubleFire(){doubleFire += 50;}//生命数加一public void addLife(){life++;}//清空火力值public void clearDoubleFire(){doubleFire = 0;}public void step() {}//英雄机活着时每次返回不同的图片实现英雄机的喷火private int index = 0;public BufferedImage getImage() {if(isLife()){return Images.heros[index++%2];}return null;}//英雄机不存在越界行为public boolean outBround() {return false;}}

子弹类Bullet

/** 子弹类,实现子弹的移动*/
public class Bullet extends FlyingObject {//dir为不同的子弹图片标记,0为向上,1为向下private int speed;private int dir;Bullet(int x,int y,String direction){super(8,20,x,y);if(direction.equals("up")){speed = -2;dir = 0;}else if(direction.equals("down")){speed = 3;dir = 1;}}//子弹移动public void step() {y += speed;}/** 返回子弹图片,Images.bullets[0]是向上的,Images.bullets[1]是向下的* 当状态为DEAD时,改变状态为REMOVE*/public BufferedImage getImage() {if(isLife()){return Images.bullets[dir];}else if(isDead()){state = REMOVE;return null;}return null;}//判断是否越界public boolean outBround() {return y<=0 || y>=World.HEIGHT;}}

返回分数接口

/** 返回分数接口*/
public interface Enemy {public int getScore();
}

返回奖励类型接口

/** 返回奖励类型接口*/
public interface Award {public int DOUBLE_FIRE = 0;public int LIFE = 1;public int getType();}

主类World的设计

各个对象类都设计完成了,接下来我对先从要实现的功能来进行分析,然后再来设计。

功能分析

一、英雄机能随鼠标移动和发射子弹
二、英雄机发射的子弹击中敌机后让敌机生命减一同时会有声音提示,英雄机生命小于等于零后游戏结束
三、敌机能发射子弹
四、敌机的子弹击中英雄机后英雄机生命减一,敌机生命小于等于零后爆破后移除
五、敌机、子弹在状态为REMOVE和越界后要删除掉
六、游戏运行后有bgm

启动页面,单击后运行

运行页面

鼠标移出窗口暂停

英雄机生命小于等于零游戏结束,单击后重新进入启动界面

设计World类属性

 //设置四个状态常量,一个当前状态变量public static final int START = 0;public static final int RUNNING = 1;public static final int PAUSE = 2;public static final int GAME_OVER = 3;private int state = START;//窗口的宽和高public static final int WIDTH = 400;public static final int HEIGHT = 700;

声明java.applet.AudioClip类型的引用用来储存音频

java.applet.AudioClip all_bomb,enemy_bomb,bg,hero_bomb,hero_bullet;
 //声明并创建天空对象,声明并创建英雄机对象private Sky sky = new Sky();private Hero hero = new Hero();/**声明敌人数组enemies数组向上造型为FlyingObject超类方面使用*声明英雄机的子弹数组heroBullets*声明敌人的子弹数组enemiesBullets*/private FlyingObject[] enemies = {};private Bullet[] heroBullets = {};private Bullet[] enemiesBullets = {};
 //声明图片类静态变量:启动图、暂停图、和游戏结束图并赋值public static BufferedImage start;public static BufferedImage pause;public static BufferedImage gameover;static{start = Images.readImage("start.png");pause = Images.readImage("pause.png");gameover = Images.readImage("gameover.png");}
//在构造方法里为各音频赋值
public World(){try{all_bomb = JApplet.newAudioClip(new File("music/all_bomb.wav").toURI().toURL());enemy_bomb = JApplet.newAudioClip(new File("music/enemy_bomb.wav").toURI().toURL());bg = JApplet.newAudioClip(new File("music/bg.wav").toURI().toURL());hero_bomb = JApplet.newAudioClip(new File("music/hero_bomb.wav").toURI().toURL());hero_bullet = JApplet.newAudioClip(new File("music/hero_bomb.wav").toURI().toURL());}catch(MalformedURLException e){e.printStackTrace();}}

生成敌人

 //随机生成大敌机、小敌机、侦察机的对象public FlyingObject nextOne(){int n = (int)(Math.random()*100);if(n>70){return new Bee();}else if(n>40){return new BigAirplane();}else{return new Airplane();}}/**每隔一段时间调用nextOne方法生成一个敌人添加到敌人数组当中*当分数大于100后隔更长一段时间生成boss机添加到敌人数组*/private int enemiesIndex = 0;public void enterAction(){enemiesIndex++;if(enemiesIndex%30==0){enemies = Arrays.copyOf(enemies, enemies.length+1);enemies[enemies.length-1] = nextOne();}if(enemiesIndex%1000==0 && score>100){enemies = Arrays.copyOf(enemies, enemies.length+1);enemies[enemies.length-1] = new BossAirplane();}}

敌人发射子弹

 //每隔一段时间遍历敌人敌人数组让没一个敌人数组发射子弹添加到敌人子弹数组private int enemiesShootIndex = 0;public void enemiesShoot(){enemiesShootIndex++;if(enemiesShootIndex%100==0){//遍历敌人数组for(int i=0;i<enemies.length;i++){FlyingObject f = enemies[i];//敌人还活着与不是侦察机时发射子弹if(f.isLife() && !(f instanceof Bee)){//敌人调用shoot方法生成子弹数组Bullet[] b = f.shoot();//将生成的子弹数组添加到敌人子弹数组enemiesBullets = Arrays.copyOf(enemiesBullets, enemiesBullets.length+b.length);System.arraycopy(b, 0, enemiesBullets, enemiesBullets.length-b.length,b.length);}}}}

判断敌人的子弹是否击中英雄机和英雄机是否与敌人相撞

 public void hitAction(){//遍历敌人数组for(int i=0;i<enemies.length;i++){FlyingObject f = enemies[i];//敌人和英雄机都还活着,英雄机调用hit方法检测碰撞if(f.isLife() && hero.isLife() && hero.hit(f)){//碰撞后改变敌人状态为DEADf.goDead();//播放碰撞音效hero_bullet.play();//英雄机减命和清空火力hero.clearDoubleFire();hero.subtractLife();}}//遍历敌人子弹数组for(int i=0;i<enemiesBullets.length;i++){Bullet b = enemiesBullets[i];//如果英雄机的状态为LIFE,调用hit方法判断是否发生碰撞if(b.hit((FlyingObject)hero) && b.isLife()){//碰撞后改变子弹的状态为DEADb.goDead();//播放碰撞音效hero_bullet.play();//英雄机减命和清空火力hero.subtractLife();hero.clearDoubleFire();}}}

英雄机发射子弹

private int shootIndex = 0;public void shootAction(){shootIndex++;if(shootIndex%40==0){//英雄机调用shoot方法生成子弹数组Bullet[] b = hero.shoot();//将子弹数组添加到英雄机子弹数组中heroBullets = Arrays.copyOf(heroBullets, heroBullets.length+b.length);System.arraycopy(b, 0, heroBullets, heroBullets.length-b.length,b.length);}}

判断英雄机发射的子弹是否击中敌人

 //初始化分数为0int score = 0;public void bangAction(){//遍历敌人数组for(int i=0;i<enemies.length;i++){FlyingObject f = enemies[i];//遍历英雄机子弹数组for(int j=0;j<heroBullets.length;j++){Bullet b = heroBullets[j];//判断敌人和子弹的状态是否为LIFE和子弹调用hit方法判断是否发生碰撞if(b.isLife() && f.isLife() && b.hit(f)){if(f.life>1){//如果敌人的生命大于1生命减一,子弹状态改变为DEADf.subtractLife();b.goDead();}else{//播放爆破音效enemy_bomb.play();//当敌人的生命不大于一时改变子弹和敌人的状态为DEADf.goDead();b.goDead();if(f instanceof Enemy){//如果是实现了加分的接口则给score加分Enemy e = (Enemy) f;score += e.getScore();}if(f instanceof Award){//如果是加奖励则添加对应的奖励Award a = (Award) f;int type = a.getType();switch(type){case Award.DOUBLE_FIRE:hero.addDoubleFire();break;case Award.LIFE:hero.addLife();break;}}}}}}}

对象都动起来

public void stepAction(){//天空动起来sky.step();//敌人动起来for(int i=0;i<enemies.length;i++){enemies[i].step();}//英雄机子弹动起来for(int i=0;i<heroBullets.length;i++){heroBullets[i].step();}//敌人子弹动起来for(int i=0;i<enemiesBullets.length;i++){enemiesBullets[i].step();}}

清除状态为REMOVE和超出窗口的敌人和子弹

 //防止对象过多发生内存泄漏public void outOfBoundsAction(){//创建一个FlyingObject的数组来储存没REMOVE和没超出窗口的敌人int index = 0;FlyingObject[] fs = new FlyingObject[enemies.length];for(int i=0;i<enemies.length;i++){FlyingObject f = enemies[i];//如果!f.isRemove() && !f.outBround()则存储在fs里if(!f.isRemove() && !f.outBround()){//index++记录长度fs[index++] = f;}}//缩减敌人数组为fs中的元素enemies = Arrays.copyOf(fs, index);//下面和上面同理index = 0;Bullet[] bs = new Bullet[heroBullets.length];for(int i=0;i<heroBullets.length;i++){Bullet b = heroBullets[i];if(!b.isRemove() && !b.outBround()){bs[index++] = b;}}heroBullets = Arrays.copyOf(bs, index);index = 0;Bullet[] ebs = new Bullet[enemiesBullets.length];for(int i=0;i<enemiesBullets.length;i++){Bullet b = enemiesBullets[i];if(!b.isRemove() && !b.outBround()){ebs[index++] = b;}}enemiesBullets = Arrays.copyOf(ebs, index);}

英雄没命游戏结束

public void checkGameOverAction(){if(hero.getLife()<0){hero_bomb.play();state = GAME_OVER;}}

在画板上画出所有对象

public void paint(Graphics g){//画天空sky.paintObject(g);//画英雄机hero.paintObject(g);//画敌人for(int i=0;i<enemies.length;i++){enemies[i].paintObject(g);}//画英雄机子弹for(int i=0;i<heroBullets.length;i++){heroBullets[i].paintObject(g);}//画敌人子弹数组for(int i=0;i<enemiesBullets.length;i++){enemiesBullets[i].paintObject(g);}//画出得分和生命g.drawString("SCORE:"+score, 10, 25);g.drawString("LIFE:"+hero.getLife(), 10, 45);//游戏处于不同状态画出不同状态图switch(state){case START:g.drawImage(start, 0, 0, null);break;case PAUSE:g.drawImage(pause, 0, 0, null);break;case GAME_OVER:g.drawImage(gameover, 0, 0,null);break;}}

游戏运行方法

public void action(){//创建监听鼠标事件匿名内部类MouseAdapter l = new MouseAdapter(){//鼠标移动事件public void mouseMoved(MouseEvent e){//状态为RUNNING时获取鼠标坐标,英雄机调用moveTo方法让英雄机随着鼠标移动if(state==RUNNING){int x=e.getX();int y=e.getY();hero.moveTo(x, y);}}//鼠标单击事件public void mouseClicked(MouseEvent e){//状态为START时单击状态改变为RUNNING并且播放背景音乐if(state==START){//bg.loop为循环播放音乐bg.loop();state = RUNNING;}else if(state==GAME_OVER){//状态为GAME_OVER时改变状态为STARTstate = START;//分数重置为0score = 0;//重置所有对象为下一盘游戏做准备enemies = new FlyingObject[0];heroBullets = new Bullet[0];enemiesBullets = new Bullet[0];hero = new Hero();}}//鼠标移出窗口事件public void mouseExited(MouseEvent e){//当状态为RUNNING时改变状态为PAUSEif(state==RUNNING){state = PAUSE;//停止背景音乐播放bg.stop();}}//鼠标进入窗口事件public void mouseEntered(MouseEvent e){//如果状态为PAUSE改变状态为RUNNING并播放背景音乐if(state==PAUSE){bg.loop();state = RUNNING;}}};//为监听鼠标对象添加Java的监听this.addMouseListener(l);this.addMouseMotionListener(l);//创建计时器定时运行上面的各种方法让程序运行Timer timer = new Timer();//intervel 为启动延时和以后运行时间间隔,以毫秒为单位int intervel = 10;timer.schedule(new TimerTask(){public void run() {//如果状态为RUNNING时开始运行if(state==RUNNING){enterAction();enemiesShoot();shootAction();stepAction();bangAction();outOfBoundsAction();hitAction();checkGameOverAction();}//每次都重画保证刷新率repaint();}}, intervel,intervel);}

旋风无敌大大大招

 //这里实现里监听键盘的接口KeyListener,重写按键时间@Overridepublic void keyPressed(KeyEvent e) {//当状态为RUNNING时if(state==RUNNING){//判断是否按下空格键switch(e.getKeyCode()){case KeyEvent.VK_SPACE://按下空格键后播放爆炸音效同时清空所有地方对象all_bomb.play();enemies = new FlyingObject[0];enemiesBullets = new Bullet[0];break;}}}

实现线程运行

因为播放音效会阻塞程序,而使用java.applet.AudioClip类又要在线程里才能播放出声音
所以这里就实现了Runnable接口,重写run方法运行程序

 @Overridepublic void run() {action();}

main方法启动程序

public static void main(String[] args) {//创建World对象,World类继承了画板类JPanelWorld world = new World();//创建窗口对象JFrame frame = new JFrame();//将画板添加到窗口中去frame.add(world);//设置窗口默认关闭操作frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗口大小frame.setSize(WIDTH, HEIGHT);//这个不知道,有没有都没事frame.setLocationRelativeTo(null); //设置窗口可见frame.setVisible(true); //添加键盘监听frame.addKeyListener(world);//创建线程对象Thread t=new Thread(world);//启动线程t.start();System.out.println("111");}

完结撒花

感谢阅读,如果有人的话

源码百度云

链接:https://pan.baidu.com/s/1l5u-Ibikf9M_PO_0HU31HA
提取码:0i3i

Java学习记录:Java飞机大战进阶版(敌人有子弹、有生命、有boss、有声音、还有大招一键清屏)相关推荐

  1. Java学习记录 Java与JSON

    什么是JSON? JSON英文全称是 JavaScript Object Notation (JS对象简谱). JSON是一种使用了JS对象的书写语法的格式.[引用1] 它基于 ECMAScript ...

  2. 用JAVA制作小游戏——飞机大战(三)

    本篇博客是对飞机大战游戏项目完整代码的展示 详细代码讲解: 用JAVA制作小游戏--飞机大战(一) 用JAVA制作小游戏--飞机大战(二) 最下方附整个程序的文件下载链接 代码展示 主界面 impor ...

  3. 用JAVA制作小游戏——飞机大战(二)

    本篇博客是对飞机大战游戏使用代码的展示 重难点: 首先需要鼠标能够控制战机,使鼠标在窗口内时始终能够使战机的位置与鼠标相同,实现鼠标控制战斗机移动. 其次需要能够以一定的速度产生子弹和敌机,并且以一定 ...

  4. Java入门123:一个老鸟的Java学习心得(二维码版)

    Java入门123:一个老鸟的Java学习心得(二维码版)清华大学出版社 Java入门123--一个老鸟的Java学习心得(二维码版)充分考虑了初学Java的种种困难,讲解细致入微,抽丝剥茧,层层推进 ...

  5. Java学习记录五(多线程、网络编程、Lambda表达式和接口组成更新)

    Java学习记录五(多线程.网络编程.Lambda表达式和接口组成更新) Java 25.多线程 25.1实现多线程 25.1.1进程 25.1.2线程 25.1.3多线程的实现 25.1.4设置和获 ...

  6. java飞机场模拟程序_java 飞机大战 小游戏源码

    [实例简介] 本项目是一个使用java做的一个飞机大战的小游戏,一个英雄机,初始有三次生命,当打中蜜蜂会有一次生命奖励,当打中敌机会有相应分数奖励,但如果被敌机打中会失去一次生命机会.如果生命都失去, ...

  7. Java多线程编写简易飞机大战(一)

    ** Java多线程编写简易飞机大战(一) ** 利用多线程编写飞机大战,主要有3个关键: ①继承Thread类,重写run方法: ②线程工作代码在run方法中写: ③启动时,调用线程对象的start ...

  8. Java学习从入门到精通-旧版

    为什么80%的码农都做不了架构师?>>>    Java学习从入门到精通-旧版 http://tech.ccidnet.com/art/3737/20051017/465333_1. ...

  9. java多线程阶乘_【java学习记录】11.用多线程实现阶乘的计算过程和结果的读取(thread类ReadThread )...

    (源码在上传的压缩包"[java学习记录]11.多线程实现阶乘计算(Thread类和Runnable接口)"中可看到,该压缩包可下载)java * 采用Thread类的子类实现线程 ...

最新文章

  1. 贝叶斯优化-matlab
  2. matlab循环前后变量定义,Matlab for 多个变量循环能不能这样啊 ,求教高手!!!!...
  3. 浅淡绿萝2.0和星火计划
  4. 力扣151. 翻转字符串里的单词
  5. C++转换构造函数和类型转换函数
  6. 从VC++到GCC移植:谈两者的语法差异
  7. 英特尔新任CEO的“开挂”人生
  8. linux去重统计个数,linux 文件内容查找、去重、统计(示例代码)
  9. C、C++用指针引用的差异
  10. oracle 定义变量 查询,Oracle定义PL/SQL变量
  11. Unity中设置对象匀速移动
  12. VB6.0视频教程78集,入门视频教程,基础够了(基础篇)
  13. JavaScript中浏览器兼容性解决办法
  14. 波司登 × 阿里云 × 奇点云:教科书式的数智化转型实践
  15. 树的基本概念和2叉树中重要的几个性质
  16. microduino与onetnet测试
  17. 继电保护原理1.2-反时限过流保护
  18. NOIP2014提高组A.石头剪刀布
  19. 用网络摄像头做延时摄影(WPF+Emgu.CV)
  20. 应用MATLAB求解线性代数题目(一)——行列式

热门文章

  1. java mkfifo_如何在Android中创建命名管道(mkfifo)?
  2. 网络流最大流算法(ISAP算法及DINIC算法)
  3. 【C#】关于右下角托盘图标以及气泡使用的注意事项
  4. java consumer_java-8 – 方法参考 – 使用Consumer参数将Function传递给方法
  5. 上海求职骗子公司大全!!
  6. DLO-SLAM代码阅读
  7. (原创)华硕Z87-A老主板修改BIOS支持NVMe启动后的常见问题及解决办法(采坑实录)
  8. JavaScript的五种基本类型
  9. 【OpenCV入门】读取图片/视频/调用摄像头
  10. matlab 画三维三角形,三维图输入了11个点,怎么画的时候变成了三角形?