Java坦克大戰07 8.IO流應用02 8.3記錄退出游戲時敵人坦克坐標/方向,存檔退出 8.3.1思路分析 在Recorder類中,增加一個Vector集合,用來接收從MyPanel類中傳入的enemyTanks集合,在記錄時遍歷集合,將還存活的敵人坦克的方向和坐標逐一取出並保存 8.3.2代碼 ...
Java坦克大戰07
8.IO流應用02
8.3記錄退出游戲時敵人坦克坐標/方向,存檔退出
8.3.1思路分析
在Recorder類中,增加一個Vector集合,用來接收從MyPanel類中傳入的enemyTanks集合,在記錄時遍歷集合,將還存活的敵人坦克的方向和坐標逐一取出並保存
8.3.2代碼實現
修改處1
Recorder類:增加屬性enemyTanks、增加方法setEnemyTanks、修改keepRecord方法:
//定義Vector,指向MyPanel對象的敵人坦克的Vector
private static Vector<EnemyTank> enemyTanks = null;
public static void setEnemyTanks(Vector<EnemyTank> 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對象,用於保存敵人的信息node
private static Vector<Node> nodes = new Vector<>();
增加getNodesAndEnemyTankRec方法,用於讀取recordFile,恢復相關信息:
//增加一個方法,用於讀取recordFile,恢復相關信息
//該方法在點擊繼續上局的時候調用
public static Vector<Node> 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<Node> 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處理文件相關異常
8.7.1異常情況
在還沒有文件記錄的時候,如果我們選擇“繼續上局”游戲的話,就會出現異常。因為文件中沒有記錄,MyPanel中的nodes集合也就得不到數據,會出現一個敵人坦克都沒有的情況:
8.7.2修改方法
修改處1
在Recorder類中增加getRecordFile方法:
//返回記錄文件的路徑
public static String getRecordFile() {
return recordFile;
}
修改處2
在MyPanel類中的MyPanel方法的最開始,添加判斷方法:
先判斷記錄文件是否存在,如果存在就正常執行,若不存在,就提示只能開新新游戲,將 key 置為 1
//先判斷記錄文件是否存在,如果存在就正常執行,若不存在,就提示只能開新新游戲,將 key 置為 1
File file = new File(Recorder.getRecordFile());
if (file.exists()) {
nodes = Recorder.getNodesAndEnemyTankRec();
} else {
System.out.println("沒有存檔記錄,只能開啟新游戲!");
key = "1";
}
修改處3
順便把子彈類中子彈位置的提示信息刪除:
運行截圖: