1、效果图

1.png

2、代码

(1)主类PanelGame.java

package com.swing.plane;

import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.swing.util.ImageLoadUtil;

/**
 * 主类
 * @author may
 *
 */
public class PanelGame extends Frame {

    private static final long serialVersionUID = 6719627071124599012L;
    //我方飞机场
    private List<Panel> Goodpanels = new ArrayList<Panel>();
    //敌军飞机场
    private List<Panel> panels = new ArrayList<Panel>();
    //公共的子弹工厂
    private List<Shell> shells = new ArrayList<Shell>(); 
    //随机
    private Random random = new Random();
    //战场背景
    private static Image image = ImageLoadUtil.loadImage("/lib/bg.jpg");
    //缓冲图
    private BufferedImage buffImage = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);    
    //爆炸
    private List<Explode> explodes = new ArrayList<Explode>();
    //杀敌数
    public int killEnemyCount = 0;
    //死亡次数
    public int deadCount = 0;
    
    public PanelGame() {
        this.setSize(500,500);
        this.setLocation(300, 100);
        this.addWindowListener(new WindowAdapter() {
            
            @Override
            public void windowClosing(WindowEvent e) {
                PanelGame.this.dispose();
            }
            
        });
        //在显示(画窗口前new出来,否则会报空指针异常)
        //panel = new Panel(100,100, false);
        this.addKeyListener(new keyCtrl());
        this.createGoodPanels(1);
        this.setVisible(true);
        new Thread(new MyThread()).start();
        
    }
    
    
    
    public void createPanels(int num) {
        for(int i = 0; i < num; i++) {
            panels.add(new Panel(this, true));
        }
        
    }
    
    public void createGoodPanels(int num) {
        if(Goodpanels.size() <= 0) {
            
            for(int i = 0; i < num; i++) {
                Goodpanels.add(new Panel(452, 250, false, this));
            }
            
        }
    }
    
    
    
    public List<Explode> getExplodes() {
        return explodes;
    }



    public List<Shell> getShells() {
        return shells;
    }



    public List<Panel> getPanels() {
        return panels;
    }
    
    
    

    public List<Panel> getGoodpanels() {
        return Goodpanels;
    }



    @Override
    public void paint(Graphics g) {
        g.drawImage(buffImage, 0, 0, null);
    }
    
    @Override
    public void update(Graphics g) {
        Graphics warG = buffImage.getGraphics();
        warG.fillRect(0, 0, 500, 500);
        warG.drawImage(image, 0, 0, 500, 500, null);
        Color c = warG.getColor();
        warG.setColor(Color.gray);
        warG.setFont(new Font("微软雅黑", Font.PLAIN, 18));
        warG.drawString("击毁敌机:" + killEnemyCount, 10, 50);
        warG.drawString("死亡次数:" + deadCount, 10, 80);
        
        for(int i = 0; i < Goodpanels.size(); i++) {
            Goodpanels.get(i).draw(warG);
            warG.drawString("生命值:" + Goodpanels.get(i).lifeValue, 10, (i+1)*30 + 80);
        }
        warG.setColor(c);
        for(int i = 0; i < panels.size(); i++) {
            panels.get(i).draw(warG);
        }
        for(int i = 0; i < shells.size(); i++) {
            shells.get(i).draw(warG);
        }
        for(int i = 0; i < explodes.size(); i++) {
            explodes.get(i).draw(warG);
        }
        paint(g);
        warG.setColor(c);
        if(this.getPanels().size() < 3) {
            this.createPanels(random.nextInt(6) + 1);
            
        }
    }
    
    
    
    
    public List<Panel> getPanel() {
        return Goodpanels;
    }



    public static void main(String[] args) {
        new PanelGame();
    }
    
    private class keyCtrl extends KeyAdapter {

        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();
            if(keyCode == KeyEvent.VK_F1) {
                createGoodPanels(1);
                
            }
            
            for(int i = 0; i < Goodpanels.size(); i++) {
                
                Goodpanels.get(i).keyPressed(e);
            }
            
        }

        @Override
        public void keyReleased(KeyEvent e) {
            for(int i = 0; i < Goodpanels.size(); i++) {
                
                Goodpanels.get(i).keyReleased(e);
            }
        } 
    }
    
    private class MyThread implements Runnable {

        @Override
        public void run() {
            while(true) {
                repaint();
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
        }
        
    }
    
}

(2)Panel.java

package com.swing.plane;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Random;

import com.swing.util.ImageLoadUtil;
/**
 * 飞机类
 * @author may
 *
 */
public class Panel {
    
    private int x;//位置
    private int y;//位置
    private static final int WIDTH = 48;//飞机的大小
    private static final int HEIGHT = 48;//飞机的大小
    private static final int WAR_WIDTH = 500;//游戏窗口的大小
    private static final int WAR_HEIGHT = 500;//游戏窗口的大小
    private boolean up = false, right = false, down = false, left = false;//飞机的移动方向
    private boolean enemy = true;//默认为敌机
    private static Image[] images = new Image[2];//敌机与我方的飞机图片
    private List<Shell> shells = null;//子弹容器
    private int step = 1;//移动的步数
    private boolean isLive = true;//默认飞机生存
    private int oldX = x;//记录飞机上一次的位置
    private int oldY = y;//记录飞机上一次的位置
    private int keep = 0;//敌机自动发射子弹的间隔
    private Random random = new Random();//定义随机数,用于定义敌机的子弹发射的时间间隔
    private Director dir = Director.STOP;//飞机默认是不动的
    private PanelGame game;//游戏主类
    public int lifeValue = 90;//飞机的生命值
    
    static {
        for(int i = 0; i < images.length; i++) {
            images[i] = ImageLoadUtil.loadImage("/lib/plane" + (i + 1) + ".png");
            images[i].getWidth(null);
            
        }
        
}        
    public Panel(PanelGame game, boolean enemy) {
        this.game = game;
        this.enemy = enemy;
        //如果是敌机,定义它初始位置
        if(this.enemy) {
            this.x = - random.nextInt(3 * WIDTH) ;
            this.y = random.nextInt(WAR_HEIGHT - 2 * HEIGHT) + HEIGHT;
        }
        this.shells = game.getShells();
    }    
    
    public Panel(int x, int y, boolean enemy, PanelGame game) {
        this.x = x;
        this.y = y;
        this.enemy = enemy;
        this.game = game;
        this.shells = game.getShells();
}
            
    public void draw(Graphics g) {
        //如果飞机还活着,就画它
        if(this.isLive) {
            
            Color c = g.getColor();
            if(enemy) {
                g.drawImage(images[1], x, y, WIDTH, HEIGHT, null);
                
            } else {
                g.drawImage(images[0], x, y, WIDTH, HEIGHT, null);
            }
            g.setColor(c);
            g.setColor(c);
            
            this.move();
            if(enemy) {
                this.hit(game);
            }
        }
    }
    
    /**
     * 创建子弹
     */
    public void createShells() {
        if(!enemy) {
            this.getShells().add(new Shell(x - 10, y + 20, this, false, game));
            
        } else {
            
            this.getShells().add(new Shell(x + 50, y + 20, this, true, game));
        }
    
    }
    
    

    public boolean isEnemy() {
        return enemy;
    }

    public int getX() {
        return x;
    }
  
    public List<Shell> getShells() {
        //shells = game.getShells();
        return shells;
    }
    //如果飞机被击毁,飞机在飞机战场上消失(主类的容器)
    public void removedeadPlane() {
        this.isLive = false;
        if(!this.isLive && this.enemy) {
            game.getPanels().remove(this);
        } 
        if(!this.isLive && !this.enemy) {
            game.getPanel().remove(this);
        } 
        
    }

    public boolean isLive() {
        return isLive;
    }
    
    public void setLive(boolean isLive) {
        this.isLive = isLive;
    }

    public int getY() {
        return y;
    }
    //确定方向,这些方向的确定是通过按键监听来确定
    private void directer() {
        if( left && !down && !right && !up ) {
            dir = Director.L;
        }else if( left && up && !right && !down ) {
            dir = Director.LU;    
        }else if( up && !left && !right && !down ) {
            dir = Director.U;
        }else if( up && right && !left && !down ) {
            dir = Director.RU;
        }else if( right && !up && !left && !down ) {
            dir = Director.R;
        }else if( right && down && !up && !left ) {
            dir = Director.RD;
        }else if( down && !up && !right && !left ) {
            dir = Director.D;
        }else if( left && down && !right && !up ) {
            dir = Director.LD;
        }else if( !left && !up && !right && !down ) {
            dir = Director.STOP;
        }
    }

    //根据方向的移动方法
    public void move() {
        oldX = x;
        oldY = y;
        
        switch(dir) {
        case L:
            x -= step;
            break;
        case LU:
            x -= step;
            y -= step;
            break;
        case U:
            y -= step;
            break;
        case RU:
            x += step;
            y -= step;
            break;
        case R:
            x += step;
            break;
        case RD:
            x += step;
            y += step;
            break;
        case D:
            y += step;
            break;
        case LD:
            x -= step;
            y += step;
            break;
        case STOP:
            break;
        }
        //如果不是敌机,不允许它跑出战场
        if(!enemy) {            
            if(x > (WAR_WIDTH - 48) || x < 0) {
                x = oldX;                
            }
            if(y > (WAR_HEIGHT - 48) || y < 30) {
                y = oldY;
            }            
        }
        //如果是敌机,确定它的方向
        if(enemy) {
            dir = Director.R;
            //每隔50个刷新周期,发射一枚子弹
            if(keep == 0) {
                keep = 50;
                this.createShells();
            }
            keep --;
            //如果敌机逃出战场,摧毁它
            if(x > WAR_WIDTH) {
                game.getPanels().remove(this);
                
            }            
        }        
    }
    
    //键盘按下监听事件,由主类调用
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        switch(keyCode) {
        case KeyEvent.VK_UP  : 
            this.up = true;
            break;
        case KeyEvent.VK_RIGHT :
            this.right = true;
            break;
        case KeyEvent.VK_DOWN :
            this.down = true;
            break;
        case KeyEvent.VK_LEFT  :
            this.left = true;
            break;
        }
        this.directer();
        
    }
    //键盘抬起监听事件,由主类调用
    public void keyReleased(KeyEvent e) {
        int keyCode = e.getKeyCode();
        switch(keyCode) {
        case KeyEvent.VK_UP : 
            this.up = false;
            break;
        case KeyEvent.VK_RIGHT :
            this.right = false;
            break;
        case KeyEvent.VK_DOWN :
            this.down = false;
            break;
        case KeyEvent.VK_LEFT :
            this.left = false;
            break;
        case KeyEvent.VK_CONTROL :
            this.createShells();
            break;
        }
        this.directer();
    }
    //矩形碰撞检测
    public Rectangle getRectangle() {
        
        return new Rectangle(this.x, this.y, WIDTH, HEIGHT);        
    }
    
    //撞到了就爆炸
        public void createExplode() {            
            game.getExplodes().add(new Explode(this.x, this.y, game));
        }
    
    public void hit(PanelGame game) {
        
        if(this.enemy) {
            List<Panel> p = game.getGoodpanels();
            for(int i = 0; i < p.size(); i++) {
                if(this.getRectangle().intersects(p.get(i).getRectangle())) {
                    game.getPanels().remove(this);
                    
                    p.get(i).lifeValue -= 30;
                        
                    
                    if(p.get(i).lifeValue <= 0) {
                        
                        game.getGoodpanels().remove(p.get(i));
                        
                    } 
                    this.createExplode();  
                }
            }            
        }         
    }
}

(3)、Shell.java炮弹类

package com.swing.plane;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.List;
/**
 * 炮弹类
 * @author may
 *
 */
public class Shell {
    
    private int x;
    private int y;
    private static final int WIDTH = 10;
    private static final int HEIGHT = 10;
    private boolean enemy = false;
    private boolean isLive = true;
    private Panel panel;
    private PanelGame game;
    private int step =2;
    public Shell(int x, int y, Panel panel, boolean enemy, PanelGame game) {
        this.x = x;
        this.y = y;
        this.panel = panel;
        this.enemy = enemy;
        this.game = game;
    }
    
    public void draw(Graphics g) {
        if(this.isLive) {
          Color c = g.getColor();
            if(enemy) {                
                g.setColor(Color.red);
            } else {                
                g.setColor(Color.yellow);
            }
            g.fillOval(this.x, this.y, WIDTH, HEIGHT);
            g.setColor(c);
            move();
            this.hit(game);
        }        
    }
    public Rectangle getRectangle() {
        Rectangle rectangle = new Rectangle(x, y, WIDTH, HEIGHT);
        
        return rectangle;
}

    public boolean isLive() {
        return isLive;
    }

    public void setLive(boolean isLive) {
        this.isLive = isLive;
    }

    public void move() {
        if(!enemy) {
            x -= step;
        } else {
            x += step;
        }
        
        if(x < 10 || x > 500) {
            this.setLive(false);
            panel.getShells().remove(this);
        }
        
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }
    //撞到了就爆炸
    public void createExplode() {
        
        game.getExplodes().add(new Explode(this.x, this.y, game));
    }
    //碰撞检测方法
    public void hit(PanelGame game) {
        List<Panel> enemys = game.getPanels();
        List<Panel> goods = game.getPanel();
        for(int i = 0; i < enemys.size(); i++) {
            if(this.enemy != enemys.get(i).isEnemy()) {
                
                if(this.getRectangle().intersects(enemys.get(i).getRectangle())) {
                    this.setLive(false);
                    panel.getShells().remove(this);
                    enemys.get(i).removedeadPlane();
                    this.createExplode();
                    game.killEnemyCount ++;
                }
            }
            
        }
        
        for(int i = 0; i < goods.size(); i++) {
            if(this.enemy != goods.get(i).isEnemy()) {
                
                if(this.getRectangle().intersects(goods.get(i).getRectangle())) {
                    this.setLive(false);
                    panel.getShells().remove(this);
                    goods.get(i).lifeValue -= 30;
                    
                    if(goods.get(i).lifeValue <= 0) {
                        game.deadCount ++;
                        goods.get(i).removedeadPlane();
                        
                    } 
                    this.createExplode();
                }
            }
            
        }
        
    }
}

(4)爆炸类Explode.java

package com.swing.plane;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;

import com.swing.util.ImageLoadUtil;
/**
 * 爆炸类
 * @author may
 *
 */
public class Explode {
    
    private int x;//爆炸位置
    private int y;//爆炸位置
    private static Image[] images = new Image[10];
    private int count = 0;//当前播放到的图片在数组中的下标
    private PanelGame game;//持有主窗口的引用
    
    //静态加载图片
    static {
        for(int i = 0; i < images.length; i++) {
            images[i] = ImageLoadUtil.loadImage("/lib/explode/" + (i) + ".gif");
            //避免Java的懒加载,让它一用到就可直接用,否则可能一开始的一两张图将看不到
            images[i].getHeight(null);
        }
   }
    /**
     * 
     * @param x 位置
     * @param y 位置
     * @param game 游戏主类
     */
    public Explode(int x, int y, PanelGame game) {
        this.x = x;
        this.y = y;
        this.game = game;
    }
    
    public void draw(Graphics g) {
        Color c = g.getColor();
        if(count == 3) {
            //播放完后将自己从主类容器中去掉
            game.getExplodes().remove(this);
        }
        g.drawImage(images[count ++], this.x - images[count ++].getWidth(null)/2 , this.y - images[count ++].getHeight(null)/2, 30, 30,  null);
        g.setColor(c);
    }
}

(5)方向枚举常量

package com.swing.plane;

/**
 * 定义飞机运动的方向
 * @author may
 *
 */
public enum Director {
    
    U, RU, R, RD, D , LD, L, LU, STOP;
 }

(6)图片加载辅助类

package com.swing.util;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;

public class ImageLoadUtil {
    private ImageLoadUtil() {}
    public static Image loadImage(String path) {
      BufferedImage image = null;
        try {
            image = ImageIO.read(ImageLoadUtil.class.getResource(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return image;
      }
    }