Java程序之飞机大战

功能分析
Shoot是一款非常有名的射击类小游戏—飞机大战,游戏中,玩家可以驾驶英雄机,在空中进行战斗,通过鼠标点击并移动英雄机,可以发射子弹,打掉飞机或者蜜蜂,从而来获得分数和奖励(分数默认为0,性命为3),打掉一架敌飞机可以获得5分,打掉一个小蜜蜂可以获得20次双倍火力或者增加一条性命的奖励,如果英雄机撞上敌机或者小蜜蜂,则会减少一条性命,并且双倍火力清零,当性命为0时,游戏结束。
1.飞行物父类(后期主要做敌人父类)

import java.awt.image.BufferedImage;
/**飞行物父类*/
public abstract class FlyingObject {
    protected BufferedImage image;
    protected int width;   //宽
    protected int height;  //高
    protected int x;       //x坐标
    protected int y;       //y坐标 
    public abstract void step();            //走步 10毫秒一次
    public abstract boolean outOfBounds();  //检查飞行物是否出界
    public boolean shootBy(Bullet bullet){  //检查当前敌人是否被子弹击中
        int x1=this.x;   //x1:敌人的X
        int x2=this.x+this.width;           //y1:敌人的x+敌人的宽
        int y1=this.y;   //敌人的宽
        int y2=this.y+this.height;          //敌人的y+敌人的高
        int x=bullet.x;    //子弹的x
        int y=bullet.y;    //子弹的y
        return x>x1&&x<x2&&y>y1&&y<y2;      //x在x1和x2之间并且y在y1和y2之间,就是子弹击中敌人
    }
}

2.敌人接口,主要体现得分功能

/**接口---敌人得分*/
public interface Enemy {
    public  int getScore();  //得分
}

3.奖励接口,主要体现奖励类型

/**接口---奖励*/
public interface Award {
    public static final int DOUBLE_FIRE=0;  //火力
    public static final int LIFE=1;         //生命
    public int getType();  //获取奖励类型(0火力 1生命)
}

4.敌机子类

import java.util.Random;
/**敌机---是飞行物,也是敌人*/
public class Airplane extends FlyingObject implements Enemy {
    private int speed=2;           //下落步数
    public Airplane(){             //构造方法
        image=ShootGame.airplane;  //图片-静态块已加载
        width=image.getWidth();    //写活 可扩展性高
        height=image.getHeight();
        Random ra=new Random();
        x=ra.nextInt(ShootGame.WIDTH-this.width);  //屏幕宽到敌机宽之间的随机数
        y=-this.height;            //负的敌机高
    }
    public  int getScore(){        //重写接口抽象方法
        return 5;
    }
    public  void step(){           //重写父类走步方法
        y+=speed;                  //敌机仅仅是向下走 y改变 x不变
    }
    public  boolean outOfBounds(){ //重写父类越界方法
        return this.y>=ShootGame.HEIGHT;  //若敌机的y坐标大于窗口的高 则出界
    }
}

5.蜜蜂子类

import java.util.Random;
/**小蜜蜂---是飞行物,也是奖励*/
public class Bee extends FlyingObject implements Award {
    private int xSpeed=1;     //x坐标走步步数
    private int ySpeed=2;     //y坐标走步步数
    private int awardType;    //奖励类型
    public Bee(){             //构造方法
        image=ShootGame.bee;  //图片-静态块已加载
        width=image.getWidth();
        height=image.getHeight();
        Random ra=new Random();
        x=ra.nextInt(ShootGame.WIDTH-this.width); //屏幕宽到蜜蜂宽之间的随机数
        y=-this.height;       //负的蜜蜂高
        awardType=ra.nextInt(2);  //奖励类型 0火力,1生命
    }
    public int getType(){     //重写接口抽象方法
         awardType=(int)(Math.random()*2);
        return awardType;
    }
    public  void step(){      //重写父类走步方法
        y+=ySpeed;  //向左或者向右
        x+=xSpeed;  //向下
        if(x>=ShootGame.WIDTH-this.width){
            xSpeed=-1;  
        }
        if(x<=0){
            xSpeed=1;
        }
    }
    public  boolean outOfBounds(){
        return this.y>=ShootGame.HEIGHT;  //若蜜蜂的y坐标大于窗口的高 则出界
    }
}

6.英雄机子类

import java.awt.image.BufferedImage;
import java.util.Random;
/**英雄机---是飞行物*/
public class Hero extends FlyingObject {
    private int life;               //生命
    private int doubleFire;         //火力值
    private BufferedImage[] images; //图片切换数
    private int index;              //协助切换图片
    public Hero(){                  //构造方法
        image=ShootGame.hero0;      //图片-静态块已加载
        width=image.getWidth();
        height=image.getHeight();
        x=150;         //x坐标固定
        y=400;         //y坐标固定
        life=3;        //命数为3
        doubleFire=0;  //火力值为0(单倍火力)
        images=new BufferedImage[]{ShootGame.hero0,ShootGame.hero1};//两张图片切换键
        index=0;       //协助图片切换 
    }
    public void step(){        //重写父类走步方法 
        /** * index++; * int a=index/10; * int b=a%2; * image=images[b]; */
        image=images[index++/10%images.length];//每100毫秒切换一次图片
    }
    public Bullet[] shoot(){   //发射子弹
        int xStep=this.width/4;
        int yStep=20;       
        if(doubleFire>0){      //双倍火力
            Bullet[] bs=new Bullet[2];                     //双倍火力有俩个火力发射点
            bs[0]=new Bullet(this.x+xStep*1,this.y-yStep); //双倍火力的第一发子弹发出位置
            bs[1]=new Bullet(this.x+xStep*3,this.y-yStep); //双倍火力的第二发子弹发出位置
            doubleFire-=2;     //发射一次双倍火力,火力值-2(每个双倍火力可持续发20次)
            return bs;
        }else{                 //单倍火力
            Bullet[] bs=new Bullet[1];
            bs[0]=new Bullet(this.x+xStep*2,this.y-yStep); //单倍火力的子弹发出位置
            return bs;
        }
    }
    public void moveTo(int x,int y){  //英雄机随着鼠标移动
        this.x=x-this.width/2;
        this.y=y-this.height/2;
    }
    public  boolean outOfBounds(){    //英雄机永不越界
        return false;
    }
    public void addLife(){         //生命+1
        life++;  
    }
    public int getLife(){          //获取生命数
        return life;
    }
    public void subtractLife(){    //英雄机命数-1
        life--;
    }
    public void addDoubleFir(){    //火力值增40
        doubleFire+=40;  
    }
    public void clearDoubleFire(){ //清火力(火力归零)
        doubleFire=0;
    }
    public boolean hit(FlyingObject other){  //英雄机和敌人的碰撞 this英雄机 other敌人
        int x1=other.x-this.width/2;         //敌人的x-英雄机宽的一半
        int x2=other.x+other.width+this.width/2;   //敌人的x+敌人的宽+英雄机宽的一半
        int y1=other.y-this.height/2;        //敌人的y-英雄机高的一半
        int y2=other.y+other.height+this.height/2; //敌人的y+敌人的高+英雄机高的一半
        int x=this.x+this.width/2;   //中心点x坐标 英雄机的x+英雄机宽的一半
        int y=this.y+this.height/2;  //中心点y坐标 英雄机的y+英雄机高的一半
        return x>x1&&x<x2&&y>y1&&y<y2;
    }
}

7.子弹子类

/**子弹---是飞行物*/
public class Bullet extends FlyingObject {
    private int speed=3;          //走的步数
    public Bullet(int x,int y){   //构造方法
        image=ShootGame.bullet;   //图片-静态块已加载
        width=image.getWidth();
        height=image.getHeight();
        this.x=x;   //与英雄机有关
        this.y=y;
    }
    public  void step(){            //重写父类走步方法
        y-=speed;  //y- 向上走 x
    }
    public  boolean outOfBounds(){  //判断子弹是否越界
        return this.y<=-this.height;
    }
}

8.主程序类

import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;    //框架
import javax.swing.JPanel;    //画板
import java.awt.Graphics;     //paint()中的参数
import java.util.Random;
import java.util.Timer;       //定时器
import java.util.TimerTask;   //定时
import java.util.Arrays;
import java.awt.event.MouseAdapter;   
import java.awt.event.MouseEvent;      
import java.awt.Color;        //颜色
import java.awt.Font;         //字体
/**主程序类*/
public class ShootGame extends JPanel{
    public static final int WIDTH=400;   //窗口的宽
    public static final int HEIGHT=690;  //窗口的高

    public static BufferedImage background;  //背景图片
    public static BufferedImage start;       //开始图片 
    public static BufferedImage pause;       //暂停图片
    public static BufferedImage gameover;    //游戏结束图片
    public static BufferedImage airplane;    //敌机图片
    public static BufferedImage bee;         //蜜蜂图片
    public static BufferedImage bullet;      //子弹图片
    public static BufferedImage hero0;       //英雄机0图片
    public static BufferedImage hero1;       //英雄机1图片
    private Hero hero=new Hero();      // 英雄机
    private Bullet[] bullets={};       // 子弹数组
    private FlyingObject[] flyings={}; // 敌机数组

    public static final int START=0;      //启动状态
    public static final int RUNING=1;     //运行状态
    public static final int PAUSE=2;      //暂停状态
    public static final int GAME_OVER=3;  //结束状态
    private int state=START;              //当前状态(启动状态)

    static{     // 静态代码块,初始化图片资源
        try{    //捕获异常语句
            background=ImageIO.read(ShootGame.class.getResource("background.png"));
            start=ImageIO.read(ShootGame.class.getResource("start.png"));
            pause=ImageIO.read(ShootGame.class.getResource("pause.png"));
            gameover=ImageIO.read(ShootGame.class.getResource("gameover.png"));
            airplane=ImageIO.read(ShootGame.class.getResource("airplane.png"));
            bee=ImageIO.read(ShootGame.class.getResource("bee.png"));
            bullet=ImageIO.read(ShootGame.class.getResource("bullet.png"));
            hero0=ImageIO.read(ShootGame.class.getResource("hero0.png"));
            hero1=ImageIO.read(ShootGame.class.getResource("hero1.png"));
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    public FlyingObject nextOne(){  //创建敌人(敌机+小蜜蜂)对象
        Random ra=new Random();
        int type=ra.nextInt(20);    //生成0~19的随机数
        if(type==0){
            return new Bee();       //若随机数为0生成蜜蜂
        }else{
            return new Airplane();  //否则生成敌机
        }
    }

    int flyEnteredIndex=0;          //飞行物入场计数
    public void enterAction(){      //10毫秒走一次 控制入场时间
        flyEnteredIndex++;          //每10毫秒增1
        if(flyEnteredIndex%40==0){  //400(10*40)毫秒走一次
            FlyingObject obj=nextOne();
            flyings=Arrays.copyOf(flyings,flyings.length+1);
            flyings[flyings.length-1]=obj;
        }
    }   
    public void stepAction(){       //走步方法
        hero.step();                //英雄机走一步
        for(int i=0;i<flyings.length;i++){    //遍历所有敌人
            flyings[i].step();      //每个敌人走一步
        }
        for(int i=0;i<bullets.length;i++){    //遍历所有子弹
            bullets[i].step();      //每个子弹走一步
        }
    }   
    int shootIndex=0;               //射击计数
    public void shootAction(){      //子弹入场 因为在run方法里边 所以也是10毫秒走一次 
        shootIndex++;               //每10毫秒自增1
        if(shootIndex%20==0){       //每300毫秒走一次
            Bullet[] bs=hero.shoot();
            bullets=Arrays.copyOf(bullets, bullets.length+bs.length);
            System.arraycopy(bs, 0, bullets,bullets.length-bs.length, bs.length); //数组的追加
        }
    }
    public void outOfBoundsAction(){    //删除越界飞行物
        int index=0;                    //1.不越界敌人数组下标 2.不越界敌人个数
        FlyingObject[] flyingLives=new FlyingObject[flyings.length]; //不越界敌人数组
        for(int i=0;i<flyings.length;i++){        //遍历所有敌人
            FlyingObject f=flyings[i];  //获取每一个敌人
            if(!f.outOfBounds()){       //不越界
                flyingLives[index]=f;   //将不越界敌人添加到不越界敌人数组
                index++;                //1.下标+1 2.不越界敌人个数增1
            }
        }
        flyings=Arrays.copyOf(flyingLives,index); //将不越界敌人数组里的元素复制到飞行物数组中
    }
    public void bangAction(){           //所有子弹与所有敌人的碰撞
        for(int i=0;i<bullets.length;i++){        //遍历每一个子弹
            Bullet b=bullets[i];        //获取每一个子弹
            bang(b);                    //一个子弹与所有敌人碰撞
        }
    }
    int score=0;                        //玩家得分
    public void bang(Bullet b){         //一个子弹与所有敌人碰撞
        int index=-1;                   //被撞敌人的下标
        for(int i=0;i<flyings.length;i++){        //遍历每一个敌人
            FlyingObject f=flyings[i];  //获取每一个敌人
            if(f.shootBy(b)){           //撞上了
                index=i;                //记录被撞敌人的下标(index值发生改变,不会再是-1)
                break;
            }
        }
        if(index!=-1){                  //被撞上的飞行物
            FlyingObject one = flyings[index];    //获取被撞的敌人
            if(one instanceof Enemy){   //判断被撞敌人的类型 是敌人的话 得分
                Enemy e=(Enemy)one;     //将被撞敌人强转为敌人类型
                score+=e.getScore();    //累加分数
            }
            if(one instanceof Award){   //判断被撞敌人的类型 是蜜蜂的话 得奖励
                Award e=(Award)one;     //将被撞敌人强转为奖励类型
                int type=e.getType();
                switch(type){           //判断获得奖励类型
                case Award.DOUBLE_FIRE: //奖励双倍火力
                     hero.addDoubleFir();         //调用英雄机增火力方法
                     break;
                case Award.LIFE:        //奖励一条命
                     hero.addLife();    //调用英雄机增命力方法
                     break;                 
                }
            }
            FlyingObject t=flyings[index];         //被撞元素
            flyings[index]=flyings[flyings.length-1];   
            flyings[flyings.length-1]=t;  //交换被撞敌人与数组中的最后一个元素 即将被撞敌人挪到数组中最后一个位置
            flyings=Arrays.copyOf(flyings,flyings.length-1);  //缩容默认去掉最后一个 去掉最后一个元素也就是被撞的元素
        }
    }
    public void checkGameOverAction(){  //检测游戏是否结束
        if(isGameOver()){               //游戏结束时
            state=GAME_OVER;
        }
    }
    public boolean isGameOver(){        //判断游戏是否结束,返回true表示游戏结束
        for(int i=0;i<flyings.length;i++){  //遍历每一个敌人
            FlyingObject f=flyings[i];  //获取每一个敌人
            if(hero.hit(f)){            //如果撞上了
                hero.subtractLife();    //英雄机减命
                hero.clearDoubleFire(); //英雄机清火力
                FlyingObject t=flyings[i];
                flyings[i]=flyings[flyings.length-1];
                flyings[flyings.length-1]=t;  //交换被撞敌人和数组的最后一个元素
                flyings=Arrays.copyOf(flyings, flyings.length-1);  //缩容
            }
        }
        return hero.getLife()<=0;       //命数<=0 游戏结束
    }
    public void action(){               //启动程序的执行 
        MouseAdapter l=new MouseAdapter(){
            public void mouseMoved(MouseEvent e){   //鼠标移动事件
                if(state==RUNING){      //当前状态为运行状态时执行
                int x=e.getX();         //获取鼠标x坐标
                int y=e.getY();         //获取鼠标y坐标
                hero.moveTo(x, y);      //英雄机随着鼠标移动
                }
            }
            public void mouseClicked(MouseEvent e){  //鼠标点击事件
                switch(state){          //不同状态时点击后有不同反应
                case START:             //启动状态时
                    state=RUNING;       //当前状态变为运行状态
                    break;
                case GAME_OVER:         //游戏结束状态时
                    score=0;            //清理现场
                    hero=new Hero();
                    flyings=new FlyingObject[0];
                    bullets=new Bullet[0];
                    state=START;        //当前状态为启动状态
                    break;
                }
            }
            public void mouseExited(MouseEvent e){   //鼠标移出事件 
                if(state==RUNING){      //当前状态为运行状态时
                    state=PAUSE;        //当前状态改为暂停状态
                }
            }
            public void mouseEntered(MouseEvent e){  //鼠标移入事件
                if(state==PAUSE){      //当前状态为暂停状态时
                    state=RUNING;      //当前状态改为运行状态
                }
            }
        };
        this.addMouseListener(l);       //处理鼠标的操作事件
        this.addMouseMotionListener(l); //处理鼠标的滑动事件
        Timer timer=new Timer();        //定时器对象 定时执行的一些事件
        int intervel=10;                //时间间隔(毫秒)
        timer.schedule(new TimerTask(){ //匿名内部类 重写run方法
            public void run(){          //10毫秒走一次 run方法里边的都是10毫秒走一次
                if(state==RUNING){      //当前状态为运行状态时执行 
                enterAction();          //敌人入场
                stepAction();           //飞行物走步
                shootAction();          //子弹入场
                outOfBoundsAction();    //删除越界飞行物
                bangAction();           //子弹与敌人的碰撞
                checkGameOverAction();  //检测游戏是否结束
                }
                repaint();              //重画,调用paint方法 
            }
        },intervel,intervel);           //做定时计划任务
    }

    public void paint(Graphics g){      //重写父类paint()方法 g:画笔
        g.drawImage(background,0,0,null);           //画背景图
        paintHero(g);                   //画英雄机
        paintFlyingObjects(g);          //画敌机(敌机+小蜜蜂)
        paintBullets(g);                //画子弹
        paintScoreAndLife(g);           //画分和生命
        paintState(g);                  //画状态
    }
    public void paintHero(Graphics g){  //画英雄机对象
        g.drawImage(hero.image,hero.x,hero.y,null);
    }
    public void paintFlyingObjects(Graphics g){     //画敌机(敌机+小蜜蜂)对象
        for(int i=0;i<flyings.length;i++){          //遍历flyings数组
            FlyingObject f=flyings[i];  //把每个敌人存到f中 为了代码的简洁
            g.drawImage(f.image,f.x,f.y,null);
        }
    }
    public void paintBullets(Graphics g){            //画子弹对象
        for(int i=0;i<bullets.length;i++){           //遍历bullets数组
            Bullet b=bullets[i];        //把每个敌人存到f中 为了代码的简洁
            g.drawImage(b.image,b.x,b.y,null);
        }
    }
    public void paintScoreAndLife(Graphics g){       //画分和生命
        g.setFont(new Font(Font.SERIF,Font.BOLD,20));//改变画笔字体
        g.setColor(new Color(0xFF0000));             //改变画笔颜色 (0xFF0000纯红 0x00FF00纯绿 0x0000FF纯蓝)
        g.drawString("SCORE:"+score,10,25);
        g.drawString("LIFE:"+hero.getLife(), 10, 45);
    }
    public void paintState(Graphics g){ //画状态
        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 static void main(String[] args) { 
        JFrame frame=new JFrame("Fly"); //创建一个JFrame对象
        ShootGame game=new ShootGame(); //创建一个JPanel对象
        frame.add(game);                //将面板添加到框架上
        frame.setSize(WIDTH,HEIGHT);    //设置窗口大小
        frame.setAlwaysOnTop(true);     //设置总是在最上边
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //设置默认关闭操作,窗口关闭,程序也关闭
        frame.setLocationRelativeTo(null);  //设置窗体初始位置(居中显示)
        frame.setVisible(true);         //1.设置窗口可见 2.尽快调用paint() 

        game.action();                  //启动程序的执行

    }
}

你可能感兴趣的:(Java程序之飞机大战)