Airplane:

package cn.tedu.cn;
import java.awt.image.BufferedImage;
public class Airplane extends FlyingObject implements EnemyScore{
    private int speed;   //移动速度
    public Airplane(){  //构造方法
        super(48,50);   //小敌机的宽高
        speed = 2;      //移动速度
    }
    /*重写step()移动*/
    public void step() {
        y+=speed;  //y+向下
    }

    private int index = 1;  //爆破图的下标
    /*重写getImage()获取图片*/
    public BufferedImage getImage() {  //每十毫秒走一次
        if(isLive()) {
            return Images.airs[0];
        }else if(isDead()) {
            BufferedImage img = Images.airs[index++];  //获取爆破图
            if(index==Images.airs.length) {  //到最后一张了
                state = REMOVE;   //将当前状态修改为REMOVE删除状态
            }
            return img;  //返回爆破图
        }
        return null;  //删除状态不返回图片

        /*
         *                    index=1
         * 10M  img=airs[1]   index=2   airs[1]
         * 20M  img=airs[2]   index=3   airs[2]
         * 30M  img=airs[3]   index=4   airs[3]
         * 40M  img=airs[4]   index=5   airs[4]
         *                    (REMOVE)
         * 50M  不返回图片
         */
    }

    public int getScore() {
        return 1; //打掉小敌机玩家得1 分
    }
}

Bee:

package cn.tedu.cn;
import java.awt.image.BufferedImage;
import java.util.Random;

public class Bee extends FlyingObject implements EnemyAward{
    private int xSpeed;
    private int ySpeed;
    private int awardType;

    public Bee(){
        super(60,51);
        Random rand = new Random();
        xSpeed = 1;
        ySpeed = 2;
        awardType = rand.nextInt(2);   //0到1之间

    }
    public void step() {
        x+=xSpeed;  //x向左向右
        y+=ySpeed;  //y+向下
        if(x<=0 || x>=World.WIDTH-width){          //若x<=0或X>=(窗口宽-蜜蜂宽),表示到头了
            xSpeed*=-1;  //切换方向(正便=变负、负变正)
        }
    }

    private int index = 1;  //爆破图的下标
    /*重写getImage()获取图片*/
    public BufferedImage getImage() {  //每十毫秒走一次
        if(isLive()) {
            return Images.bees[0];
        }else if(isDead()) {
            BufferedImage img = Images.bees[index++];  //获取爆破图
            if(index==Images.bees.length) {  //到最后一张了
                state = REMOVE;   //将当前状态修改为REMOVE删除状态
            }
            return img;  //返回爆破图
        }
        return null;  //删除状态不返回图片
    }

    public int getAwardType() {
        return awardType;  //返回奖励类型
    }
}

BigAirplane:

package cn.tedu.cn;
import java.awt.image.BufferedImage;
public class BigAirplane extends FlyingObject implements EnemyScore{
    private int speed;
    public BigAirplane(){
        super(66,89);
        speed = 2;
    }
    public void step() {
        y+=speed;  //y+向下
    }

    private int index = 1;  //爆破图的下标
    /*重写getImage()获取图片*/
    public BufferedImage getImage() {  //每十毫秒走一次
        if(isLive()) {
            return Images.bairs[0];
        }else if(isDead()) {
            BufferedImage img = Images.bairs[index++];  //获取爆破图
            if(index==Images.bairs.length) {  //到最后一张了
                state = REMOVE;   //将当前状态修改为REMOVE删除状态
            }
            return img;  //返回爆破图
        }
        return null;  //删除状态不返回图片
    }

    /*重写getScore()*/
    public int getScore() {
        return 3;  //打掉大敌机,玩家得3分
    }
}

Bullet:

package cn.tedu.cn;
import java.awt.image.BufferedImage;
public class Bullet extends FlyingObject{
    private int speed;

    public Bullet(int x,int y){   //子弹有许多个,每个子弹的初始坐标都不同
        super(8,20,x,y);
        speed = 3;
    }
    public void step() {
        y-=speed;  //y+向上
    }

    /*重写getImage()获取图片*/
    public BufferedImage getImage() {
        if(isLive()) {
            return Images.bullet;    //直接返回图片
        }else if(isDead()){     //若死了的
            state = REMOVE;    //将状态修改为REMOVE删除状态
        }
        return null;  //死了的和删除的,都不反图片
      /*
      //若活着的,返回bullet 图片
      //若死了的,状态改为删除,同时不返回图片
      //若删除的不返回图片
      */
    }

    /*重写isOutOfBounds()判断子弹是否越界*/
    public boolean isOutOfBounds() {
        return y<=-height;  //敌人的y>=窗口的高,即为越界了
    }
}

EnemyAward接口:

package cn.tedu.cn;
/*奖励接口*/
public interface EnemyAward {
    public int FIRE = 0;  //火力
    public int LIFE = 1;  //命

    /*获取奖励类型*/
    public int getAwardType();
}

EnemyScore接口:

package cn.tedu.cn;
/*得分接口*/
public interface EnemyScore {
    public int getScore();  //得分
}

FlyingObject超类:

package cn.tedu.cn;
import java.util.Random;
import java.awt.image.BufferedImage;
/*飞行物*/
public abstract class FlyingObject {
    public static final int LIVE = 0;   //活着的
    public static final int DEAD = 1;   //死了的
    public static final int REMOVE = 2; //删除的
    protected int state = LIVE;   //当前状态默认为活着的

    protected int width;   //宽
    protected int height;  //高
    protected int x;       //x坐标
    protected int y;       //y坐标

    //专门给小敌机,大敌机,小蜜蜂提供的
    //因为三种敌人的宽高不同,所以数据得写活,自然传参
    //因为三种敌人的x和y坐标相同,所以直接写死,不需要传参
    public FlyingObject(int width,int height){
        this.width=width;
        this.height=height;
        Random rand = new Random();   //随机数对象
        x = rand.nextInt(World.WIDTH-width);  //0到(窗口宽-小敌机宽)之间是随机数
        y = -height;                  //y:负的敌人的高
    }

    /*专门给英雄机、天空、子弹提供的*/
    //因为英雄机,天空,子弹的宽高xy都不同,所以数据都得写活,都得传参过来
    public FlyingObject(int width,int height,int x,int y){
        this.width=width;
        this.height=height;
        this.x=x;
        this.y=y;

    }
    public abstract void step();
    /*获取对象的图片*/
    public abstract BufferedImage getImage();
    /*判断是否活着的*/
    public boolean isLive() {
        return state==LIVE;  //当前状态为LIVE则表示为活着的,返回true,否则返回flase
    }
    /*判断是死了着的*/
    public boolean isDead() { //当前状态为DEAD则表示为活着的,返回true,否则返回flase
        return state==DEAD;
    }
    /*判断是否删除的*/
    public boolean isRemove() { //当前状态为REMOVE则表示为活着的,返回true,否则返回flase
        return state==REMOVE;
    }

    /*判断敌人是否越界*/
    public boolean isOutOfBounds() {
        return y>=World.HEIGHT;  //敌人的y>=窗口的高,即为越界了
    }

    /*检测敌人与子弹/英雄机的碰撞  this:敌人  other:子弹/英雄机*/
    public boolean isHit(FlyingObject other) {
        int x1 = this.x-other.width;  //x1:敌人的x-子弹/英雄机的宽
        int x2 = this.x+this.width;   //x2:敌人的x+敌人的宽
        int y1 = this.y-other.height; //y1:敌人的y-子弹/英雄机的高
        int y2 = this.y+this.height;  //y2:敌人的y+敌人的高
        int x = other.x;    //x:子弹/英雄机的x
        int y = other.y;    //y:子弹/英雄机的y

        return x>=x1 && x<=x2 && y>=y1 && y<=y2;
    }

    /*飞行物去死*/
    public void goDead() {
        state = DEAD;  //将当前状态修改为DEAD死了的
    }
}

Hero:

package cn.tedu.cn;

import java.awt.image.BufferedImage;

public class Hero extends FlyingObject {
    private int life;
    private int fire;

    public Hero() {
        super(97, 139, 140, 400);
        life = 3;
        fire = 0;
    }

    public void step() {
    }

    int index = 0;  //下标

    /*重写getImage()获取图片*/
    public BufferedImage getImage() {   //每十个毫毛走一次
        return Images.heros[index++ % Images.heros.length];  //在0到1之间来回切换

      /*                   index=0;
        10M   返 回hero[0]   index=1;
        20M   返 回hero[1]   index=2;
        30M   返 回hero[0]   index=3;
        40M   返 回hero[1]   index=4;
       */
    }

    /*英雄机发射子弹(生成子弹对象)*/
    public Bullet[] shoot() {
        int xStep = this.width / 4;   //1/4英雄机的宽
        int yStep = 2;
        if (fire > 0) {   //双倍火力
            Bullet[] bs = new Bullet[2];  //2发子弹
            bs[0] = new Bullet(this.x + 1 * xStep, this.y - yStep);  //x:英雄机的x+1/4英雄机的宽  y:英雄机的y-固定的20
            bs[1] = new Bullet(this.x + 3 * xStep, this.y - yStep);  //x:英雄机的x+3/4英雄机的宽  y:英雄机的y-固定的20
            fire -= 2;    //发射一次双倍火力,则火力值减2
            return bs;
        } else {   //单倍
            Bullet[] bs = new Bullet[1];  //1发子弹
            bs[0] = new Bullet(this.x + 2 * xStep, this.y - yStep);  //x:英雄机的x+2/4英雄机的宽  y:英雄机的y-固定的20
            return bs;
        }
    }

    /*英雄机随着鼠标移动*/
    public void moveTo(int x, int y) {
        this.x = x - this.width / 2;   //英雄机的x=鼠标的x-1/2英雄机的宽
        this.y = y - this.height / 2;  //英雄机的y=鼠标的y-1/2英雄机的高
    }

    /*英雄机增命*/
    public void addLife() {
        life++;  //命数加1
    }

    /*获取英雄机的命*/
    public int getLife() {
        return life;    //返回命数
    }

    /*英雄机减命*/
    public void subtractLife() {
        life--;//命数-1
    }

    /*清空火力值*/
    public void clearFire() {
        fire = 0;  //火力值为零
    }

    /*英雄机增火力*/
    public void addFire() {
        fire += 40;   //火力值增40
    }
}

Images:
package cn.tedu.cn;
//图片工具类
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class Images {
    //  公开的 静态的   数据类型   变量名
    public static BufferedImage sky;
    public static BufferedImage bullet;
    public static BufferedImage[] heros;
    public static BufferedImage[] airs;
    public static BufferedImage[] bairs;
    public static BufferedImage[] bees;

    public static BufferedImage start;
    public static BufferedImage pause;
    public static BufferedImage gameover;

    static {
        start = readImage("img/start.png");
        pause = readImage("img/pause.png");
        gameover = readImage("img/gameover.png");

        sky = readImage("img/background.png");
        bullet = readImage("img/bullet.png");

        heros = new BufferedImage[2];
        heros[0] = readImage("img/hero0.png");
        heros[1] = readImage("img/hero1.png");

        airs = new BufferedImage[5];
        airs[0] = readImage("img/airplane.png");
        bairs = new BufferedImage[5];
        bairs[0] = readImage("img/bigairplane.png");
        bees = new BufferedImage[5];
        bees[0] =  readImage("img/bee.png");
        for(int i=1;i<airs.length;i++) {  //赋值爆破图
            airs[i] = readImage("img/bom"+i+".png");
            bairs[i] = readImage("img/bom"+i+".png");
            bees[i] = readImage("img/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();
        }
    }
}

Sky:
package cn.tedu.cn;
import java.awt.image.BufferedImage;
/*天空:是飞行物*/
public class Sky extends FlyingObject{
    private int speed;;//移动速度
    private int y1;   //第二张图的y坐标

    /*构造方法*/
    public Sky(){
        super(World.WIDTH,World.HEIGHT,0,0);
        speed = 1;
        y1 = -World.HEIGHT;
    }
    public void step() {
        y += speed;   //y+(向下)
        y1+= speed;   //y+(向下)
        if(y>=World.HEIGHT) {  //若y>=窗口的高,意味着y移出去了
            y=-World.HEIGHT;   //则修改y的值为负的窗口的高(挪到最上面去了)
        }
        if(y1>World.HEIGHT) {  //若y1>=窗口的高,意味着y1一出去了
            y1=-World.HEIGHT;  //则修改y1的值为负的窗口的高(挪到最上面去了)
        }
    }
    /*重写getImage()获取图片*/
    public BufferedImage getImage() {
        return Images.sky;  //直接返回sky图片即可
    }
    /*获取y1坐标*/
    public int getY1() {
        return y1;
    }
}

World主程序:

package cn.tedu.cn;

import javax.swing.*;
import java.awt.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Random;
import java.util.Arrays;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class World extends JPanel {
    public static final int WIDTH = 400; // 窗口的宽
    public static final int HEIGHT = 700; // 窗口的高

    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;   //当前状态(默认为启动状态)

    private Sky sky = new Sky(); // 天空对象
    private Hero hero = new Hero(); // 英雄机

    private FlyingObject[] enemies = {}; // 敌人组
    private Bullet[] bullets = {}; // 子弹数组

    /* 敌人生成(小敌机,大敌机,小蜜蜂)对象 */
    public FlyingObject nextOne() {
        Random rand = new Random();
        int type = rand.nextInt(20); // 0到19之间的随机数
        if (type < 5) { // 0到4返回小蜜蜂对象
            return new Bee();
        } else if (type < 13) { // 5到12返回小蜜蜂对象
            return new Airplane();
        } else { // 13到19返回大敌机对象
            return new BigAirplane();
        }
    }

    private int enterIndex = 0;

    /* 敌人(小敌机,大敌机,小蜜蜂)入场 */
    public void enterAction() { // 每10毫秒做一次
        enterIndex++; // 每10毫秒增1
        if (enterIndex % 40 == 0) { // 每400毫秒走一次
            FlyingObject obj = nextOne(); // 获取敌人对象
            enemies = Arrays.copyOf(enemies, enemies.length + 1); // 扩容
            enemies[enemies.length - 1] = obj; // 将obj添加到最后一个元素上
        }
    }

    private int shootIndex = 0; // 子弹入场计数

    /* 子弹入场 */
    public void shootAction() { // 每10毫秒走一次
        shootIndex++; // 每10毫秒走一次
        if (shootIndex % 30 == 0) { // 每300毫秒走一次
            Bullet[] bs = hero.shoot(); // 获取子弹数组对象
            bullets = Arrays.copyOf(bullets, bullets.length + bs.length); // 扩容(bs有几个元素就扩大几个元素)
            System.arraycopy(bs, 0, bullets, bullets.length - bs.length, bs.length); // 数组的追加
        }
    }

    /*飞行物移动*/
    public void stepAction() {
        sky.step();  //天空动
        for (int i = 0; i < enemies.length; i++) {  //遍历所有敌人
            enemies[i].step();   //敌人动
        }
        for (int i = 0; i < bullets.length; i++) {   //遍历所有子弹
            bullets[i].step();   //子弹动
        }
    }

    /*删除越界的敌人和子弹*/
    public void outOfBoundsAction() {    //每10毫秒走一次
        for (int i = 0; i < enemies.length; i++) {  //遍历所有敌人
            if (enemies[i].isOutOfBounds() || enemies[i].isRemove()) { //判断是否出界或爆破
                enemies[i] = enemies[enemies.length - 1];  //把最后一个敌人放在出界敌人的位置
                enemies = Arrays.copyOf(enemies, enemies.length - 1);  //缩容
            }
        }
        for (int i = 0; i < bullets.length; i++) {   //遍历所有子弹
            if (bullets[i].isOutOfBounds() || bullets[i].isRemove()) {  //判断是否出界或爆破
                bullets[i] = bullets[bullets.length - 1];   //把最后一个子弹放在出界子弹的位置
                bullets = Arrays.copyOf(bullets, bullets.length - 1);  //缩容
            }
        }
    }

    private int score = 0;   //玩家得分

    /*子弹与敌人的碰撞*/
    public void bulletBangAction() {
        for (int i = 0; i < bullets.length; i++) {  //遍历所有子弹
            Bullet b = bullets[i];   //获取每个子弹
            for (int j = 0; j < enemies.length; j++) {   //遍历所有敌人
                FlyingObject f = enemies[j];    //获取每个敌人
                if (b.isLive() && f.isLive() && f.isHit(b)) {  //若都活着并且还撞上了
                    b.goDead();   //子弹去死
                    f.goDead();   //敌人去死

                    if (f instanceof EnemyScore) {  //若被撞对象能得分--所有实现EnemyScore的类
                        EnemyScore es = (EnemyScore) f;  //将被撞敌人强转为得分接口
                        score += es.getScore();   //玩家得分
                    }
                    if (f instanceof EnemyAward) {  //若被撞敌人为奖励--所有实现EnemyAward的类
                        EnemyAward ea = (EnemyAward) f;   //将被撞敌人强转为奖励接口
                        int type = ea.getAwardType();    //获取奖励类型
                        switch (type) {    //根据奖励类型来获取不同的奖励
                            case EnemyAward.FIRE:  //若奖励类型为火力
                                hero.addFire();    //则英雄机增火力
                                break;
                            case EnemyAward.LIFE:  //若奖励类型为命
                                hero.addLife();    //则英雄机增命
                                break;
                        }
                    }
                }
            }
        }
    }

    /*英雄机与敌人撞*/
    public void heroBangAction() {  //每10毫秒走一次
        for (int i = 0; i < enemies.length; i++) {  //遍历所有敌人
            FlyingObject f = enemies[i];  //获取每个敌人
            if (hero.isLive() && f.isLive() && f.isHit(hero)) {
                f.goDead();  //敌人去死
                hero.subtractLife();  //英雄机减命
                hero.clearFire();   //英雄机清空火力
            }
        }
    }

    public void checkGameOverAction() {
        if (hero.getLife() <= 0) {   //表示游戏结束了
            state = GAME_OVER;  //将当前状态修改为游戏结束状态
        }
    }

    /* 启动程序的执行 */
    public void action() {
        MouseAdapter m = new MouseAdapter() {
            public void mouseMoved(MouseEvent e) {
                if (state == RUNNING) {
                    int x = e.getX();  //获取鼠标的x坐标
                    int y = e.getY();  //获取鼠标的y坐标
                    hero.moveTo(x, y);  //英雄机随着鼠标移动
                }
            }

            public void mouseClicked(MouseEvent e) {
                switch (state) {   //根据当前状态做不同的处理
                    case START:   //启动状态时修改为运行状态
                        state = RUNNING;
                        break;
                    case GAME_OVER:  //游戏结束状态时修改为启动状态
                        score = 0;  //先清理现场,在修改为启动状态
                        sky = new Sky();
                        hero = new Hero();
                        enemies = new FlyingObject[0];
                        bullets = new Bullet[0];
                        state = START;//修改为启动状态
                        break;
                }
            }

            /*重写mouseExited()鼠标移出事件*/
            public void mouseExited(MouseEvent e) {
                if (state == RUNNING) {  //运行状态时修改为暂停状态
                    state = PAUSE;
                }
            }

            /* 重写mouseEntered()鼠标移入事件*/
            public void mouseEntered(MouseEvent e) {
                if (state == PAUSE) {   //暂停状态时修改为运行状态
                    state = RUNNING;
                }
            }
        };
        this.addMouseListener(m);
        this.addMouseMotionListener(m);

        Timer timer = new Timer(); // 定时器对象
        int intervel = 10; // 定时间隔(以毫秒为单位)
        timer.schedule(new TimerTask() {
            public void run() { // 定时器干的事(每十毫秒走一次)
                // 敌人入场 子弹入场 飞行物移动 子弹与敌人碰撞 英雄机与敌人碰撞
                if (state == RUNNING) {   //仅在运行状态下执行
                    enterAction();  //敌人(小敌机,大敌机,小蜜蜂)入场
                    shootAction();  //子弹入场
                    stepAction();   //飞行物移动
                    outOfBoundsAction();  //删除越界敌人
                    bulletBangAction();   //子弹与敌人碰撞
                    heroBangAction();   //英雄机与敌人的碰撞
                    checkGameOverAction();  //检测游戏结束
                }
                repaint(); // 重画 调用repaint() 画笔
            }
        }, intervel, intervel);  //定时计划表
    }

    /* 重写paint()画 */
    public void paint(Graphics g) { // 每10毫秒走一次
        g.drawImage(sky.getImage(), sky.x, sky.y, null); // 画天空1
        g.drawImage(sky.getImage(), sky.x, sky.getY1(), null); // 画天空2
        g.drawImage(hero.getImage(), hero.x, hero.y, null); // 画英雄机
        for (int i = 0; i < enemies.length; i++) { // 遍历所有敌人
            FlyingObject f = enemies[i]; // 获取每个敌人
            g.drawImage(f.getImage(), f.x, f.y, null); // 画敌人
        }
        for (int i = 0; i < bullets.length; i++) { // 遍历所有子弹
            Bullet b = bullets[i]; // 获取每个子弹
            g.drawImage(b.getImage(), b.x, b.y, null); // 画子弹
        }

        g.drawString("分数:" + score, 10, 25);      //画分
        g.drawString("生命:" + hero.getLife(), 10, 45);   //画命

        /*画启动图,暂停图,结束图*/
        switch (state) {
            case START:
                g.drawImage(Images.start, 0, 0, null);
                break;
            case PAUSE:
                g.drawImage(Images.pause, 0, 0, null);
                break;
            case GAME_OVER:
                g.drawImage(Images.gameover, 0, 0, null);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("飞机大战");
        World world = new World();
        frame.add(world);
        Image icon = Toolkit.getDefaultToolkit().getImage("C:\\Users\\才哥\\Desktop\\Shoot\\src\\cn\\tedu\\cn\\img\\1.png");
        frame.setIconImage(icon);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH, HEIGHT);
        frame.setLocationRelativeTo(null);


        frame.setVisible(true); // 设置窗口可见 尽快调用

        world.action();
    }
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐