当前位置: 首页 > 图灵资讯 > 技术篇> IO流应用到坦克大战(坦克大战4.0)

IO流应用到坦克大战(坦克大战4.0)

来源:图灵教育
时间:2023-05-23 09:34:55

1.08版坦克大战1.1增加功能654

1.游戏开始时,播放经典坦克大战音乐,[思考,使用播放音乐的类别]654

2.修正下文件的存储位置6544

3.处理文件相关异常=提示代码的健壮性654

com中的代码.stulzl.tankgame08.包中测试Tankgame08
package com.stulzl.tankgame08;import javax.swing.*;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.util.Scanner;//主方法  572public class Tankgame08 extends JFrame {    ///定义我们的MyPanel    MyPanel mp = null;    static Scanner scanner = new Scanner(System.in);    public static void main(String[] args) {        Tankgame08 tankgame0 = new Tankgame08();//调用显示结果    }    /////构造设置窗口信息    public Tankgame08(){        System.out.println(”请输入选择 1:新游戏 2:继续玩游戏”);        String key = scanner.next();        mp = new MyPanel(key);//初始化面板,这个key是将用户选择传输到MyPanel进行判断和选择        ///将mp放入Thread 并启动        Thread thread = new Thread(mp);        thread.start();///启动MyPanel线程        this.add(mp);///将面板添加到窗口        this.setSize(1300,950);//设置窗口大小        this.addKeyListener(mp);///让JFrame监控mp        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭程序        this.setVisible(true);//显示窗口        ///在JFrame中添加监控关闭窗口处理的相应方法  650        this.addWindowListener(new WindowAdapter() {            @Override            public void windowClosing(WindowEvent e) {                Recorder.keepRecord();////调用保存记录方法                System.exit(0);///这种System的方法不用纠结,可以理解,成就是关闭左右            }        });    }}
Tank,父类坦克
package com.stulzl.tankgame08;public class Tank {//父类坦克    private int x;///坦克的横坐标    private int y;///坦克纵坐标    private int direct;//在坦克方向0上 1右 2下 3左   577    private int speed = 1;//控制坦克速度    boolean isLive = true;////我们坦克生存标志    ///在坦克上右下左移动  577    public void moveUp(){//向上移动        y-=speed;    }    public void moveRight(){//向右移动        x+=speed;    }    public void moveDown(){//向下移动        y+=speed;    }    public void moveLeft(){//左移动        x-=speed;    }    public int getSpeed() {        return speed;    }    public void setSpeed(int speed) {        this.speed = 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;    }}
我们的坦克Hero
package com.stulzl.tankgame08;import java.util.Vector;public class Hero extends Tank {///我们的坦克,设置坦克坐标,打开Shot射击线程    ///我们的坦克生存标志islive直接写在父类中,方便    ///定义Shot对象,表示射击(线程)    Shot shot = null;    ///可以发射多颗子弹  607    Vector shots = new Vector<>();    //构造器    public Hero(int x, int y) {        super(x, y);    }    //射击方法  600    public void shortEnemyTank(){        ///最多发射5颗子弹   607//        if(shots.size()==5){/////            return;//        }        //创建Shot对象,根据Hero坦克的位置 方向        switch(getDirect()){            case 0://向上                shot = new Shot(getX()+20,getY(),0);///因为射击Shot线程有参构造器,所以要传值                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的Vector集合中        shots.add(shot);        由于Shot实现了Runnable接口,///启动Shot线程所以可以直接调用        Thread thread = new Thread(shot);        thread.start();//启动    }}
敌人的坦克EnemyTank
package com.stulzl.tankgame08;import java.util.Vector;public class EnemyTank extends Tank implements Runnable{//敌人的坦克    //在敌人坦克类,使用Vector 保存多个Shot子弹    Vector shots = new Vector<>();    boolean isLive = true;///敌人坦克存活    ///增加成员Enemytank 你可以得到敌人坦克的Vector  646    //分析    //1. Vector 在    Vector enemyTanks = new Vector<>();    //在这里提供一种方法,MyPanel 成员(即我们在MyPanel定义的敌人坦克集合)  646    // Vector enemyTanks = new Vector<>();    //设置到 EnemyTank(即我们在EnemyTank中定义的集合) 的成员 enemyTanks    ///这里解释一下为什么要这样做,因为我们的目的是防止敌人坦克重叠,所以我们必须得到每一两个敌人坦克的坐标。然而,敌人坦克    ///定义不是在EnemyTank类中定义的,而是在MyPanel中定义的敌人坦克因此,我们必须通过一种方法来获得集合    ///到MyPanel定义的敌人坦克集合,收集后必须接受,因此,在EnemyTank中定义了同一类型的集合    ////用于收到敌人坦克集合    public void setEnemyTanks(Vector enemyTanks) {        this.enemyTanks = enemyTanks;    }    //编写方法,判断当前的敌人坦克,是否和 enemyTanks 其他坦克的重叠或碰撞  646-647    public boolean isTouchEnemyTak(){        ////判断当前敌人坦克(this)方向        switch(this.getDirect(){///这里获得的方向是与其他敌人坦克相比的敌人坦克方向            //通过笔记分析,我们 分别比较8中情况(4类)            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;//表示没有碰撞    }    //构造器    public EnemyTank(int x, int y) {        super(x, y);    }    @Override    public void run() {        while(true){            我们在这里判断,如果shotss, size() = 在shots集合中创建子弹,并启动  608            if(isLive==true && shots.size()==0){//敌人坦克存活,敌人子弹集合Vector为空                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);////将子弹添加到shotsVector集合中                Thread thread = new Thread(s);                thread.start();//启动子弹线程            }            //继续按照坦克的方向移动   605            switch(getDirect()){                case 0://向上                    ///保持坦克朝一个方向走30步                    for(int i=0;i<30;i++){                        ///控制坦克移动范围不得超过边界,只能在边界内移动,不能与其他敌人坦克碰撞  606                        if(getY()>0 && !isTouchEnemyTak()) {                            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 && !isTouchEnemyTak()){                            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 && !isTouchEnemyTak()){                            moveDown();                        }                        //休眠50毫秒                        try {                            Thread.sleep(50);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                   break;                case 3://向左                    for(int i=0;i<30;i++){                        if(getX()>0 && !isTouchEnemyTak()){                            moveLeft();                        }                        //休眠50毫秒                        try {                            Thread.sleep(50);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                    break;            }            ///然后判断随机改变坦克方向0-3            setDirect((int)(Math.random()*4));//Math.random() [0-1)                                              //Math.random()*4) [0-4)            //结束线程            if(isLive==false){                break;            }        }    }}

 

射击Shot

 

package com.stulzl.tankgame08;//发射子弹线程  600public 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();            }            switch(direct){///根据方向值选择相应的子弹方向                case 0://向上                    y-=speed;                    break;                case 1://向右                    x+=speed;                    break;                case 2://向下                    y+=speed;                    break;                case 3://向左                    x-=speed;                    break;            }            //System.out.println("子弹x= "+x+" y= "+y);            //当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程)            //当子弹击中敌人坦克时,也应该结束次线程            if(!(x>=0 && x<=1000 && y>=0 && y<=750 && isLive)){//子弹越界窗口的范围                isLive = false;///子弹死了                break;            }        }    }}
爆炸Bomb
package com.stulzl.tankgame08;//炸弹 604public 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;        }    }}
Node类恢复数据使用
package com.stulzl.tankgame08;///Node对象表示敌人坦克信息publicic 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;    }}
记录Recorder类数据或读取文件
package com.stulzl.tankgame08;import java.io.*;import java.util.Vector;////用于记录相关信息和文件的交互  650@SuppressWarnings("all")public class Recorder {    //定义变量,记录下我们摧毁敌人坦克的数量    private  static int allEnemyTankNum = 0;    //定义IO对象,准备将数据写入文件    private static BufferedWriter bw = null;    private static BufferedReader br = null;    //请注意,我们将此文件位置保存在E盘中,但当涉及文件变更或复制时,这里的路径不会修改    //所以我们把文件路径保存到src以下  654//    private static String recordFile = "e:\java学习\course138myRecord.txt";    private static String recordFile = "src\\myRecord.txt";    //定义Vector,用于接收MyPanel类中定义的EnemyTankVector集合和防止敌人坦克碰撞定义的Vector集合    //一个意思    private static Vector enemyTanks = null;    //定义NodeVector集合,用于保存敌人的信息node    private static Vector nodes = new Vector<>();    ///返回记录文件的目录  654    public static String getRecordFile() {        return recordFile;    }    ///用于获取EnemyTank的Vector集合,定义为MyPanel类    public static void setEnemyTanks(Vector enemyTanks) {        Recorder.enemyTanks = enemyTanks;    }    //添加一种方法,读取recordFile文件信息,回复相关数据  653    ///这个方法,继续上局的时候可以调用    public static Vector getNodesAndEnemyTankrec(){        try {            ///创建Bufferedreader对象            如果玩家第一次上来就选择继续游戏,//在这里做一个小提示。但是我们的recordFile文件还没有创建为空            //会抛出异常,所以更新一下   654            br = new BufferedReader(new FileReader(recordFile));            ///阅读文件信息            ///读取时击毙敌人的坦克数量值,因为readline()返回String类型,所以需要转换类型            allEnemyTankNum = Integer.parseInt(br.readLine());            ///继续循环读取剩余敌人坦克信息 x,y,direct            String line = "";            while((line = br.readLine())!=null){                //因为读的时候字符串,但是我们需要数组,因为从数组到左更方便                String syd[] = line.split(" ");//依据" "(空格)分割字符串                ///这里new是一个Node对象,将读到的信息传递给Node类别                ///也需要类型转换                Node node = new Node(Integer.parseInt(syd[0]), Integer.parseInt(syd[1])                        , Integer.parseInt(syd[2]));                ///为了更好的管理,将node对象放入我们创建的nodesVector集合中,因为后面                ////返回值直接返回nodesVector集合。                nodes.add(node);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            //关闭流            try {                if(br!=null){                    br.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        ///返回nodesVector集合(实际上返回了我们读到的所有敌人坦克数据),我们        ///把信息放在Node类中,而Node放在Nodes的Vector集合中//是谁调用这种方法并接收它        ///有所有读到的数据        return nodes;    }    当游戏退出时,//添加一种方法,我们将保护allenemyTanknum值  650    // 存进"E:\java学习\course137myRecord.txt"文件    //因为这是一种不会自动执行的方法,我们需要调用    ////升级保存敌人坦克的坐标和方向  651    public static void keepRecord(){        try {            bw = new BufferedWriter(new FileWriter(recordFile));            ///保存销毁敌人的坦克数            bw.write(allEnemyTankNum+"\r\n");//"\r\n“换行的意思            //bw.newLine();///这样写换行也可以            ///Vector遍历敌人坦克 ,然后根据情况保存.   651            //OOP, 定义一个属性 ,然后通过setxxx获得 敌人坦克的Vector            for (int i = 0; i < enemyTanks.size(); i++) {                ///取出一辆敌人坦克                EnemyTank enemyTank = enemyTanks.get(i);                /////保存敌人坦克信息                if(enemyTank.isLive)如果敌人坦克存活,{//                    ///将信息写入变量                    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;    }    //当我们的坦克摧毁一辆敌人坦克时,应该是allenemytanknumm++    public static void addAllEnemyTankNun(){        Recorder.allEnemyTankNum++;    }}
AeplayWave背景音乐
package com.stulzl.tankgame08;import javax.sound.sampled.*;import java.io.File;import java.io.IOException;//播放游戏bgm,这类是老师写的,这里不做重点  654public 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();        }    }}
MyPanel画板
package com.stulzl.tankgame08;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// 不断重绘子弹需要重绘子弹 MyPanel Runnnablele实现 ,作为线程使用  601public class MyPanel extends JPanel implements KeyListener,Runnable{    //定义我们的坦克    Hero hero = null;    //定义敌人坦克,放入Vector中  578    Vector enemyTanks = new Vector<>();    int enemyTanksSize = 3;///敌人坦克数量    //定义存储Node对象的Vector集合,用于恢复敌人坦克的坐标和方向    ///目的时接收并调用getnodesAndemyTankrec()方法返回nodes的Vector集合    Vector nodes = new Vector<>();    //定义Vector,用于储存炸弹    Vector bombs = new Vector<>();    //定义三张炸弹图片来显示爆炸效果    //说明子弹击中坦克时,将Bomb对象添加到bombs中    Image image1 = null;    Image image2 = null;    Image image3 = null;    ////构造器设置坦克信息    public MyPanel(String key){        ///调用getNodesAndenemyTankrec()方法恢复数据,并使用我们在MyPanel中创建的nodes集合接收        //这里有一个小提示。如果玩家第一次上来就选择继续游戏,但是我们的recordFile会文件尚未创建为空        ///会抛出异常,所以更新   654        ///首先判断记录的文件是否存在        //如果存在,则正常执行。如果文件不存在,提示只能打开新游戏。key = "1"        ///根据getrecordFile()方法获得的文件路径,判断文件是否存在        File file = new File(Recorder.getRecordFile());        if(file.exists(){//存在            nodes = Recorder.getNodesAndEnemyTankrec();        }else{//不存在            System.out.println(文件不存在,只能打开新游戏”);            key="1";///把key放在1上,强行打开新游戏        }        ///我们的坦克设置        hero = new Hero(500, 100);///创建并初始化自己的坦克坐标        hero.setSpeed(5);///改变坦克速度        ///让玩家选择新游戏还是继续玩游戏  653        switch(key){            case "1"://新游戏                //遍历 敌人坦克的初始化                for (int i = 0; i <enemyTanksSize; i++) {                    //创建并设置敌人坦克坐标,每隔100像素放一辆坦克                    //(100 * (i + 1)), 0敌人坦克坐标                    EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);                    ///将MyPanel中定义的enemyTanksVector集合设置给                    // EnemyTank中定义的enemyTanksVector集合                    enemyTank.setEnemyTanks(enemyTanks);                    ///将MyPanel中定义的enemyTanksVector集合设置给Recorder中enemyTanks  651                    ////                    Recorder.setEnemyTanks(enemyTanks);                    ////改变敌人坦克的方向                    enemyTank.setDirect(2);                    ////随机启动敌人坦克                    Thread thread1 = new Thread(enemyTank);                    thread1.start();                    ///给enemyTank 添加子弹shotot   602                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());                    ///添加enemytankVector 成员                    enemyTank.shots.add(shot);                    //启动 shot 子弹对象                    Thread thread = new Thread(shot);                    thread.start();                    ///将敌人坦克添加到Vector中                    enemyTanks.add(enemyTank);                }                break;            case "2":继续玩游戏                //遍历 敌人坦克的初始化                for (int i = 0; i <nodes.size(); i++) {                    ///取出node敌人坦克信息                    Node node = nodes.get(i);                    ////设置敌人坦克坐标                    EnemyTank enemyTank = new EnemyTank(node.getX(),node.getY());                    ///将MyPanel中定义的enemyTanksVector集合设置给                    // EnemyTank中定义的enemyTanksVector集合                    enemyTank.setEnemyTanks(enemyTanks);                    ///将MyPanel中定义的enemyTanksVector集合设置给Recorder中enemyTanks  651                    ////                    Recorder.setEnemyTanks(enemyTanks);                    ////改变敌人坦克的方向                    enemyTank.setDirect(node.getDirect());                    ////随机启动敌人坦克                    Thread thread1 = new Thread(enemyTank);                    thread1.start();                    ///给enemyTank 添加子弹shotot   602                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());                    ///添加enemytankVector 成员                    enemyTank.shots.add(shot);                    //启动 shot 子弹对象                    Thread thread = new Thread(shot);                    thread.start();                    ///将敌人坦克添加到Vector中                    enemyTanks.add(enemyTank);                }                break;            default:                System.out.println(“你的输入有误~”);                break;        }        ///初始化图片对象        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));        ///在这里播放音乐   654        AePlayWave aePlayWave = new AePlayWave("src\\111.wav");        aePlayWave.start();///启动线程    }    ///编写记录记录记录的方法,显示我们摧毁了敌方坦克的信息  650    public void showInfo(Graphics g){        //画出玩家总分        g.setColor(Color.black);//设置画笔颜色        Font font = new Font(宋体”, Font.BOLD, 25);///设置字体,加粗,字体大小        g.setFont(font);///将上两句设置的信息添加到画笔中        g.drawString1020,30)“你累计摧毁敌方坦克”;///把这行字放在1020,30坐标        ////画敌方坦克作为小标志        drawTank(1020,60,g,0,0);///后20代表方向,坦克颜色代表        //战绩        g.setColor(Color.black);//之所以重新设置画笔颜色,因为画坦克标志时画笔的颜色发生了变化        //Recorder.getAllEnemyTankNum()+”类型转换        g.drawString(Recorder.getAllEnemyTankNum()+”,1080,100);    }    ///绘图方法    @Override    public void paint(Graphics g) {        super.paint(g);        g.fillRect(0,0,1000,750);//填充矩形,默认黑色,这是坦克的游戏区        ////这里调用记录记录记录记录的方法        showInfo(g);        //画出自己的坦克,我们把方法封装成一种方法,可以调用  573        if(hero !=null && hero.isLive==true) {///我们的坦克不是空的,而是存活的            drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);///这1控制坦克的颜色类型        }        ///画hero射击子弹//        if(hero.shot!=null && hero.shot.isLive==true){///如果子弹存在并存活,则绘制。如果子弹移动到边界,则不绘制//            g.draw3DRect(hero.shot.x,hero.shot.y,1,1,false);//子弹大小 长1 高1//            //this.repaint();////////重绘///        }        ////画hero子弹集Vector  607        ////遍历绘制        for (int i = 0; i < hero.shots.size(); i++) {            Shot shot = hero.shots.get(i);//取出一颗子弹            //如果子弹存在并存活,就画出来。如果子弹移动到边界,就不会画出来。            if(shot!=null && shot.isLive==true) {                g.draw3DRect(shot.x,shot.y, 1, 1, false);//子弹大小 长1 高1            }else{///如果子弹是空的或已经被销毁,从shots的Vector集合中删除                hero.shots.remove(shot);            }        }        //如果bombs集合中有对象,就画出   604        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();            如果bomblife为0,从bombs集合中删除            if(bomb.life==0){                bombs.remove(bomb);            }        }        ///画敌人坦克,Vector集合遍历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 所有子弹   602                for (int j = 0; j < enemyTank.shots.size(); j++) {                    //取出敌人子弹                    Shot shot = enemyTank.shots.get(j);                    //绘制                    if (shot.isLive == true) { ///子弹存活                        g.draw3DRect(shot.x, shot.y, 1, 1, false);//子弹大小 长1 高1                    } 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;        }        //按坦克方向,绘制相应方向的坦克  577        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )        switch(direct){            case 0://表示坦克向上                g.fill3DRect(x,y,10,60,false);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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(“暂时没有其他操作”);        }    }    ///写一个判断子弹击中坦克的方法 方法 603    public  void hitTank(Shot s, Tank tank){//Tank 这里直接用父类Tank接收tank涉及多态,更方便        ///判断子弹s是否击中坦克        switch(tank.getDirect()){            case 0://向上            case 2://向下//如果子弹在坦克区,说明击中坦克                if(s.x>tank.getX() && s.x<tank.getX()+40                && s.y>tank.getY() && s.y<tank.getY()+60){                    s.isLive = false;                    tank.isLive = false;                    //当我们的子弹击中敌人坦克时,将enemytank从Vector中删除                    enemyTanks.remove(tank);                    ///当我们摧毁一辆敌方坦克时,数据allenemyTankNumm++  650                    //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank                    if(tank instanceof EnemyTank)(///判断敌方坦克是否为敌方坦克                        Recorder.addAllEnemyTankNun();                    }                    ///创建Bomb对象,加入bombs集合                    Bomb bomb = new Bomb(tank.getX(),tank.getY());                    bombs.add(bomb);///将炸弹添加到bombs的Vector集合中                }                break;            case 1://向右            case 3://向左                if(s.x>tank.getX() && s.x<tank.getX()+60                        && s.y>tank.getY() && s.y<tank.getY()+40){                    s.isLive = false;                    tank.isLive = false;                    //当我们的子弹击中敌人坦克时,将enemytank从Vector中删除  605                    enemyTanks.remove(tank);                    ///当我们摧毁一辆敌方坦克时,数据allenemyTankNumm++                    //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank                    if(tank instanceof EnemyTank)(///判断敌方坦克是否为敌方坦克                        Recorder.addAllEnemyTankNun();                    }                    ///创建Bomb对象,加入bombs集合                    Bomb bomb = new Bomb(tank.getX(),tank.getY());                    bombs.add(bomb);////将炸弹添加到金bombsVector集合中                }                break;        }    }    //三种方法    //有字符输出,触发    public void keyTyped(KeyEvent e) {    }    //按键盘,触发    ///处理按下wdsa键的情况   577    @Override    public void keyPressed(KeyEvent e) {        if(e.getKeyCode()==KeyEvent.VK_W){//方向上            //改变坦克的方向            hero.setDirect(0);            if(hero.getY()>0){///判断我们的坦克,在边界范围内移动  606                hero.moveUp();            }        }else if(e.getKeyCode()==KeyEvent.VK_D){//方向右            hero.setDirect(1);            if(hero.getX()+60<1000){                hero.moveRight();            }        }else if(e.getKeyCode()==KeyEvent.VK_S){//方向下            hero.setDirect(2);            if(hero.getY()+60<750){                hero.moveDown();            }        }else if(e.getKeyCode()==KeyEvent.VK_A)左方向{///方向            hero.setDirect(3);            if(hero.getX()>0){                hero.moveLeft();            }        }        //如果用户按J键,就发射子弹        if(e.getKeyCode()==KeyEvent.VK_J){            //如果子弹是空的或者子弹被摧毁了,子弹就会被发射 ,一颗子弹只能发射一次 607//            if(hero.shot==null || hero.shot.isLive==false){//                hero.shortEnemyTank();///调用射击方法///            }            ///发射多颗子弹            if(hero.shots.size()<5){///最多发射5颗子弹  607                hero.shortEnemyTank();//调用射击方法            }        }        this.repaint();//面板重绘    }    ///松开键盘,触发    @Override    public void keyReleased(KeyEvent e) {    }    //当我们的坦克能够连续发射子弹时,判断每颗子弹是否击中敌人坦克  607    public void hitEnemyTank(){        for (int j = 0; j < hero.shots.size(); j++) {//遍历子弹集合            Shot shot = hero.shots.get(j);///取出集合子弹            if(shot!=null && shot.isLive){//当我们的子弹射出(即不是空的)并且 存活                //遍历敌人所有坦克的集合,看看哪辆敌人坦克被击中                for (int i = 0; i < enemyTanks.size(); i++) {                    EnemyTank enemyTank = enemyTanks.get(i);///取出一辆敌人坦克                    hitTank(shot,enemyTank);///调用判断是否击中                }            }        }    }    ///编写方法判断敌人坦克子弹是否击中我们坦克子弹  609    public void hitHero(){        ///遍历所有敌人坦克enemytanks的Vector集合        for (int i = 0; i < enemyTanks.size(); i++) {            ///取出一辆敌人坦克            EnemyTank enemyTank = enemyTanks.get(i);            ///遍历敌人坦克所有子弹shots集合Vectortor            for(int j=0;j<enemyTank.shots.size();j++){                //取出子弹                Shot shot = enemyTank.shots.get(j);                ////判断敌人坦克子弹shot是否击中我们的hero坦克                if(hero.isLive && shot.isLive){///我们的坦克存活,敌人子弹也存活                    hitTank(shot,hero);                }            }        }    }    @Override    public void run() {        while(true){            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            ///判断是否击中敌人坦克  603            //这种方法只能判断当前射出的子弹击中敌人,单颗子弹////            if(hero.shot!=null && hero.shot.isLive){//当我的子弹射出(即不是空的)并且 存活//                //遍历敌人所有坦克,看看哪个敌人坦克被击中///                for (int i = 0; i < enemyTanks.size(); i++) {//                    EnemyTank enemyTank = enemyTanks.get(i);////取出敌人坦克/////                    hitTank(hero.shot,enemyTank);//                }//            }            ///调用多颗子弹击中敌人坦克            hitEnemyTank();            ////调用敌人坦克击中我们的Hero坦克方法            hitHero();            this.repaint();//面板重绘        }    }}