Java implements tank war 3.0

Articles and codes have been archived in [Github warehouse: https://github.com/timerring/java-tutorial] or the public account [AIShareLab] can also be obtained by replying to java .

IO Streams - Applied to Tank Wars

Tank Battle Version 0.5

add feature

  1. Prevent overlapping movement of enemy tanks
  2. Record the player's total score (the cumulative number of destroyed enemy tanks), save and exit [io flow]
  3. When Jiquan exits the game, the coordinates/direction of the enemy tank, save and exit [io flow]
  4. When playing a game, you can choose whether to open a new game or continue the previous game

package com.hspedu.tankgame5;

/**

 * 炸弹
 */
public class Bomb {
    
    
    int x, y; //炸弹的坐标
    int life = 9; //炸弹的生命周期
    boolean isLive = true; //是否还存活

    public Bomb(int x, int y) {
    
    
        this.x = x;
        this.y = y;
    }

    //减少生命值
    public void lifeDown() {
    
     //配合出现图片的爆炸效果
        if(life > 0) {
    
    
            life--;
        } else {
    
    
            isLive = false;
        }
    }
}
package com.hspedu.tankgame5;

import java.util.Vector;

/**
 * 敌人的坦克
 */
@SuppressWarnings({
    
    "all"})
public class EnemyTank extends Tank implements Runnable {
    
    
    //在敌人坦克类,使用Vector 保存多个Shot
    Vector<Shot> shots = new Vector<>();
    //增加成员,EnemyTank 可以得到敌人坦克的Vector
    //分析
    //1. Vector<EnemyTank> 在
    Vector<EnemyTank> enemyTanks = new Vector<>();
    boolean isLive = true;

    public EnemyTank(int x, int y) {
    
    
        super(x, y);
    }



    //这里提供一个方法,可以将MyPanel 的成员 Vector<EnemyTank> enemyTanks = new Vector<>();
    //设置到 EnemyTank 的成员 enemyTanks
    public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
    
    
        this.enemyTanks = enemyTanks;
    }

    //编写方法,判断当前的这个敌人坦克,是否和 enemyTanks 中的其他坦克发生的重叠或者碰撞
    public boolean isTouchEnemyTank() {
    
    

        //判断当前敌人坦克(this) 方向
        switch (this.getDirect()) {
    
    
            case 0: //上
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下
                        //
                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY()]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右上角的坐标 [this.getX() + 40, this.getY()]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左

                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY()]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右上角的坐标 [this.getX() + 40, this.getY()]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }

                }
                break;
            case 1: //右
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下

                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 右上角的坐标 [this.getX() + 60, this.getY()]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 60, this.getY() + 40]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 40
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左

                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 右上角的坐标 [this.getX() + 60, this.getY()]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 60, this.getY() + 40]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 60
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }
                }
                break;
            case 2: //下
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下

                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 60]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 40, this.getY() + 60]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 40
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左

                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 60]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 40, this.getY() + 60]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 60
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }
                }
                break;
            case 3: //左
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下

                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY() ]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 40]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左

                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY() ]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 40]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }
                }
                break;
        }
        return  false;
    }

    @Override
    public void run() {
    
    
        while (true) {
    
    

            //这里我们判断如果shots size() =0, 创建一颗子弹,放入到
            //shots集合,并启动
            if (isLive && shots.size() < 1) {
    
    
                Shot s = null;
                //判断坦克的方向,创建对应的子弹
                switch (getDirect()) {
    
    
                    case 0:
                        s = new Shot(getX() + 20, getY(), 0);
                        break;
                    case 1:
                        s = new Shot(getX() + 60, getY() + 20, 1);
                        break;
                    case 2: //向下
                        s = new Shot(getX() + 20, getY() + 60, 2);
                        break;
                    case 3://向左
                        s = new Shot(getX(), getY() + 20, 3);
                        break;
                }
                shots.add(s);
                //启动
                new Thread(s).start();

            }


            //根据坦克的方向来继续激动
            switch (getDirect()) {
    
    
                case 0:  //向上
                    //让坦克保持一个方向,走30步
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getY() > 0 && !isTouchEnemyTank()) {
    
    
                            moveUp();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1:  //向右
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getX() + 60 < 1000 && !isTouchEnemyTank()) {
    
    
                            moveRight();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2:  //向下
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getY() + 60 < 750 && !isTouchEnemyTank()) {
    
    
                            moveDown();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3:  //向左
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getX() > 0 && !isTouchEnemyTank()) {
    
    
                            moveLeft();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
            }


            //然后随机的改变坦克方向 0-3
            setDirect((int) (Math.random() * 4));
            //写并发程序,一定要考虑清楚,该线程什么时候结束
            if (!isLive) {
    
    
                break; //退出线程.
            }

        }
    }
}
package com.hspedu.tankgame5;

import java.util.Vector;

/**
 * 自己的坦克
 */
public class Hero extends Tank {
    
    
    //定义一个Shot对象, 表示一个射击(线程)
    Shot shot = null;
    //可以发射多颗子弹
    //Vector<Shot> shots = new Vector<>();
    public Hero(int x, int y) {
    
    
        super(x, y);
    }

    //射击
    public void shotEnemyTank() {
    
    

        //发多颗子弹怎么办, 控制在我们的面板上,最多只有5颗
//        if(shots.size() == 5) {
    
    
//            return;
//        }

        //创建 Shot 对象, 根据当前Hero对象的位置和方向来创建Shot
        switch (getDirect()) {
    
    //得到Hero对象方向
            case 0: //向上
                shot = new Shot(getX() + 20, getY(), 0);
                break;
            case 1: //向右
                shot = new Shot(getX() + 60, getY() + 20, 1);
                break;
            case 2: //向下
                shot = new Shot(getX() + 20, getY() + 60, 2);
                break;
            case 3: //向左
                shot = new Shot(getX(), getY() + 20, 3);
                break;
        }

        //把新创建的shot放入到shots
        //shots.add(shot);
        //启动我们的Shot线程
        new Thread(shot).start();

    }

}
package com.hspedu.tankgame5;

import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;

public class HspTankGame05 extends JFrame {
    
    

    // 定义MyPanel
    MyPanel mp = null;
    static Scanner scanner = new Scanner(System.in);
    public static void main(String[] args) {
    
    

        HspTankGame05 hspTankGame01 = new HspTankGame05();
    }

    public HspTankGame05() {
    
    
        System.out.println("请输入选择 1: 新游戏 2: 继续上局");
        String key = scanner.next();
        mp = new MyPanel(key);
        //将mp 放入到Thread ,并启动
        Thread thread = new Thread(mp);
        thread.start();
        this.add(mp);//把面板(就是游戏的绘图区域)

        this.setSize(1300, 950);
        this.addKeyListener(mp);//让JFrame 监听mp的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        //在JFrame 中增加相应关闭窗口的处理
        this.addWindowListener(new WindowAdapter() {
    
    
            @Override
            public void windowClosing(WindowEvent e) {
    
    
                Recorder.keepRecord();
                System.exit(0);
            }
        });
    }
}
package com.hspedu.tankgame5;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileInputStream;
import java.util.Vector;

/**
 * 坦克大战的绘图区域
 */

//为了监听 键盘事件, 实现KeyListener
//为了让Panel 不停的重绘子弹,需要将 MyPanel 实现Runnable ,当做一个线程使用
@SuppressWarnings({
    
    "all"})
public class MyPanel extends JPanel implements KeyListener, Runnable {
    
    
    //定义我的坦克
    Hero hero = null;
    //定义敌人坦克,放入到Vector
    Vector<EnemyTank> enemyTanks = new Vector<>();
    //定义一个存放Node 对象的Vector, 用于恢复敌人坦克的坐标和方向
    Vector<Node> nodes = new Vector<>();
    //定义一个Vector ,用于存放炸弹
    //说明,当子弹击中坦克时,加入一个Bomb对象到bombs
    Vector<Bomb> bombs = new Vector<>();
    int enemyTankSize = 3;

    //定义三张炸弹图片,用于显示爆炸效果
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    public MyPanel(String key) {
    
    
        nodes = Recorder.getNodesAndEnemyTankRec();
        //将MyPanel对象的 enemyTanks 设置给 Recorder 的 enemyTanks
        Recorder.setEnemyTanks(enemyTanks);

        hero = new Hero(500, 100);//初始化自己坦克

        switch (key) {
    
    
            case "1":
                //初始化敌人坦克
                for (int i = 0; i < enemyTankSize; i++) {
    
    
                    //创建一个敌人的坦克
                    EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
                    //将enemyTanks 设置给 enemyTank !!!
                    enemyTank.setEnemyTanks(enemyTanks);
                    //设置方向
                    enemyTank.setDirect(2);
                    //启动敌人坦克线程,让他动起来
                    new Thread(enemyTank).start();
                    //给该enemyTank 加入一颗子弹
                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
                    //加入enemyTank的Vector 成员
                    enemyTank.shots.add(shot);
                    //启动 shot 对象
                    new Thread(shot).start();
                    //加入
                    enemyTanks.add(enemyTank);
                }
                break;
            case "2": //继续上局游戏
                //初始化敌人坦克
                for (int i = 0; i < nodes.size(); i++) {
    
    
                    Node node = nodes.get(i);
                    //创建一个敌人的坦克
                    EnemyTank enemyTank = new EnemyTank(node.getX(), node.getY());
                    //将enemyTanks 设置给 enemyTank !!!
                    enemyTank.setEnemyTanks(enemyTanks);
                    //设置方向
                    enemyTank.setDirect(node.getDirect());
                    //启动敌人坦克线程,让他动起来
                    new Thread(enemyTank).start();
                    //给该enemyTank 加入一颗子弹
                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
                    //加入enemyTank的Vector 成员
                    enemyTank.shots.add(shot);
                    //启动 shot 对象
                    new Thread(shot).start();
                    //加入
                    enemyTanks.add(enemyTank);
                }
                break;
            default:
                System.out.println("你的输入有误...");
        }


        //初始化图片对象
        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
        image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));
        image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));


    }

    //编写方法,显示我方击毁敌方坦克的信息
    public void showInfo(Graphics g) {
    
    

        //画出玩家的总成绩
        g.setColor(Color.BLACK);
        Font font = new Font("宋体", Font.BOLD, 25);
        g.setFont(font);

        g.drawString("您累积击毁敌方坦克", 1020, 30);
        drawTank(1020, 60, g, 0, 0);//画出一个敌方坦克
        g.setColor(Color.BLACK);//这里需要重新设置成黑色
        g.drawString(Recorder.getAllEnemyTankNum() + "", 1080, 100);

    }

    @Override
    public void paint(Graphics g) {
    
    
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
        showInfo(g);
        if (hero != null && hero.isLive) {
    
    
            //画出自己坦克-封装方法
            drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
        }

        //画出hero射击的子弹
        if (hero.shot != null && hero.shot.isLive == true) {
    
    
            g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);

        }
        //将hero的子弹集合 shots ,遍历取出绘制
//        for(int i = 0; i < hero.shots.size(); i++) {
    
    
//            Shot shot = hero.shots.get(i);
//            if (shot != null && shot.isLive) {
    
    
//                g.draw3DRect(shot.x, shot.y, 1, 1, false);
//
//            } else {//如果该shot对象已经无效 ,就从shots集合中拿掉
//                hero.shots.remove(shot);
//            }
//        }

        //如果bombs 集合中有对象,就画出
        for (int i = 0; i < bombs.size(); i++) {
    
    
            //取出炸弹
            Bomb bomb = bombs.get(i);
            //根据当前这个bomb对象的life值去画出对应的图片
            if (bomb.life > 6) {
    
    
                g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);
            } else if (bomb.life > 3) {
    
    
                g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);
            } else {
    
    
                g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);
            }
            //让这个炸弹的生命值减少
            bomb.lifeDown();
            //如果bomb life 为0, 就从bombs 的集合中删除
            if (bomb.life == 0) {
    
    
                bombs.remove(bomb);
            }
        }

        //画出敌人的坦克, 遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
    
    
            //从Vector 取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //判断当前坦克是否还存活
            if (enemyTank.isLive) {
    
    //当敌人坦克是存活的,才画出该坦克
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
                //画出 enemyTank 所有子弹
                for (int j = 0; j < enemyTank.shots.size(); j++) {
    
    
                    //取出子弹
                    Shot shot = enemyTank.shots.get(j);
                    //绘制
                    if (shot.isLive) {
    
     //isLive == true
                        g.draw3DRect(shot.x, shot.y, 1, 1, false);
                    } else {
    
    
                        //从Vector 移除
                        enemyTank.shots.remove(shot);
                    }
                }
            }
        }


    }

    //编写方法,画出坦克

    /**
     * @param x      坦克的左上角x坐标
     * @param y      坦克的左上角y坐标
     * @param g      画笔
     * @param direct 坦克方向(上下左右)
     * @param type   坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int direct, int type) {
    
    

        //根据不同类型坦克,设置不同颜色
        switch (type) {
    
    
            case 0: //敌人的坦克
                g.setColor(Color.cyan);
                break;
            case 1: //我的坦克
                g.setColor(Color.yellow);
                break;
        }

        //根据坦克方向,来绘制对应形状坦克
        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )
        //
        switch (direct) {
    
    
            case 0: //表示向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒
                break;
            case 1: //表示向右
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒
                break;
            case 2: //表示向下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒
                break;
            case 3: //表示向左
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒
                break;
            default:
                System.out.println("暂时没有处理");
        }

    }

    //如果我们的坦克可以发射多个子弹
    //在判断我方子弹是否击中敌人坦克时,就需要把我们的子弹集合中
    //所有的子弹,都取出和敌人的所有坦克,进行判断
    //老韩给的部分代码..
    public void hitEnemyTank() {
    
    

//        //遍历我们的子弹
//        for(int j = 0;j < hero.shots.size();j++) {
    
    
//            Shot shot = hero.shots.get(j);
//            //判断是否击中了敌人坦克
//            if (shot != null && hero.shot.isLive) {//当我的子弹还存活
//
//                //遍历敌人所有的坦克
//                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
//                    EnemyTank enemyTank = enemyTanks.get(i);
//                    hitTank(hero.shot, enemyTank);
//                }
//
//            }
//        }

        //单颗子弹。
        if (hero.shot != null && hero.shot.isLive) {
    
    //当我的子弹还存活

            //遍历敌人所有的坦克
            for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                EnemyTank enemyTank = enemyTanks.get(i);
                hitTank(hero.shot, enemyTank);
            }

        }

    }

    //编写方法,判断敌人坦克是否击中我的坦克
    public void hitHero() {
    
    
        //遍历所有的敌人坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
    
    
            //取出敌人坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //遍历enemyTank 对象的所有子弹
            for (int j = 0; j < enemyTank.shots.size(); j++) {
    
    
                //取出子弹
                Shot shot = enemyTank.shots.get(j);
                //判断 shot 是否击中我的坦克
                if (hero.isLive && shot.isLive) {
    
    
                    hitTank(shot, hero);
                }
            }
        }
    }


    //编写方法,判断我方的子弹是否击中敌人坦克.
    //什么时候判断 我方的子弹是否击中敌人坦克 ? run方法
    //后面我们将 enemyTank 改成 tank名称
    public void hitTank(Shot s, Tank enemyTank) {
    
    
        //判断s 击中坦克
        switch (enemyTank.getDirect()) {
    
    
            case 0: //坦克向上
            case 2: //坦克向下
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 40
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {
    
    
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //当我的子弹击中敌人坦克后,将enemyTank 从Vector 拿掉
                    enemyTanks.remove(enemyTank);
                    //当我方击毁一个敌人坦克时,就对数据allEnemyTankNum++
                    //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank
                    if (enemyTank instanceof EnemyTank) {
    
    
                        Recorder.addAllEnemyTankNum();
                    }
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
            case 1: //坦克向右
            case 3: //坦克向左
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 60
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {
    
    
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //当我的子弹击中敌人坦克后,将enemyTank 从Vector 拿掉
                    enemyTanks.remove(enemyTank);
                    //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank
                    if (enemyTank instanceof EnemyTank) {
    
    
                        Recorder.addAllEnemyTankNum();
                    }
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    
    

    }

    //处理wdsa 键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
    
    
        System.out.println(e.getKeyCode());
        if (e.getKeyCode() == KeyEvent.VK_W) {
    
    //按下W键
            //改变坦克的方向
            hero.setDirect(0);//
            //修改坦克的坐标 y -= 1
            if (hero.getY() > 0) {
    
    
                hero.moveUp();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_D) {
    
    //D键, 向右
            hero.setDirect(1);
            if (hero.getX() + 60 < 1000) {
    
    
                hero.moveRight();
            }

        } else if (e.getKeyCode() == KeyEvent.VK_S) {
    
    //S键
            hero.setDirect(2);
            if (hero.getY() + 60 < 750) {
    
    
                hero.moveDown();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
    
    //A键
            hero.setDirect(3);
            if (hero.getX() > 0) {
    
    
                hero.moveLeft();
            }
        }

        //如果用户按下的是J,就发射
        if (e.getKeyCode() == KeyEvent.VK_J) {
    
    

            //判断hero的子弹是否销毁,发射一颗子弹
            if (hero.shot == null || !hero.shot.isLive) {
    
    
                hero.shotEnemyTank();
            }
            //发射多颗子弹
            //hero.shotEnemyTank();

        }
        //让面板重绘
        this.repaint();

    }

    @Override
    public void keyReleased(KeyEvent e) {
    
    

    }

    @Override
    public void run() {
    
     //每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹就移动

        while (true) {
    
    
            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //判断是我们子弹否击中了敌人坦克
            hitEnemyTank();
            //判断敌人坦克是否击中我们
            hitHero();
            this.repaint();
        }

    }
}
package com.hspedu.tankgame5;

/**
 * 一个Node 对象,表示一个敌人坦克的信息
 */
public class Node {
    
    
    private int x;
    private int y;
    private int direct;

    public Node(int x, int y, int direct) {
    
    
        this.x = x;
        this.y = y;
        this.direct = direct;
    }

    public int getX() {
    
    
        return x;
    }

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

    public int getY() {
    
    
        return y;
    }

    public void setY(int y) {
    
    
        this.y = y;
    }

    public int getDirect() {
    
    
        return direct;
    }

    public void setDirect(int direct) {
    
    
        this.direct = direct;
    }
}
package com.hspedu.tankgame5;

import java.io.*;
import java.nio.Buffer;
import java.util.Vector;

/**
 * 该类用于记录相关信息的.和文件交互
 */
@SuppressWarnings({
    
    "all"})
public class Recorder {
    
    

    //定义变量,记录我方击毁敌人坦克数
    private static int allEnemyTankNum = 0;
    //定义IO对象, 准备写数据到文件中
    private static BufferedWriter bw = null;
    private static BufferedReader br = null;
    private static String recordFile = "e:\\myRecord.txt";
    //定义Vector ,指向 MyPanel 对象的 敌人坦克Vector
    private static Vector<EnemyTank> enemyTanks = null;
    //定义一个Node 的Vector ,用于保存敌人的信息node
    private static Vector<Node> nodes = new Vector<>();

    public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
    
    
        Recorder.enemyTanks = enemyTanks;
    }

    public static String getRecordFile() {
    
    
        return recordFile;
    }

    //增加一个方法,用于读取recordFile, 恢复相关信息
    //该方法,在继续上局的时候调用即可
    public static Vector<Node> getNodesAndEnemyTankRec() {
    
    

        try {
    
    

            br = new BufferedReader(new FileReader(recordFile));
            allEnemyTankNum = Integer.parseInt(br.readLine());
            //循环读取文件,生成nodes 集合
            String line = "";//255 40 0
            while ((line = br.readLine()) != null) {
    
    
                String[] xyd = line.split(" ");
                Node node = new Node(Integer.parseInt(xyd[0]), Integer.parseInt(xyd[1]),
                        Integer.parseInt(xyd[2]));
                nodes.add(node); //放入nodes Vector
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (br != null) {
    
    
                    br.close();
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }

        return nodes;
    }


    //增加一个方法,当游戏退出时,我们将allEnemyTankNum 保存到 recordFile
    //对keepRecord 进行升级, 保存敌人坦克的坐标和方向

    public static void keepRecord() {
    
    
        try {
    
    
            bw = new BufferedWriter(new FileWriter(recordFile));
            bw.write(allEnemyTankNum + "\r\n");
            //遍历敌人坦克的Vector ,然后根据情况保存即可.
            //OOP, 定义一个属性 ,然后通过setXxx得到 敌人坦克的Vector
            for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                //取出敌人坦克
                EnemyTank enemyTank = enemyTanks.get(i);
                if (enemyTank.isLive) {
    
     //建议判断.
                    //保存该enemyTank信息
                    String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirect();
                    //写入到文件
                    bw.write(record + "\r\n");
                }
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (bw != null) {
    
    
                    bw.close();
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public static int getAllEnemyTankNum() {
    
    
        return allEnemyTankNum;
    }

    public static void setAllEnemyTankNum(int allEnemyTankNum) {
    
    
        Recorder.allEnemyTankNum = allEnemyTankNum;
    }

    //当我方坦克击毁一个敌人坦克,就应当 allEnemyTankNum++
    public static void addAllEnemyTankNum() {
    
    
        Recorder.allEnemyTankNum++;
    }
}
package com.hspedu.tankgame5;

/**
 * 射击子弹
 */
public class Shot implements Runnable {
    
    
    int x; //子弹x坐标
    int y; //子弹y坐标
    int direct = 0; //子弹方向
    int speed = 2; //子弹的速度
    boolean isLive = true; //子弹是否还存活

    //构造器
    public Shot(int x, int y, int direct) {
    
    
        this.x = x;
        this.y = y;
        this.direct = direct;
    }

    @Override
    public void run() {
    
    //射击
        while (true) {
    
    

            //休眠 50毫秒
            try {
    
    
                Thread.sleep(50);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //根据方向来改变x,y坐标
            switch (direct) {
    
    
                case 0://上
                    y -= speed;
                    break;
                case 1://右
                    x += speed;
                    break;
                case 2://下
                    y += speed;
                    break;
                case 3://左
                    x -= speed;
                    break;
            }
            //老师测试,这里我们输出x,y的坐标
            System.out.println("子弹 x=" + x + " y=" + y);
            //当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)
            //当子弹碰到敌人坦克时,也应该结束线程
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {
    
    
                System.out.println("子弹线程退出");
                isLive = false;
                break;
            }

        }
    }
}
package com.hspedu.tankgame5;

public class Tank {
    
    
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标
    private int direct = 0;//坦克方向 0 上1 右 2下 3左
    private int speed = 1;
    boolean isLive = true;
    public int getSpeed() {
    
    
        return speed;
    }

    public void setSpeed(int speed) {
    
    
        this.speed = speed;
    }

    //上右下左移动方法
    public void moveUp() {
    
    
        y -= speed;
    }
    public void moveRight() {
    
    
        x += speed;
    }
    public void moveDown() {
    
    
        y += speed;
    }
    public void moveLeft() {
    
    
        x -= speed;
    }

    public int getDirect() {
    
    
        return direct;
    }

    public void setDirect(int direct) {
    
    
        this.direct = direct;
    }

    public Tank(int x, int y) {
    
    
        this.x = x;
        this.y = y;
    }

    public int getX() {
    
    
        return x;
    }

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

    public int getY() {
    
    
        return y;
    }

    public void setY(int y) {
    
    
        this.y = y;
    }
}

Tank Battle Version 0.6

add feature

  1. When the game starts, play the classic tank battle music, [idea, use a class that plays music, you can]
  2. Correct the file storage location
  3. Handle file-related exceptions = "prompt code robustness
package com.hspedu.tankgame6;

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;

public class AePlayWave extends Thread {
    
    
    private String filename;

    public AePlayWave(String wavfile) {
    
     //构造器 , 指定文件
        filename = wavfile;

    }

    public void run() {
    
    

        File soundFile = new File(filename);

        AudioInputStream audioInputStream = null;
        try {
    
    
            audioInputStream = AudioSystem.getAudioInputStream(soundFile);
        } catch (Exception e1) {
    
    
            e1.printStackTrace();
            return;
        }

        AudioFormat format = audioInputStream.getFormat();
        SourceDataLine auline = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        try {
    
    
            auline = (SourceDataLine) AudioSystem.getLine(info);
            auline.open(format);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return;
        }

        auline.start();
        int nBytesRead = 0;
        //这是缓冲
        byte[] abData = new byte[512];

        try {
    
    
            while (nBytesRead != -1) {
    
    
                nBytesRead = audioInputStream.read(abData, 0, abData.length);
                if (nBytesRead >= 0)
                    auline.write(abData, 0, nBytesRead);
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
            return;
        } finally {
    
    
            auline.drain();
            auline.close();
        }

    }
}
package com.hspedu.tankgame6;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Vector;

/**
 * 坦克大战的绘图区域
 */

//为了监听 键盘事件, 实现KeyListener
//为了让Panel 不停的重绘子弹,需要将 MyPanel 实现Runnable ,当做一个线程使用
@SuppressWarnings({
    
    "all"})
public class MyPanel extends JPanel implements KeyListener, Runnable {
    
    
    //定义我的坦克
    Hero hero = null;
    //定义敌人坦克,放入到Vector
    Vector<EnemyTank> enemyTanks = new Vector<>();
    //定义一个存放Node 对象的Vector, 用于恢复敌人坦克的坐标和方向
    Vector<Node> nodes = new Vector<>();
    //定义一个Vector ,用于存放炸弹
    //说明,当子弹击中坦克时,加入一个Bomb对象到bombs
    Vector<Bomb> bombs = new Vector<>();
    int enemyTankSize = 3;

    //定义三张炸弹图片,用于显示爆炸效果
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    public MyPanel(String key) {
    
    
        //先判断记录的文件是否存在
        //如果存在,就正常执行,如果文件不存在,提示,只能开启新游戏,key = "1"
        File file = new File(Recorder.getRecordFile());
        if (file.exists()) {
    
    
            nodes = Recorder.getNodesAndEnemyTankRec();
        } else {
    
    
            System.out.println("文件不存在,只能开启新的游戏");
            key = "1";
        }
        //将MyPanel对象的 enemyTanks 设置给 Recorder 的 enemyTanks
        Recorder.setEnemyTanks(enemyTanks);

        hero = new Hero(500, 100);//初始化自己坦克

        switch (key) {
    
    
            case "1":
                //初始化敌人坦克
                for (int i = 0; i < enemyTankSize; i++) {
    
    
                    //创建一个敌人的坦克
                    EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
                    //将enemyTanks 设置给 enemyTank !!!
                    enemyTank.setEnemyTanks(enemyTanks);
                    //设置方向
                    enemyTank.setDirect(2);
                    //启动敌人坦克线程,让他动起来
                    new Thread(enemyTank).start();
                    //给该enemyTank 加入一颗子弹
                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
                    //加入enemyTank的Vector 成员
                    enemyTank.shots.add(shot);
                    //启动 shot 对象
                    new Thread(shot).start();
                    //加入
                    enemyTanks.add(enemyTank);
                }
                break;
            case "2": //继续上局游戏
                //初始化敌人坦克
                for (int i = 0; i < nodes.size(); i++) {
    
    
                    Node node = nodes.get(i);
                    //创建一个敌人的坦克
                    EnemyTank enemyTank = new EnemyTank(node.getX(), node.getY());
                    //将enemyTanks 设置给 enemyTank !!!
                    enemyTank.setEnemyTanks(enemyTanks);
                    //设置方向
                    enemyTank.setDirect(node.getDirect());
                    //启动敌人坦克线程,让他动起来
                    new Thread(enemyTank).start();
                    //给该enemyTank 加入一颗子弹
                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
                    //加入enemyTank的Vector 成员
                    enemyTank.shots.add(shot);
                    //启动 shot 对象
                    new Thread(shot).start();
                    //加入
                    enemyTanks.add(enemyTank);
                }
                break;
            default:
                System.out.println("你的输入有误...");
        }


        //初始化图片对象
        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
        image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));
        image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));

        //这里,播放指定的音乐
        new AePlayWave("src\\111.wav").start();

    }

    //编写方法,显示我方击毁敌方坦克的信息
    public void showInfo(Graphics g) {
    
    

        //画出玩家的总成绩
        g.setColor(Color.BLACK);
        Font font = new Font("宋体", Font.BOLD, 25);
        g.setFont(font);

        g.drawString("您累积击毁敌方坦克", 1020, 30);
        drawTank(1020, 60, g, 0, 0);//画出一个敌方坦克
        g.setColor(Color.BLACK);//这里需要重新设置成黑色
        g.drawString(Recorder.getAllEnemyTankNum() + "", 1080, 100);

    }

    @Override
    public void paint(Graphics g) {
    
    
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
        showInfo(g);
        if (hero != null && hero.isLive) {
    
    
            //画出自己坦克-封装方法
            drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
        }

        //画出hero射击的子弹
        if (hero.shot != null && hero.shot.isLive == true) {
    
    
            g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);

        }
        //将hero的子弹集合 shots ,遍历取出绘制
//        for(int i = 0; i < hero.shots.size(); i++) {
    
    
//            Shot shot = hero.shots.get(i);
//            if (shot != null && shot.isLive) {
    
    
//                g.draw3DRect(shot.x, shot.y, 1, 1, false);
//
//            } else {//如果该shot对象已经无效 ,就从shots集合中拿掉
//                hero.shots.remove(shot);
//            }
//        }

        //如果bombs 集合中有对象,就画出
        for (int i = 0; i < bombs.size(); i++) {
    
    
            //取出炸弹
            Bomb bomb = bombs.get(i);
            //根据当前这个bomb对象的life值去画出对应的图片
            if (bomb.life > 6) {
    
    
                g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);
            } else if (bomb.life > 3) {
    
    
                g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);
            } else {
    
    
                g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);
            }
            //让这个炸弹的生命值减少
            bomb.lifeDown();
            //如果bomb life 为0, 就从bombs 的集合中删除
            if (bomb.life == 0) {
    
    
                bombs.remove(bomb);
            }
        }

        //画出敌人的坦克, 遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
    
    
            //从Vector 取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //判断当前坦克是否还存活
            if (enemyTank.isLive) {
    
    //当敌人坦克是存活的,才画出该坦克
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
                //画出 enemyTank 所有子弹
                for (int j = 0; j < enemyTank.shots.size(); j++) {
    
    
                    //取出子弹
                    Shot shot = enemyTank.shots.get(j);
                    //绘制
                    if (shot.isLive) {
    
     //isLive == true
                        g.draw3DRect(shot.x, shot.y, 1, 1, false);
                    } else {
    
    
                        //从Vector 移除
                        enemyTank.shots.remove(shot);
                    }
                }
            }
        }


    }

    //编写方法,画出坦克

    /**
     * @param x      坦克的左上角x坐标
     * @param y      坦克的左上角y坐标
     * @param g      画笔
     * @param direct 坦克方向(上下左右)
     * @param type   坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int direct, int type) {
    
    

        //根据不同类型坦克,设置不同颜色
        switch (type) {
    
    
            case 0: //敌人的坦克
                g.setColor(Color.cyan);
                break;
            case 1: //我的坦克
                g.setColor(Color.yellow);
                break;
        }

        //根据坦克方向,来绘制对应形状坦克
        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )
        //
        switch (direct) {
    
    
            case 0: //表示向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒
                break;
            case 1: //表示向右
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒
                break;
            case 2: //表示向下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒
                break;
            case 3: //表示向左
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒
                break;
            default:
                System.out.println("暂时没有处理");
        }

    }

    //如果我们的坦克可以发射多个子弹
    //在判断我方子弹是否击中敌人坦克时,就需要把我们的子弹集合中
    //所有的子弹,都取出和敌人的所有坦克,进行判断
    //老韩给的部分代码..
    public void hitEnemyTank() {
    
    

//        //遍历我们的子弹
//        for(int j = 0;j < hero.shots.size();j++) {
    
    
//            Shot shot = hero.shots.get(j);
//            //判断是否击中了敌人坦克
//            if (shot != null && hero.shot.isLive) {//当我的子弹还存活
//
//                //遍历敌人所有的坦克
//                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
//                    EnemyTank enemyTank = enemyTanks.get(i);
//                    hitTank(hero.shot, enemyTank);
//                }
//
//            }
//        }

        //单颗子弹。
        if (hero.shot != null && hero.shot.isLive) {
    
    //当我的子弹还存活

            //遍历敌人所有的坦克
            for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                EnemyTank enemyTank = enemyTanks.get(i);
                hitTank(hero.shot, enemyTank);
            }

        }

    }

    //编写方法,判断敌人坦克是否击中我的坦克
    public void hitHero() {
    
    
        //遍历所有的敌人坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
    
    
            //取出敌人坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //遍历enemyTank 对象的所有子弹
            for (int j = 0; j < enemyTank.shots.size(); j++) {
    
    
                //取出子弹
                Shot shot = enemyTank.shots.get(j);
                //判断 shot 是否击中我的坦克
                if (hero.isLive && shot.isLive) {
    
    
                    hitTank(shot, hero);
                }
            }
        }
    }


    //编写方法,判断我方的子弹是否击中敌人坦克.
    //什么时候判断 我方的子弹是否击中敌人坦克 ? run方法
    //后面我们将 enemyTank 改成 tank名称
    public void hitTank(Shot s, Tank enemyTank) {
    
    
        //判断s 击中坦克
        switch (enemyTank.getDirect()) {
    
    
            case 0: //坦克向上
            case 2: //坦克向下
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 40
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {
    
    
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //当我的子弹击中敌人坦克后,将enemyTank 从Vector 拿掉
                    enemyTanks.remove(enemyTank);
                    //当我方击毁一个敌人坦克时,就对数据allEnemyTankNum++
                    //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank
                    if (enemyTank instanceof EnemyTank) {
    
    
                        Recorder.addAllEnemyTankNum();
                    }
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
            case 1: //坦克向右
            case 3: //坦克向左
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 60
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {
    
    
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //当我的子弹击中敌人坦克后,将enemyTank 从Vector 拿掉
                    enemyTanks.remove(enemyTank);
                    //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank
                    if (enemyTank instanceof EnemyTank) {
    
    
                        Recorder.addAllEnemyTankNum();
                    }
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    
    

    }

    //处理wdsa 键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
    
    
        System.out.println(e.getKeyCode());
        if (e.getKeyCode() == KeyEvent.VK_W) {
    
    //按下W键
            //改变坦克的方向
            hero.setDirect(0);//
            //修改坦克的坐标 y -= 1
            if (hero.getY() > 0) {
    
    
                hero.moveUp();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_D) {
    
    //D键, 向右
            hero.setDirect(1);
            if (hero.getX() + 60 < 1000) {
    
    
                hero.moveRight();
            }

        } else if (e.getKeyCode() == KeyEvent.VK_S) {
    
    //S键
            hero.setDirect(2);
            if (hero.getY() + 60 < 750) {
    
    
                hero.moveDown();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
    
    //A键
            hero.setDirect(3);
            if (hero.getX() > 0) {
    
    
                hero.moveLeft();
            }
        }

        //如果用户按下的是J,就发射
        if (e.getKeyCode() == KeyEvent.VK_J) {
    
    

            //判断hero的子弹是否销毁,发射一颗子弹
            if (hero.shot == null || !hero.shot.isLive) {
    
    
                hero.shotEnemyTank();
            }
            //发射多颗子弹
            //hero.shotEnemyTank();

        }
        //让面板重绘
        this.repaint();

    }

    @Override
    public void keyReleased(KeyEvent e) {
    
    

    }

    @Override
    public void run() {
    
     //每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹就移动

        while (true) {
    
    
            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //判断是我们子弹否击中了敌人坦克
            hitEnemyTank();
            //判断敌人坦克是否击中我们
            hitHero();
            this.repaint();
        }

    }
}
package com.hspedu.tankgame5;

import java.io.*;
import java.nio.Buffer;
import java.util.Vector;

/**
 * 该类用于记录相关信息的.和文件交互
 */
@SuppressWarnings({
    
    "all"})
public class Recorder {
    
    

    //定义变量,记录我方击毁敌人坦克数
    private static int allEnemyTankNum = 0;
    //定义IO对象, 准备写数据到文件中
    private static BufferedWriter bw = null;
    private static BufferedReader br = null;
    private static String recordFile = "e:\\myRecord.txt";
    //定义Vector ,指向 MyPanel 对象的 敌人坦克Vector
    private static Vector<EnemyTank> enemyTanks = null;
    //定义一个Node 的Vector ,用于保存敌人的信息node
    private static Vector<Node> nodes = new Vector<>();

    public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
    
    
        Recorder.enemyTanks = enemyTanks;
    }

    public static String getRecordFile() {
    
    
        return recordFile;
    }

    //增加一个方法,用于读取recordFile, 恢复相关信息
    //该方法,在继续上局的时候调用即可
    public static Vector<Node> getNodesAndEnemyTankRec() {
    
    

        try {
    
    

            br = new BufferedReader(new FileReader(recordFile));
            allEnemyTankNum = Integer.parseInt(br.readLine());
            //循环读取文件,生成nodes 集合
            String line = "";//255 40 0
            while ((line = br.readLine()) != null) {
    
    
                String[] xyd = line.split(" ");
                Node node = new Node(Integer.parseInt(xyd[0]), Integer.parseInt(xyd[1]),
                        Integer.parseInt(xyd[2]));
                nodes.add(node); //放入nodes Vector
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (br != null) {
    
    
                    br.close();
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }

        return nodes;
    }


    //增加一个方法,当游戏退出时,我们将allEnemyTankNum 保存到 recordFile
    //对keepRecord 进行升级, 保存敌人坦克的坐标和方向

    public static void keepRecord() {
    
    
        try {
    
    
            bw = new BufferedWriter(new FileWriter(recordFile));
            bw.write(allEnemyTankNum + "\r\n");
            //遍历敌人坦克的Vector ,然后根据情况保存即可.
            //OOP, 定义一个属性 ,然后通过setXxx得到 敌人坦克的Vector
            for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                //取出敌人坦克
                EnemyTank enemyTank = enemyTanks.get(i);
                if (enemyTank.isLive) {
    
     //建议判断.
                    //保存该enemyTank信息
                    String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirect();
                    //写入到文件
                    bw.write(record + "\r\n");
                }
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (bw != null) {
    
    
                    bw.close();
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public static int getAllEnemyTankNum() {
    
    
        return allEnemyTankNum;
    }

    public static void setAllEnemyTankNum(int allEnemyTankNum) {
    
    
        Recorder.allEnemyTankNum = allEnemyTankNum;
    }

    //当我方坦克击毁一个敌人坦克,就应当 allEnemyTankNum++
    public static void addAllEnemyTankNum() {
    
    
        Recorder.allEnemyTankNum++;
    }
}
package com.hspedu.tankgame6;

/**
 * 炸弹
 */
public class Bomb {
    
    
    int x, y; //炸弹的坐标
    int life = 9; //炸弹的生命周期
    boolean isLive = true; //是否还存活

    public Bomb(int x, int y) {
    
    
        this.x = x;
        this.y = y;
    }

    //减少生命值
    public void lifeDown() {
    
     //配合出现图片的爆炸效果
        if(life > 0) {
    
    
            life--;
        } else {
    
    
            isLive = false;
        }
    }
}
package com.hspedu.tankgame6;

import java.util.Vector;

/**
 * 敌人的坦克
 */
@SuppressWarnings({
    
    "all"})
public class EnemyTank extends Tank implements Runnable {
    
    
    //在敌人坦克类,使用Vector 保存多个Shot
    Vector<Shot> shots = new Vector<>();
    //增加成员,EnemyTank 可以得到敌人坦克的Vector
    //分析
    //1. Vector<EnemyTank> 在
    Vector<EnemyTank> enemyTanks = new Vector<>();
    boolean isLive = true;

    public EnemyTank(int x, int y) {
    
    
        super(x, y);
    }



    //这里提供一个方法,可以将MyPanel 的成员 Vector<EnemyTank> enemyTanks = new Vector<>();
    //设置到 EnemyTank 的成员 enemyTanks
    public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
    
    
        this.enemyTanks = enemyTanks;
    }

    //编写方法,判断当前的这个敌人坦克,是否和 enemyTanks 中的其他坦克发生的重叠或者碰撞
    public boolean isTouchEnemyTank() {
    
    

        //判断当前敌人坦克(this) 方向
        switch (this.getDirect()) {
    
    
            case 0: //上
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下
                        //老韩分析
                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY()]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右上角的坐标 [this.getX() + 40, this.getY()]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左
                        //老韩分析
                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY()]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右上角的坐标 [this.getX() + 40, this.getY()]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }

                }
                break;
            case 1: //右
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下
                        //老韩分析
                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 右上角的坐标 [this.getX() + 60, this.getY()]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 60, this.getY() + 40]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 40
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左
                        //老韩分析
                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 右上角的坐标 [this.getX() + 60, this.getY()]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 60, this.getY() + 40]
                            if (this.getX() + 60 >= enemyTank.getX()
                                    && this.getX() + 60 <= enemyTank.getX() + 60
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }
                }
                break;
            case 2: //下
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下
                        //老韩分析
                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 60]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 40, this.getY() + 60]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 40
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左
                        //老韩分析
                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 60]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 右下角的坐标 [this.getX() + 40, this.getY() + 60]
                            if (this.getX() + 40 >= enemyTank.getX()
                                    && this.getX() + 40 <= enemyTank.getX() + 60
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }
                }
                break;
            case 3: //左
                //让当前敌人坦克和其它所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
    
    
                    //从vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
    
    
                        //如果敌人坦克是上/下
                        //老韩分析
                        //1. 如果敌人坦克是上/下 x的范围 [enemyTank.getX(), enemyTank.getX() + 40]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 60]

                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY() ]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                            //3. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 40]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 40
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 60) {
    
    
                                return true;
                            }
                        }
                        //如果敌人坦克是 右/左
                        //老韩分析
                        //1. 如果敌人坦克是右/左  x的范围 [enemyTank.getX(), enemyTank.getX() + 60]
                        //                     y的范围 [enemyTank.getY(), enemyTank.getY() + 40]
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
    
    
                            //2. 当前坦克 左上角的坐标 [this.getX(), this.getY() ]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                            //3. 当前坦克 左下角的坐标 [this.getX(), this.getY() + 40]
                            if (this.getX() >= enemyTank.getX()
                                    && this.getX() <= enemyTank.getX() + 60
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 40) {
    
    
                                return true;
                            }
                        }
                    }
                }
                break;
        }
        return  false;
    }

    @Override
    public void run() {
    
    
        while (true) {
    
    

            //这里我们判断如果shots size() =0, 创建一颗子弹,放入到
            //shots集合,并启动
            if (isLive && shots.size() < 1) {
    
    
                Shot s = null;
                //判断坦克的方向,创建对应的子弹
                switch (getDirect()) {
    
    
                    case 0:
                        s = new Shot(getX() + 20, getY(), 0);
                        break;
                    case 1:
                        s = new Shot(getX() + 60, getY() + 20, 1);
                        break;
                    case 2: //向下
                        s = new Shot(getX() + 20, getY() + 60, 2);
                        break;
                    case 3://向左
                        s = new Shot(getX(), getY() + 20, 3);
                        break;
                }
                shots.add(s);
                //启动
                new Thread(s).start();

            }


            //根据坦克的方向来继续激动
            switch (getDirect()) {
    
    
                case 0:  //向上
                    //让坦克保持一个方向,走30步
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getY() > 0 && !isTouchEnemyTank()) {
    
    
                            moveUp();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1:  //向右
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getX() + 60 < 1000 && !isTouchEnemyTank()) {
    
    
                            moveRight();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2:  //向下
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getY() + 60 < 750 && !isTouchEnemyTank()) {
    
    
                            moveDown();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3:  //向左
                    for (int i = 0; i < 30; i++) {
    
    
                        if (getX() > 0 && !isTouchEnemyTank()) {
    
    
                            moveLeft();
                        }
                        //休眠50毫秒
                        try {
    
    
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    break;
            }


            //然后随机的改变坦克方向 0-3
            setDirect((int) (Math.random() * 4));
            //听老韩说,写并发程序,一定要考虑清楚,该线程什么时候结束
            if (!isLive) {
    
    
                break; //退出线程.
            }

        }
    }
}
package com.hspedu.tankgame6;

/**
 * 自己的坦克
 */
public class Hero extends Tank {
    
    
    //定义一个Shot对象, 表示一个射击(线程)
    Shot shot = null;
    //可以发射多颗子弹
    //Vector<Shot> shots = new Vector<>();
    public Hero(int x, int y) {
    
    
        super(x, y);
    }

    //射击
    public void shotEnemyTank() {
    
    

        //发多颗子弹怎么办, 控制在我们的面板上,最多只有5颗
//        if(shots.size() == 5) {
    
    
//            return;
//        }

        //创建 Shot 对象, 根据当前Hero对象的位置和方向来创建Shot
        switch (getDirect()) {
    
    //得到Hero对象方向
            case 0: //向上
                shot = new Shot(getX() + 20, getY(), 0);
                break;
            case 1: //向右
                shot = new Shot(getX() + 60, getY() + 20, 1);
                break;
            case 2: //向下
                shot = new Shot(getX() + 20, getY() + 60, 2);
                break;
            case 3: //向左
                shot = new Shot(getX(), getY() + 20, 3);
                break;
        }

        //把新创建的shot放入到shots
        //shots.add(shot);
        //启动我们的Shot线程
        new Thread(shot).start();

    }

}
package com.hspedu.tankgame6;

import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;

public class HspTankGame06 extends JFrame {
    
    

    //定义MyPanel
    MyPanel mp = null;
    static Scanner scanner = new Scanner(System.in);
    public static void main(String[] args) {
    
    

        HspTankGame06 hspTankGame01 = new HspTankGame06();
    }

    public HspTankGame06() {
    
    
        System.out.println("请输入选择 1: 新游戏 2: 继续上局");
        String key = scanner.next();
        mp = new MyPanel(key);
        //将mp 放入到Thread ,并启动
        Thread thread = new Thread(mp);
        thread.start();
        this.add(mp);//把面板(就是游戏的绘图区域)

        this.setSize(1300, 950);
        this.addKeyListener(mp);//让JFrame 监听mp的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        //在JFrame 中增加相应关闭窗口的处理
        this.addWindowListener(new WindowAdapter() {
    
    
            @Override
            public void windowClosing(WindowEvent e) {
    
    
                Recorder.keepRecord();
                System.exit(0);
            }
        });
    }
}
package com.hspedu.tankgame6;

/**
 * 一个Node 对象,表示一个敌人坦克的信息
 */
public class Node {
    
    
    private int x;
    private int y;
    private int direct;

    public Node(int x, int y, int direct) {
    
    
        this.x = x;
        this.y = y;
        this.direct = direct;
    }

    public int getX() {
    
    
        return x;
    }

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

    public int getY() {
    
    
        return y;
    }

    public void setY(int y) {
    
    
        this.y = y;
    }

    public int getDirect() {
    
    
        return direct;
    }

    public void setDirect(int direct) {
    
    
        this.direct = direct;
    }
}
package com.hspedu.tankgame6;

/**
 * 射击子弹
 */
public class Shot implements Runnable {
    
    
    int x; //子弹x坐标
    int y; //子弹y坐标
    int direct = 0; //子弹方向
    int speed = 2; //子弹的速度
    boolean isLive = true; //子弹是否还存活

    //构造器
    public Shot(int x, int y, int direct) {
    
    
        this.x = x;
        this.y = y;
        this.direct = direct;
    }

    @Override
    public void run() {
    
    //射击
        while (true) {
    
    

            //休眠 50毫秒
            try {
    
    
                Thread.sleep(50);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //根据方向来改变x,y坐标
            switch (direct) {
    
    
                case 0://上
                    y -= speed;
                    break;
                case 1://右
                    x += speed;
                    break;
                case 2://下
                    y += speed;
                    break;
                case 3://左
                    x -= speed;
                    break;
            }
            //老师测试,这里我们输出x,y的坐标
            //System.out.println("子弹 x=" + x + " y=" + y);
            //当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)
            //当子弹碰到敌人坦克时,也应该结束线程
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {
    
    
                System.out.println("子弹线程退出");
                isLive = false;
                break;
            }

        }
    }
}
package com.hspedu.tankgame6;

public class Tank {
    
    
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标
    private int direct = 0;//坦克方向 0 上1 右 2下 3左
    private int speed = 1;
    boolean isLive = true;
    public int getSpeed() {
    
    
        return speed;
    }

    public void setSpeed(int speed) {
    
    
        this.speed = speed;
    }

    //上右下左移动方法
    public void moveUp() {
    
    
        y -= speed;
    }
    public void moveRight() {
    
    
        x += speed;
    }
    public void moveDown() {
    
    
        y += speed;
    }
    public void moveLeft() {
    
    
        x -= speed;
    }

    public int getDirect() {
    
    
        return direct;
    }

    public void setDirect(int direct) {
    
    
        this.direct = direct;
    }

    public Tank(int x, int y) {
    
    
        this.x = x;
        this.y = y;
    }

    public int getX() {
    
    
        return x;
    }

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

    public int getY() {
    
    
        return y;
    }

    public void setY(int y) {
    
    
        this.y = y;
    }
}

Guess you like

Origin blog.csdn.net/m0_52316372/article/details/130565498