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版
增加功能:
- 游戏开始时,播放音乐
- 修正下文件存储位置
- 处理文件相关异常
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
顺便把子弹类中子弹位置的提示信息删除:
运行截图: