飞机大战JAVA编程

飞机大战JAVA编程

最近在学习java语言,飞机大战是其中一个练习小项目。这里记录一下写这个程序的思路。

  • 首先是需求分析,这里建立项目需求的思维导图,一目了然:

    这里写图片描述
  • 然后是思路分析

    这里写图片描述
    这是写程序前列举的一个基本的思路,以此为主线,写的时候遇到具体问题再进行修改,最后得出最终程序。
  • 最后是写好的程序结构图:

    这里写图片描述

这里就不多写文字了,所有内容都在图中,下面是运行结果和源代码。
运行结果:


这里写图片描述
源码:

//FlyingObject类,抽象类:
package com.centerm.shoot;

import java.awt.image.BufferedImage;
/**
 * 将四个主要角色的共同属性提取出来组成一个父类
 * @author 89447
 */
public abstract class FlyingObject {
    //定义所有飞行器共有的属性:图片、坐标、尺寸
    protected BufferedImage image;
    protected int x;
    protected int y;
    protected int width;
    protected int height;
    //定义所有飞行器共有的方法:移动、越界
    public abstract void moveFlying();
    public abstract boolean outOfBound();
    //下面定义的这个方法只有Airplane和Bee使用
    public boolean shootBy(Bullet bullet){
        int x1 = this.x;
        int x2 = this.x + this.width;
        int y1 = this.y;
        int y2 = this.y + this.height;

        int xb1 = bullet.x;
        int xb2 = bullet.x + bullet.width;
        int yb1 = bullet.y;
        int yb2 = bullet.y + bullet.height;

        return (xb1>x1 && xb1<x2) && (yb1>y1 && yb1<y2) ||
                 (xb2>x1 && xb2<x2) && (yb1>y1 && yb1<y2) ||
                 (xb1>x1 && xb1<x2) && (yb2>y1 && yb2<y2) ||
                 (xb2>x1 && xb2<x2) && (yb2>y1 && yb2<y2);
    }
}
package com.centerm.shoot;

import java.util.Random;
/**
 * 敌机
 * @author 89447
 *
 */
public class Airplane extends FlyingObject{
    //前进速度
    private int speed;
    //构造方法
    public Airplane(){
        image = Stage.airplane;
        x = new Random().nextInt(Stage.STAGE_WIDTH - image.getWidth());
        y = -image.getHeight();
        width = image.getWidth();
        height = image.getHeight();
        speed = 3;
    }
    //移动
    public void moveFlying(){
        this.y += this.speed;
    }
    //出界判断
    public boolean outOfBound() {
        return this.y > Stage.STAGE_HEIGHT;
    }
}
package com.centerm.shoot;

import java.util.Random;
/**
 * 蜜蜂类
 * @author 89447
 *
 */
public class Bee extends FlyingObject{
    //奖励类型
    public static final int AWARD_LIFE = 0;
    public static final int AWARD_FIRE = 1;
    //左右飞行,用于飞行方向的改变
    private static final int FLY_RIGHT = 1;
    private static final int FLY_LEFT = -1;
    //飞行方向变量
    private int flyingDirection = FLY_RIGHT;
    //X、Y方向上前进的速度
    private int speedX;
    private int speedY;

    //构造函数
    public Bee(){
        image = Stage.bee;
        x = new Random().nextInt(Stage.STAGE_WIDTH - image.getWidth());
        y = -image.getHeight();
        width = image.getWidth();
        height = image.getHeight();

        speedX = 2;
        speedY = 1;
    }
    //移动一步
    public void moveFlying(){
        /**
         * 先确定小蜜蜂飞行的方向
         */
        if(this.x >= Stage.STAGE_WIDTH - this.width){
            flyingDirection = FLY_LEFT;
        }
        if(this.x <= 0){
            flyingDirection = FLY_RIGHT;
        }
        /**
         * 再根据方向进行移动
         */
        if(flyingDirection == FLY_RIGHT){
            this.x += this.speedX;
            this.y += this.speedY;
        }else{
            this.x -= this.speedX;
            this.y += this.speedY;
        }
    }
    //获取奖励类型
    public int getAwardType(){
        return new Random().nextInt(2)==AWARD_LIFE ? AWARD_LIFE : AWARD_FIRE;
    }
    //判断出界
    public boolean outOfBound() {
        return this.y > Stage.STAGE_HEIGHT;
    }
}
package com.centerm.shoot;
/**
 * 子弹类
 * @author 89447
 *
 */
public class Bullet extends FlyingObject{
    //子弹运行速率
    private int speed;
    //构造函数
    public Bullet(int x, int y){
        this.x = x;
        this.y = y;
        image = Stage.bullet;
        width = image.getWidth();
        height = image.getHeight();
        speed = 4;
    }
    //子弹移动一步
    public void moveFlying(){
        this.y -= this.speed;
    }
    //判断出界
    public boolean outOfBound() {
        return this.y < 0;
    }
}
package com.centerm.shoot;
/**
 * 英雄机的类
 * @author 89447
 *
 */
public class Hero extends FlyingObject{
    //定义默认生命值
    private static final int DEFAULT_LIFE = 3;  
    //定义移动方向,用于键盘控制
    public static final int MOVE_UP = 1;        
    public static final int MOVE_DOWN = -1;
    public static final int MOVE_LEFT = 2;
    public static final int MOVE_RIGHT = -2;
    //定义一次移动的距离,用于键盘控制
    public static final int STEP_DISTANCE = 10;         
    //定义火力值、生命值
    private int firePower;
    private int life;
    //构造函数
    public Hero(int x, int y){
        this.x = x;
        this.y = y;
        image = Stage.hero0;
        width = image.getWidth();
        height = image.getHeight();

        firePower = 0;
        life = DEFAULT_LIFE;
    }
    //获取生命值
    public int getLife(){
        return life;
    }
    //生命值减一
    public void substactLife() {
        this.life --;
    }
    //生命值加一
    public void addLife() {
        this.life ++;
    }
    //获取双倍火力值
    public int getFirePower(){
        return firePower;
    }
    //清空火力值
    public void clrFirePower(){
        firePower = 0;
    }
    //火力值增加固定的数值
    public void addFirePower(){
        firePower += 40;
    }
    //英雄机按照某个方向移动一步,用于键盘控制
    public void moveDirection(int direction){
        switch (direction) {
        case MOVE_DOWN:
            if(this.y >= Stage.STAGE_HEIGHT - this.height){
                break;
            }else if(this.y >= Stage.STAGE_HEIGHT - this.height- STEP_DISTANCE &&
                    this.y <Stage.STAGE_HEIGHT - this.height){
                this.y = Stage.STAGE_HEIGHT - this.height;
            }else{
                this.y += STEP_DISTANCE;
            }
            break;
        case MOVE_UP:
            if(this.y == 0){
                break;
            }else if(this.y > 0 && this.y <= STEP_DISTANCE){
                this.y = 0;
            }else {
                this.y -= STEP_DISTANCE;
            }
            break;
        case MOVE_LEFT:
            if(this.x == 0){
                break;
            }else if(this.x > 0 && this.x <= STEP_DISTANCE){
                this.x = 0;
            }else {
                this.x -= STEP_DISTANCE;
            }
            break;
        case MOVE_RIGHT:
            if(this.x == Stage.STAGE_WIDTH - this.width){
                break;
            }else if(this.x >= Stage.STAGE_WIDTH - this.width - STEP_DISTANCE && 
                this.x < Stage.STAGE_WIDTH - this.width){
                this.x = Stage.STAGE_WIDTH - this.width;
            }else {
                this.x += STEP_DISTANCE;
            }
            break;
        default:
            break;
        }
    }
    //英雄机移动,用于图片切换
    private int indexOfImage = 0;
    public void moveFlying(){
        indexOfImage = 1 - indexOfImage;
        if(indexOfImage == 0){
            image = Stage.hero0;
        }else{
            image = Stage.hero1;
        }
    }
    //直接将英雄机移动到某个确定的位置,用于鼠标控制
    public void setLocation(int x, int y){
        this.x = x - this.width/2;
        this.y = y - this.height/2;
    }
    //创建子弹,可能是一个,也可能是两个,因此这里返回数组
    public Bullet[] createBullets(){
        if(firePower > 0){
            firePower -= 2;
            return new Bullet[]{new Bullet(this.x + this.width/4 - 10, this.y), 
                                new Bullet(this.x + this.width*3/4 - 10, this.y)};
        }else {
            return new Bullet[]{new Bullet(this.x + this.width/2 - 10, this.y)};
        }
    }
    //出界判断,由于英雄机无法出界,因此这里返回null
    public boolean outOfBound() {
        return false;
    }
    //英雄机撞击敌机判断
    public boolean hitFlying(FlyingObject flying){
        int x1 = this.x;
        int x2 = this.x + this.width;
        int y1 = this.y;
        int y2 = this.y + this.height;

        int xb1 = flying.x;
        int xb2 = flying.x + flying.width;
        int yb1 = flying.y;
        int yb2 = flying.y + flying.height;

        return (xb1>x1 && xb1<x2) && (yb1>y1 && yb1<y2) ||
                 (xb2>x1 && xb2<x2) && (yb1>y1 && yb1<y2) ||
                 (xb1>x1 && xb1<x2) && (yb2>y1 && yb2<y2) ||
                 (xb2>x1 && xb2<x2) && (yb2>y1 && yb2<y2);
    }
}
//舞台类,关键
package com.centerm.shoot;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * 舞台类
 * @author 89447
 *
 */
@SuppressWarnings("serial")
public class Stage extends JPanel{
    public static final int STAGE_WIDTH = 400;
    public static final int STAGE_HEIGHT = 650;
    public static final String PATH = "." + File.separator + "src" + File.separator + "com" + File.separator + "centerm" + File.separator + "shoot" + File.separator;
    /**
     * 下面统一管理图片,也可以放在各个具体的类中,但是会显得比较混乱,因此这里放在一起
     */
    public static BufferedImage hero0;
    public static BufferedImage hero1;
    public static BufferedImage bee;
    public static BufferedImage bullet;
    public static BufferedImage airplane;
    public static BufferedImage background;
    public static BufferedImage pause;
    public static BufferedImage start;
    public static BufferedImage gameover;

    //定义几个状态
    public static final int START = 0;
    public static final int RUNNING = 1;
    public static final int PAUSE = 2;
    public static final int GAMEOVER = 3;

    //状态变量
    private int state = START;

    //主要的成员变量
    private Hero hero = new Hero(200,300);;
    private Bullet[] bullets = {};
    private FlyingObject[] flyings = {};

    //分数
    private int score = 0;

    //初始化图片的静态块
    static{
        try {
            hero0 = ImageIO.read(new File(PATH + "hero0.bmp"));
            hero1 = ImageIO.read(new File(PATH + "hero1.bmp"));
            bee = ImageIO.read(new File(PATH + "bee.bmp"));
            bullet = ImageIO.read(new File(PATH + "bullet.bmp"));
            airplane = ImageIO.read(new File(PATH + "airplane.bmp"));
            background = ImageIO.read(new File(PATH + "background.bmp"));
            pause = ImageIO.read(new File(PATH + "pause.bmp"));
            start = ImageIO.read(new File(PATH + "start.bmp"));
            gameover = ImageIO.read(new File(PATH + "gameover.bmp"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    //绘制所有元素
    public void paint(Graphics g) {
        // TODO Auto-generated method stub
        g.drawImage(background, 0, 0, null);    //绘制背景图片
        paintHero(g);   //绘制英雄机
        paintFlyings(g);//绘制敌机:包括小蜜蜂和飞行器
        paintBullet(g); //绘制子弹:
        paintText(g);
        paintState(g);
    }

    //绘制英雄机,为paint()服务
    public void paintHero(Graphics g){
        g.drawImage(hero.image, hero.x, hero.y, null);
    }

    //绘制敌机,为paint()服务
    public void paintFlyings(Graphics g){
        for(FlyingObject flying : flyings){
            g.drawImage(flying.image, flying.x, flying.y, null);
        }
    }

    //绘制子弹,为paint()服务
    public void paintBullet(Graphics g){
        for(Bullet bullet : bullets){
            g.drawImage(bullet.image, bullet.x, bullet.y, null);
        }
    }

    //绘制文字信息,为paint()服务
    public void paintText(Graphics g){
        g.setColor(new Color(0xff0000));
        g.setFont(new Font(Font.DIALOG, 20, 20));
        g.drawString("生命数:"+Integer.toString(hero.getLife()), 0, 100);
        g.drawString("分数:"+Integer.toString(score), 0, 50);
        g.drawString("火力剩余:"+Integer.toString(hero.getFirePower()), 0, 75);
    }

    //绘制各个状态下的图片,为paint()服务
    public void paintState(Graphics g){
        switch(state){
        case START:
            g.drawImage(start, 0, 0, null);
            break;
        case RUNNING:

            break;
        case PAUSE:
            g.drawImage(pause, 0, 0, null);
            break;
        case GAMEOVER:
            g.drawImage(gameover, 0, 0, null);
            break;
        default:
            break;
        }
    }

    //生成新的敌机,为FlyingEnter()方法服务
    public FlyingObject createFlying(){
        Random random = new Random();
        if(random.nextInt(20) < 2){
            return new Bee();
        }else{
            return new Airplane();
        }
    }

    //敌机入场
    int flyingEnterDelay = 0;
    public void FlyingEnter(){
        if(flyingEnterDelay ++ >= 40){
            flyingEnterDelay = 0;
            flyings = Arrays.copyOf(flyings, flyings.length + 1);
            flyings[flyings.length - 1] = createFlying();
        }
    }

    //子弹入场
    int BulletEnterDelay = 0;
    public void BulletEnter(){
        if(BulletEnterDelay ++ >= 20){
            BulletEnterDelay = 0;
            Bullet[] bullets_temp = hero.createBullets();
            bullets = Arrays.copyOf(bullets, bullets.length + bullets_temp.length);
            for(int i = 0; i<bullets_temp.length; i++){
                bullets[bullets.length - i - 1] = bullets_temp[i];
            }
        }
    }

    //移动一帧
    public void moveStepAction(){
        //移动英雄机:切换图片
        hero.moveFlying();
        //移动敌机
        for(FlyingObject flying: flyings){
            flying.moveFlying();
        }
        //移动子弹
        for(Bullet bullet: bullets){
            bullet.moveFlying();
        }
    }

    //出界处理方法
    public void outOfBoundAction(){
        FlyingObject[] flying_temp = new FlyingObject[flyings.length];
        int flying_index = 0;
        for(int i = 0; i<flyings.length; i++){
            FlyingObject flying = flyings[i];
            if(!flying.outOfBound()){
                flying_temp[flying_index ++] = flying;
            }
        }
        flyings = Arrays.copyOf(flying_temp, flying_index);

        Bullet[] bullets_temp = new Bullet[bullets.length];
        int bullet_index = 0;
        for(int i = 0; i<bullets.length; i++){
            Bullet bullet = bullets[i];
            if(!bullet.outOfBound()){
                bullets_temp[bullet_index ++] = bullet;
            }
        }
        bullets = Arrays.copyOf(bullets_temp, bullet_index);
    }

    //一颗子弹射击敌机方法,为shootAction()服务
    public boolean bulletShootFlyings(Bullet bullet){
        int index = -1;
        FlyingObject flying;
        for(int i = 0; i<flyings.length; i++){
            flying = flyings[i];
            if(flying.shootBy(bullet)){
                index = i;  //如果有撞击到,将被撞击的元素下标取出,在外部处理这个元素,避免嵌套过深
                break;
            }
        }

        if(index != -1){
            flying = flyings[index];
            if(flying instanceof Bee){
                int type = ((Bee) flying).getAwardType();
                if(type == Bee.AWARD_FIRE){
                    hero.addFirePower();
                }
                if(type == Bee.AWARD_LIFE){
                    hero.addLife();
                }
            }
            if(flying instanceof Airplane){
                score += 5;
            }

            //省去了使用循环操作的麻烦
            flyings[index] = flyings[flyings.length - 1];
            flyings = Arrays.copyOf(flyings, flyings.length - 1);
            return true;
        }
        return false;
    }

    //子弹击落敌机方法
    public void shootAction(){
        Bullet[] bullets_temp = new Bullet[bullets.length];
        int bullet_index = 0;
        for(int i = 0; i<bullets.length; i++){
            Bullet bullet = bullets[i];
            if(!bulletShootFlyings(bullet)){
                bullets_temp[bullet_index ++] = bullet;
            }
        }

        bullets = Arrays.copyOf(bullets_temp, bullet_index);
    }

    //英雄机撞击敌人
    public void hitAction(){
        for(int i = 0; i<flyings.length; i++){
            FlyingObject flying = flyings[i];
            if(hero.hitFlying(flying)){
                hero.substactLife();
                hero.clrFirePower();

                flyings[i] = flyings[flyings.length - 1];
                flyings = Arrays.copyOf(flyings, flyings.length - 1);
            }
        }
    }

    public void gameOverAction(){
        if(hero.getLife() <= 0){
            state = GAMEOVER;
        }
    }

    public void action(){
        Timer timer = new Timer();
        /**
         * 用于移动的定时任务
         */
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(state == RUNNING){
                    FlyingEnter();
                    BulletEnter();
                    moveStepAction();
                    outOfBoundAction();
                    shootAction();
                    hitAction();
                    gameOverAction();
                }
                repaint();
            }
        }, 0, 10);

        /**
         * 键盘控制英雄机的行动
         */
        this.requestFocus();    
        this.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {    
                if(state == RUNNING){   //程序没有运行时英雄机是不能动的
                    switch(e.getKeyCode()){
                    case KeyEvent.VK_UP:
                        hero.moveDirection(Hero.MOVE_UP);
                        repaint();
                        break;
                    case KeyEvent.VK_DOWN:
                        hero.moveDirection(Hero.MOVE_DOWN);
                        repaint();
                        break;
                    case KeyEvent.VK_LEFT:
                        hero.moveDirection(Hero.MOVE_LEFT);
                        repaint();
                        break;
                    case KeyEvent.VK_RIGHT:
                        hero.moveDirection(Hero.MOVE_RIGHT);
                        repaint();
                        break;
                    default:
                        break;
                    }
                }
            }
        });

        /**
         * 鼠标控制英雄机的行动
         */
        MouseAdapter adapter = new  MouseAdapter() {
            public void mouseMoved(MouseEvent arg0) {
                if(state == RUNNING){   //状态不是运行时候不能移动英雄机
                    hero.setLocation(arg0.getX(), arg0.getY());
                }
            }

            public void mouseClicked(MouseEvent arg0) {
                if(state == START){
                    state = RUNNING;
                }
                if(state == GAMEOVER){
                    score = 0;
                    hero = new Hero(200, 300);
                    flyings = new FlyingObject[]{};
                    bullets = new Bullet[]{};
                    state = START;
                }
            }

            public void mouseExited(MouseEvent arg0) {
                if(state == RUNNING){
                    state = PAUSE;
                }
            }

            public void mouseEntered(MouseEvent arg0) {
                if(state == PAUSE){
                    state = RUNNING;
                }
            }
        };
        this.addMouseListener(adapter);
        this.addMouseMotionListener(adapter);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Stage panel = new Stage();
        frame.add(panel);
        frame.setSize(STAGE_WIDTH+10, STAGE_HEIGHT+10);
        frame.setAlwaysOnTop(true);     //将串口一直放在所有窗口之上
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   //设置默认关闭操作为串口关闭时退出程序
        frame.setLocationRelativeTo(null);  //设置窗口位置居中
        frame.setVisible(true);         //显示窗口,尽快调用paint()方法
        panel.action();
    }
}

猜你喜欢

转载自blog.csdn.net/zou8944/article/details/52565650