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 = https://www.cnblogs.com/liyuelian/archive/2022/09/15/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
順便把子彈類中子彈位置的提示資訊洗掉:

運行截圖:
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/508780.html
標籤:其他
