Java坦克大战078.IO流应用028.3记录退出游戏时敌人坦克坐标/方向,存盘退出8.3.1思路分析

在Recorder类中,增加一个Vector集合,用来接收从MyPanel类中传入的enemyTanks集合,在记录时遍历集合,将还存活的敌人坦克的方向和坐标逐一取出并保存

8.3.2代码实现修改处1

Recorder类:增加属性enemyTanks、增加方法setEnemyTanks、修改keepRecord方法:

//定义Vector,指向MyPanel对象的敌人坦克的Vectorprivate static Vector enemyTanks = null;public static void setEnemyTanks(Vector enemyTanks) {    Recorder.enemyTanks = enemyTanks;}public static void keepRecord() {    try {        bw = new BufferedWriter(new FileWriter(recordFile));        bw.write(allEnemyTankNum + "\n");        //遍历敌人坦克的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+"\n");            }        }    } catch (IOException e) {        e.printStackTrace();    } finally {        try {            if (bw != null) {                bw.close();            }        } catch (IOException e) {            e.printStackTrace();        }    }}

修改处2

在MyPanel类中的MyPanel方法,调用Recorder的静态方法setEnemyTanks,将敌人坦克的集合enemyTanks传到Recorder类中

ps:引用类型传递的是地址,地址不会变化,因此可以获取到集合的最新的状态

关闭时:

记录状态:

8.4玩游戏时可以选择是开新游戏还是继续上局游戏8.4.1思路分析

将每个敌人信息恢复(读取)成Node对象,再放到vector里面去,通过Node的vector去初始化敌人坦克的位置和方向

8.4.2代码实现修改处1

新建一个Node类:

package li.TankGame.version06;/** * @author 李 * @version 6.0 * 一个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;    }}

修改处2

在Recorder类中:

创建一个BufferedReader对象:

private static BufferedReader br = null;//输入处理流

定义一个Node的Vector对象,用于保存敌人的信息node:

//定义一个Node的Vector对象,用于保存敌人的信息nodeprivate static Vector nodes = new Vector();

增加getNodesAndEnemyTankRec方法,用于读取recordFile,恢复相关信息:

//增加一个方法,用于读取recordFile,恢复相关信息//该方法在点击继续上局的时候调用public static Vector getNodesAndEnemyTankRec() {    try {        br = new BufferedReader(new FileReader(recordFile));        //读取上局击毁坦克数量        allEnemyTankNum = Integer.parseInt(br.readLine());        //循环读取文件,生成nodes集合        String line = "";        while ((line = br.readLine()) != null) {            //用空格将每一行的数据分割,分割完的字符数组里面存储了一组敌方坦克的x,y,direct            String[] xyd = line.split(" ");            //将字符串转为int类型,赋值给node对象            Node node = new Node(Integer.parseInt(xyd[0]),                    Integer.parseInt(xyd[1]), Integer.parseInt(xyd[2]));            //将该node对象放到nodes集合中            nodes.add(node);        }    } catch (IOException e) {        e.printStackTrace();    } finally {        try {            if (br != null) {                br.close();            }        } catch (IOException e) {            e.printStackTrace();        }    }    return nodes;}

修改处3

在MyPanel类中:

定义一个存放Node对象的Vector,用于恢复敌人坦克的坐标和方向:

//定义一个存放Node对象的Vector,用于恢复敌人坦克的坐标和方向Vector nodes = new Vector();

修改MyPanel方法,修改了方法传入的参数String key;

在方法里面调用了getNodesAndEnemyTankRec,将其返回的nodes集合传给MyPanel类的nodes的集合;

使用switch,根据输入的key判断是新开一局还是接着上一局游戏;

public MyPanel(String key) {    nodes = Recorder.getNodesAndEnemyTankRec();    //将MyPanel对象的enemyTanks 设置给Recorder的enemyTanks    Recorder.setEnemyTanks(enemyTanks);    hero = new Hero(400, 200);//初始化自己的坦克    //hero.setSpeed(5); //改变坦克的速度    switch (key){        case "1":  //开新游戏             Recorder.setAllEnemyTankNum(0);//重设击毁敌方坦克数目            //初始化敌人的坦克            for (int i = 0; i < enemyTankNum; 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("/bomb1.png"));    image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb2.png"));    image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb3.png"));}

修改处4

在TankGame06类中新建一个Scanner对象:

static Scanner scanner = new Scanner(System.in);

修改TankGame06构造器,是在控制台输入的选择传到MyPanel构造器中:

public TankGame06() {    System.out.println("请输入选择:\n" + "1:新游戏 2:继续上局");    String key = scanner.next();    mp = new MyPanel(key);    //将mp放入到Thread,并启动    Thread thread = new Thread(mp);    thread.start();    this.add(mp);//把面板(就是游戏的绘图区域)添加进来    this.setSize(950, 600);//设置大小    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);        }    });}

退出时:

继续上局:

ps:这里截图不及时,实际上恢复的位置与上局一致

坦克大战7.0版

增加功能:

  1. 游戏开始时,播放音乐
  2. 修正下文件存储位置
  3. 处理文件相关异常

8.5游戏开始时,播放音乐思路

新建一个播放音乐的类

修改处1

在网上找到相关音乐的.wav文件(注意一定要是wav,自己改的缀有可能会出现不能播放的情况),将其粘贴到项目的src文件的根目录下面

修改处2

新建一个播放音乐的类

package li.TankGame.version07;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();        }    }}

修改处3

在MyPanel类中的构造器MyPanel中,在最后一行启动线程

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

8.6修正下文件存储位置

把Recorder类中的记录文件修改为:保存到src目录下

8.7.2修改方法修改处1

在Recorder类中增加getRecordFile方法:

//返回记录文件的路径public static String getRecordFile() {    return recordFile;}

修改处2

在MyPanel类中的MyPanel方法的最开始,添加判断方法:

先判断记录文件是否存在,如果存在就正常执行,若不存在,就提示只能开新新游戏,将 key 置为 1

//先判断记录文件是否存在,如果存在就正常执行,若不存在,就提示只能开新新游戏,将 key 置为 1File file = new File(Recorder.getRecordFile());if (file.exists()) {    nodes = Recorder.getNodesAndEnemyTankRec();} else {    System.out.println("没有存档记录,只能开启新游戏!");    key = "1";}

修改处3

顺便把子弹类中子弹位置的提示信息删除:

运行截图: