目录
一 IO流 - 应用到坦克大战
1 坦克大战5.0版
(1)防止坦克重叠运动;
(2)记录玩家的成绩,存盘退出;【IO流】
思路
(3)记录当时的敌人坦克坐标,存盘退出;【IO流】
(4)玩游戏时,可以选择是开新游戏还是继续上局游戏。
2 坦克大战6.0版
(1)游戏开始时,播放经典的坦克大战音乐;
(2)修正下文文件存储的位置;
(3)处理文件相关异常。
增强功能
思路
首先分析各种情况: 实现代码
① 首先要在EnemyTank类中加入敌人坦克集合属性,然后创建一个set敌人坦克集合的方法,然后设计碰撞的方法。
//增加成员,EnemyTank 可以得到敌人坦克的Vector
//分析
//1. Vector 在
Vector enemyTanks = new Vector<>();
//这里提供一个方法,可以将MyPanel 的成员 Vector enemyTanks = new Vector<>();
//设置到 EnemyTank 的成员 enemyTanks
public void setEnemyTanks(Vector enemyTanks) {
this.enemyTanks = enemyTanks;
}
//编写方法,判断当前的这个敌人坦克,是否和 enemyTanks 中的其他坦克发生的重叠或者碰撞
public boolean isTouchEnemyTank() {
//判断当前敌人坦克(this) 方向
switch (this.getDirect()) {
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;
}
② 并且在该类的调用移动方法前面进行判断是否碰撞,例如:
if (!isTouchEnemyTank()) {
downMove();
}
③ 在MyPanel类中当创建一个敌人坦克对象后,将敌人坦克集合加入。
enemyTank.setEnemyTanks(enemyTanks);
实现代码
① 在MyPanel类中编写方法,显示我方击毁敌方坦克的信息。
//编写方法,显示我方击毁敌方坦克的信息
public void showInfo(Graphics g) {
//画出玩家的总成绩
g.setColor(Color.BLACK);
Font font = new Font("宋体", Font.BOLD, 25);
g.setFont(font);
g.drawString("您累积击毁敌方坦克", 1020, 30);
drawTank(1020, 60, g, 0, 0);//画出一个敌方坦克
g.setColor(Color.BLACK);//这里需要重新设置成黑色
g.drawString(Recorder.getAllEnemyTankNum() + "", 1080, 100);
}
② 在MyPanel类的paint方法中调用该方法。
showInfo(g);
③ 新建一个Recorder类。
public class Recorder {
//定义变量,记录我方击毁敌人坦克数
private static int allEnemyTankNum = 0;
//定义IO对象, 准备写数据到文件中
private static BufferedWriter bw = null;
private static String recordFile = "e:\\myRecord.txt";
//增加一个方法,当游戏退出时,我们将allEnemyTankNum 保存到 recordFile
public static void keepRecord() throws IOException {
bw = new BufferedWriter(new FileWriter(recordFile));
bufferedWriter.write(allShotEnemyTankNums + "");
bufferedWriter.newLine();
if (bufferedWriter != null){
bufferedWriter.close();
}
}
public static int getAllEnemyTankNum() {
return allEnemyTankNum;
}
public static void setAllEnemyTankNum(int allEnemyTankNum) {
Recorder.allEnemyTankNum = allEnemyTankNum;
}
//当我方坦克击毁一个敌人坦克,就应当 allEnemyTankNum++
public static void addAllEnemyTankNum() {
Recorder.allEnemyTankNum++;
}
}
④ 在击中敌人坦克时候调用该类的addAllEnemyTankNum方法,在主类中,加入监听,在关闭窗口时候用包调用Recorder的keepRecord方法,使用包装类将击败坦克数字保存到文件里 。
//在JFrame 中增加相应关闭窗口的处理
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
Recorder.keepRecord();
System.exit(0);
}
});
思路
实现代码
① 首先在Recorder类中添加属性Vector ,指向 MyPanel 对象的 敌人坦克Vector,并设置set方法来接受该集合。
//定义Vector ,指向 MyPanel 对象的 敌人坦克Vector
private static Vector enemyTanks = null;
public static void setEnemyTanks(Vector enemyTanks) {
Recorder.enemyTanks = enemyTanks;
}
② 在KeepRecord方法中遍历敌人坦克集合,将存活坦克的位置信息保存。
//遍历敌人坦克的Vector ,然后根据情况保存即可.
//OOP, 定义一个属性 ,然后通过setXxx得到 敌人坦克的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 + "\r\n");
}
}
③ 在MyPanel类的构造方法中,将坦克集合赋给Recorder类的坦克集合。
//将MyPanel对象的 enemyTanks 设置给 Recorder 的 enemyTanks
Recorder.setEnemyTanks(enemyTanks);
思路
代码实现
① 新建Node类,用于保存从recordFile文件读取的敌人坦克信息。
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;
}
}
② 在Recorder类中添加Node集合,并创建读文件的方法,返回值是Node集合。
private static Vector nodes = new Vector<>();
//增加一个方法,用于读取recordFile, 恢复相关信息
//该方法,在继续上局的时候调用即可
public static Vector readFile() throws IOException {
bufferedReader = new BufferedReader(new FileReader(recordFile));
String num = "";
num = bufferedReader.readLine();
allShotEnemyTankNums = Integer.parseInt(num);
String info = null;
//循环读取文件,生成nodes 集合
while ((info = bufferedReader.readLine()) != null){
String[] s = info.split(" ");
Node node = new Node(Integer.parseInt(s[0]), Integer.parseInt(s[1]), Integer.valueOf(s[2]));
nodes.add(node);//放入nodes Vector
}
if (bufferedReader != null) {
bufferedReader.close();
}
return nodes;
}
③ 在TankGame类中添加num属性,main类中添加如下代码,用于选择游戏类型。
static int num = -1;//0表示继续,1表示新开
Scanner scanner = new Scanner(System.in);
System.out.print("继续游戏(0)or新游戏(1):");
while (true) {
num = scanner.nextInt();
if (num == 0 || num == 1) {
break;
}
System.out.println("请重输..");
}
new TankGame04();
④ 在MyPanel类中定义并创建node集合属性,用于接受敌人坦克信息,并且在构造器中根据选择的是继续游戏还是新游戏来进行敌人坦克的初始化。
Vector nodes = new Vector<>();
//构造方法中
nodes = Recorder.readFile();
if (TankGame04.num == 1) {//开启一局新游戏
//初始化敌人坦克
for (int i = 0; i < enemyTankSize; i++) {
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
//将enemyTanks 设置给 enemyTank !!!
enemyTank.setEnemyTanks(enemyTanks);
//设置方向
enemyTank.setDirect(1);
//启动敌人坦克线程,让他动起来
new Thread(enemyTank).start();
//给该enemyTank 加入一颗子弹
Bullet bullet = new Bullet((enemyTank.getX() + 20), (enemyTank.getY() + 60), 1);
//加入enemyTank的Vector 成员
enemyTank.bullets.add(bullet);
//启动 shot 对象
Thread thread = new Thread(bullet);
//开启线程
thread.start();
//加入敌人坦克集合
enemyTanks.add(enemyTank);
}
}else if (TankGame04.num == 0){//继续上局游戏
for (int i = 0; i < nodes.size(); i++) {
EnemyTank enemyTank = new EnemyTank(nodes.get(i).getX(), nodes.get(i).getY());
enemyTank.setEnemyTanks(enemyTanks);
enemyTank.setDirect(nodes.get(i).getDirection());
new Thread(enemyTank).start();
enemyTanks.add(enemyTank);
}
}
加入AePlayWave类文件,并且将wav音乐文件放在指定的位置,在MyPanel类的构造器中加入如下代码即可。
new AePlayWave("src\\111.wav").start();
private static String recordFile = "src\\recordFile.txt";
把MyPanel类的构造器的调用Recorder类的readFile方法加上条件判断,防止第一没有文件的话出现的异常。
//先判断记录的文件是否存在
//如果存在,就正常执行,如果文件不存在,提示,只能开启新游戏,key = "1"
File file = new File(Recorder.getRecordFile());
if (file.exists()) {
nodes = Recorder.getNodesAndEnemyTankRec();
} else {
System.out.println("文件不存在,只能开启新的游戏");
key = "1";
}