1.08版坦克大战1.1增加功能654
1.游戏开始时,播放经典坦克大战音乐,[思考,使用播放音乐的类别]654
2.修正下文件的存储位置6544
3.处理文件相关异常=提示代码的健壮性654
com中的代码.stulzl.tankgame08.包中测试Tankgame08
package com.stulzl.tankgame08;import javax.swing.*;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.util.Scanner;//主方法 572public class Tankgame08 extends JFrame { ///定义我们的MyPanel MyPanel mp = null; static Scanner scanner = new Scanner(System.in); public static void main(String[] args) { Tankgame08 tankgame0 = new Tankgame08();//调用显示结果 } /////构造设置窗口信息 public Tankgame08(){ System.out.println(”请输入选择 1:新游戏 2:继续玩游戏”); String key = scanner.next(); mp = new MyPanel(key);//初始化面板,这个key是将用户选择传输到MyPanel进行判断和选择 ///将mp放入Thread 并启动 Thread thread = new Thread(mp); thread.start();///启动MyPanel线程 this.add(mp);///将面板添加到窗口 this.setSize(1300,950);//设置窗口大小 this.addKeyListener(mp);///让JFrame监控mp this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭程序 this.setVisible(true);//显示窗口 ///在JFrame中添加监控关闭窗口处理的相应方法 650 this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { Recorder.keepRecord();////调用保存记录方法 System.exit(0);///这种System的方法不用纠结,可以理解,成就是关闭左右 } }); }}
Tank,父类坦克
package com.stulzl.tankgame08;public class Tank {//父类坦克 private int x;///坦克的横坐标 private int y;///坦克纵坐标 private int direct;//在坦克方向0上 1右 2下 3左 577 private int speed = 1;//控制坦克速度 boolean isLive = true;////我们坦克生存标志 ///在坦克上右下左移动 577 public void moveUp(){//向上移动 y-=speed; } public void moveRight(){//向右移动 x+=speed; } public void moveDown(){//向下移动 y+=speed; } public void moveLeft(){//左移动 x-=speed; } public int getSpeed() { return speed; } public void setSpeed(int speed) { this.speed = speed; } public int getDirect() { return direct; } public void setDirect(int direct) { this.direct = direct; } public Tank(int x, int y) { this.x = x; this.y = y; } 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; }}
我们的坦克Hero
package com.stulzl.tankgame08;import java.util.Vector;public class Hero extends Tank {///我们的坦克,设置坦克坐标,打开Shot射击线程 ///我们的坦克生存标志islive直接写在父类中,方便 ///定义Shot对象,表示射击(线程) Shot shot = null; ///可以发射多颗子弹 607 Vector shots = new Vector<>(); //构造器 public Hero(int x, int y) { super(x, y); } //射击方法 600 public void shortEnemyTank(){ ///最多发射5颗子弹 607// if(shots.size()==5){///// return;// } //创建Shot对象,根据Hero坦克的位置 方向 switch(getDirect()){ case 0://向上 shot = new Shot(getX()+20,getY(),0);///因为射击Shot线程有参构造器,所以要传值 break; case 1://向右 shot = new Shot(getX()+60,getY()+20,1); break; case 2://向下 shot = new Shot(getX()+20,getY()+60,2); break; case 3://向左 shot = new Shot(getX(),getY()+20,3); break; } ////将新创建的shot放入shots的Vector集合中 shots.add(shot); 由于Shot实现了Runnable接口,///启动Shot线程所以可以直接调用 Thread thread = new Thread(shot); thread.start();//启动 }}
敌人的坦克EnemyTank
package com.stulzl.tankgame08;import java.util.Vector;public class EnemyTank extends Tank implements Runnable{//敌人的坦克 //在敌人坦克类,使用Vector 保存多个Shot子弹 Vector shots = new Vector<>(); boolean isLive = true;///敌人坦克存活 ///增加成员Enemytank 你可以得到敌人坦克的Vector 646 //分析 //1. Vector 在 Vector enemyTanks = new Vector<>(); //在这里提供一种方法,MyPanel 成员(即我们在MyPanel定义的敌人坦克集合) 646 // Vector enemyTanks = new Vector<>(); //设置到 EnemyTank(即我们在EnemyTank中定义的集合) 的成员 enemyTanks ///这里解释一下为什么要这样做,因为我们的目的是防止敌人坦克重叠,所以我们必须得到每一两个敌人坦克的坐标。然而,敌人坦克 ///定义不是在EnemyTank类中定义的,而是在MyPanel中定义的敌人坦克因此,我们必须通过一种方法来获得集合 ///到MyPanel定义的敌人坦克集合,收集后必须接受,因此,在EnemyTank中定义了同一类型的集合 ////用于收到敌人坦克集合 public void setEnemyTanks(Vector enemyTanks) { this.enemyTanks = enemyTanks; } //编写方法,判断当前的敌人坦克,是否和 enemyTanks 其他坦克的重叠或碰撞 646-647 public boolean isTouchEnemyTak(){ ////判断当前敌人坦克(this)方向 switch(this.getDirect(){///这里获得的方向是与其他敌人坦克相比的敌人坦克方向 //通过笔记分析,我们 分别比较8中情况(4类) 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;//表示没有碰撞 } //构造器 public EnemyTank(int x, int y) { super(x, y); } @Override public void run() { while(true){ 我们在这里判断,如果shotss, size() = 在shots集合中创建子弹,并启动 608 if(isLive==true && shots.size()==0){//敌人坦克存活,敌人子弹集合Vector为空 Shot s = null;//临时子弹变量 ///判断坦克方向,创建相应的子弹 switch(getDirect()){ case 0://向上 s = new Shot(getX()+20,getY(),0); break; case 1://向右 s = new Shot(getX()+60,getY()+20,1); break; case 2://向下 s = new Shot(getX()+20,getY()+60,2); break; case 3://向左 s = new Shot(getX(),getY()+20,3); break; } shots.add(s);////将子弹添加到shotsVector集合中 Thread thread = new Thread(s); thread.start();//启动子弹线程 } //继续按照坦克的方向移动 605 switch(getDirect()){ case 0://向上 ///保持坦克朝一个方向走30步 for(int i=0;i<30;i++){ ///控制坦克移动范围不得超过边界,只能在边界内移动,不能与其他敌人坦克碰撞 606 if(getY()>0 && !isTouchEnemyTak()) { moveUp(); } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 1://向右 for(int i=0;i<30;i++){ if(getX()+60<1000 && !isTouchEnemyTak()){ moveRight(); } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 2://向下 for(int i=0;i<30;i++){ if(getY()+60<750 && !isTouchEnemyTak()){ moveDown(); } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 3://向左 for(int i=0;i<30;i++){ if(getX()>0 && !isTouchEnemyTak()){ moveLeft(); } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; } ///然后判断随机改变坦克方向0-3 setDirect((int)(Math.random()*4));//Math.random() [0-1) //Math.random()*4) [0-4) //结束线程 if(isLive==false){ break; } } }}
射击Shot
package com.stulzl.tankgame08;//发射子弹线程 600public class Shot implements Runnable{ int x;//子弹x坐标 int y;//子弹y坐标 int direct=0;//子弹的方向 int speed = 2;///子弹速度 boolean isLive = true;//子弹是否存活 //构造器,接收传来的值 public Shot(int x, int y, int direct) { this.x = x; this.y = y; this.direct = direct; } @Override public void run() {//射击行为 while(true){ //休息50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } switch(direct){///根据方向值选择相应的子弹方向 case 0://向上 y-=speed; break; case 1://向右 x+=speed; break; case 2://向下 y+=speed; break; case 3://向左 x-=speed; break; } //System.out.println("子弹x= "+x+" y= "+y); //当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程) //当子弹击中敌人坦克时,也应该结束次线程 if(!(x>=0 && x<=1000 && y>=0 && y<=750 && isLive)){//子弹越界窗口的范围 isLive = false;///子弹死了 break; } } }}
爆炸Bomb
package com.stulzl.tankgame08;//炸弹 604public class Bomb { int x,y;///炸弹坐标 int life = 9;//炸弹生命周期,用来控制后面炸弹爆炸瞬间的大图还是小图? boolean isLive = true;//是否存活 public Bomb(int x, int y) { this.x = x; this.y = y; } //减少生命值 public void lifeDown(){ if(life>0){ life--; }else{ isLive = false; } }}
Node类恢复数据使用
package com.stulzl.tankgame08;///Node对象表示敌人坦克信息publicic 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类数据或读取文件
package com.stulzl.tankgame08;import java.io.*;import java.util.Vector;////用于记录相关信息和文件的交互 650@SuppressWarnings("all")public class Recorder { //定义变量,记录下我们摧毁敌人坦克的数量 private static int allEnemyTankNum = 0; //定义IO对象,准备将数据写入文件 private static BufferedWriter bw = null; private static BufferedReader br = null; //请注意,我们将此文件位置保存在E盘中,但当涉及文件变更或复制时,这里的路径不会修改 //所以我们把文件路径保存到src以下 654// private static String recordFile = "e:\java学习\course138myRecord.txt"; private static String recordFile = "src\\myRecord.txt"; //定义Vector,用于接收MyPanel类中定义的EnemyTankVector集合和防止敌人坦克碰撞定义的Vector集合 //一个意思 private static Vector enemyTanks = null; //定义NodeVector集合,用于保存敌人的信息node private static Vector nodes = new Vector<>(); ///返回记录文件的目录 654 public static String getRecordFile() { return recordFile; } ///用于获取EnemyTank的Vector集合,定义为MyPanel类 public static void setEnemyTanks(Vector enemyTanks) { Recorder.enemyTanks = enemyTanks; } //添加一种方法,读取recordFile文件信息,回复相关数据 653 ///这个方法,继续上局的时候可以调用 public static Vector getNodesAndEnemyTankrec(){ try { ///创建Bufferedreader对象 如果玩家第一次上来就选择继续游戏,//在这里做一个小提示。但是我们的recordFile文件还没有创建为空 //会抛出异常,所以更新一下 654 br = new BufferedReader(new FileReader(recordFile)); ///阅读文件信息 ///读取时击毙敌人的坦克数量值,因为readline()返回String类型,所以需要转换类型 allEnemyTankNum = Integer.parseInt(br.readLine()); ///继续循环读取剩余敌人坦克信息 x,y,direct String line = ""; while((line = br.readLine())!=null){ //因为读的时候字符串,但是我们需要数组,因为从数组到左更方便 String syd[] = line.split(" ");//依据" "(空格)分割字符串 ///这里new是一个Node对象,将读到的信息传递给Node类别 ///也需要类型转换 Node node = new Node(Integer.parseInt(syd[0]), Integer.parseInt(syd[1]) , Integer.parseInt(syd[2])); ///为了更好的管理,将node对象放入我们创建的nodesVector集合中,因为后面 ////返回值直接返回nodesVector集合。 nodes.add(node); } } catch (IOException e) { e.printStackTrace(); } finally { //关闭流 try { if(br!=null){ br.close(); } } catch (IOException e) { e.printStackTrace(); } } ///返回nodesVector集合(实际上返回了我们读到的所有敌人坦克数据),我们 ///把信息放在Node类中,而Node放在Nodes的Vector集合中//是谁调用这种方法并接收它 ///有所有读到的数据 return nodes; } 当游戏退出时,//添加一种方法,我们将保护allenemyTanknum值 650 // 存进"E:\java学习\course137myRecord.txt"文件 //因为这是一种不会自动执行的方法,我们需要调用 ////升级保存敌人坦克的坐标和方向 651 public static void keepRecord(){ try { bw = new BufferedWriter(new FileWriter(recordFile)); ///保存销毁敌人的坦克数 bw.write(allEnemyTankNum+"\r\n");//"\r\n“换行的意思 //bw.newLine();///这样写换行也可以 ///Vector遍历敌人坦克 ,然后根据情况保存. 651 //OOP, 定义一个属性 ,然后通过setxxx获得 敌人坦克的Vector for (int i = 0; i < enemyTanks.size(); i++) { ///取出一辆敌人坦克 EnemyTank enemyTank = enemyTanks.get(i); /////保存敌人坦克信息 if(enemyTank.isLive)如果敌人坦克存活,{// ///将信息写入变量 String record = enemyTank.getX()+" "+enemyTank.getY()+" "+enemyTank.getDirect(); ///写入文件 bw.write(record+"\r\n"); } } } catch (IOException e) { e.printStackTrace(); } finally { //关闭流 try { if(bw!=null){ bw.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static int getAllEnemyTankNum() { return allEnemyTankNum; } public static void setAllEnemyTankNum(int allEnemyTankNum) { Recorder.allEnemyTankNum = allEnemyTankNum; } //当我们的坦克摧毁一辆敌人坦克时,应该是allenemytanknumm++ public static void addAllEnemyTankNun(){ Recorder.allEnemyTankNum++; }}
AeplayWave背景音乐
package com.stulzl.tankgame08;import javax.sound.sampled.*;import java.io.File;import java.io.IOException;//播放游戏bgm,这类是老师写的,这里不做重点 654public 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(); } }}
MyPanel画板
package com.stulzl.tankgame08;import javax.swing.*;import java.awt.*;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.io.File;import java.util.Vector;//坦克绘图区//为响应键盘事件,Keylistener// 不断重绘子弹需要重绘子弹 MyPanel Runnnablele实现 ,作为线程使用 601public class MyPanel extends JPanel implements KeyListener,Runnable{ //定义我们的坦克 Hero hero = null; //定义敌人坦克,放入Vector中 578 Vector enemyTanks = new Vector<>(); int enemyTanksSize = 3;///敌人坦克数量 //定义存储Node对象的Vector集合,用于恢复敌人坦克的坐标和方向 ///目的时接收并调用getnodesAndemyTankrec()方法返回nodes的Vector集合 Vector nodes = new Vector<>(); //定义Vector,用于储存炸弹 Vector bombs = new Vector<>(); //定义三张炸弹图片来显示爆炸效果 //说明子弹击中坦克时,将Bomb对象添加到bombs中 Image image1 = null; Image image2 = null; Image image3 = null; ////构造器设置坦克信息 public MyPanel(String key){ ///调用getNodesAndenemyTankrec()方法恢复数据,并使用我们在MyPanel中创建的nodes集合接收 //这里有一个小提示。如果玩家第一次上来就选择继续游戏,但是我们的recordFile会文件尚未创建为空 ///会抛出异常,所以更新 654 ///首先判断记录的文件是否存在 //如果存在,则正常执行。如果文件不存在,提示只能打开新游戏。key = "1" ///根据getrecordFile()方法获得的文件路径,判断文件是否存在 File file = new File(Recorder.getRecordFile()); if(file.exists(){//存在 nodes = Recorder.getNodesAndEnemyTankrec(); }else{//不存在 System.out.println(文件不存在,只能打开新游戏”); key="1";///把key放在1上,强行打开新游戏 } ///我们的坦克设置 hero = new Hero(500, 100);///创建并初始化自己的坦克坐标 hero.setSpeed(5);///改变坦克速度 ///让玩家选择新游戏还是继续玩游戏 653 switch(key){ case "1"://新游戏 //遍历 敌人坦克的初始化 for (int i = 0; i <enemyTanksSize; i++) { //创建并设置敌人坦克坐标,每隔100像素放一辆坦克 //(100 * (i + 1)), 0敌人坦克坐标 EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0); ///将MyPanel中定义的enemyTanksVector集合设置给 // EnemyTank中定义的enemyTanksVector集合 enemyTank.setEnemyTanks(enemyTanks); ///将MyPanel中定义的enemyTanksVector集合设置给Recorder中enemyTanks 651 //// Recorder.setEnemyTanks(enemyTanks); ////改变敌人坦克的方向 enemyTank.setDirect(2); ////随机启动敌人坦克 Thread thread1 = new Thread(enemyTank); thread1.start(); ///给enemyTank 添加子弹shotot 602 Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect()); ///添加enemytankVector 成员 enemyTank.shots.add(shot); //启动 shot 子弹对象 Thread thread = new Thread(shot); thread.start(); ///将敌人坦克添加到Vector中 enemyTanks.add(enemyTank); } break; case "2":继续玩游戏 //遍历 敌人坦克的初始化 for (int i = 0; i <nodes.size(); i++) { ///取出node敌人坦克信息 Node node = nodes.get(i); ////设置敌人坦克坐标 EnemyTank enemyTank = new EnemyTank(node.getX(),node.getY()); ///将MyPanel中定义的enemyTanksVector集合设置给 // EnemyTank中定义的enemyTanksVector集合 enemyTank.setEnemyTanks(enemyTanks); ///将MyPanel中定义的enemyTanksVector集合设置给Recorder中enemyTanks 651 //// Recorder.setEnemyTanks(enemyTanks); ////改变敌人坦克的方向 enemyTank.setDirect(node.getDirect()); ////随机启动敌人坦克 Thread thread1 = new Thread(enemyTank); thread1.start(); ///给enemyTank 添加子弹shotot 602 Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect()); ///添加enemytankVector 成员 enemyTank.shots.add(shot); //启动 shot 子弹对象 Thread thread = new Thread(shot); thread.start(); ///将敌人坦克添加到Vector中 enemyTanks.add(enemyTank); } break; default: System.out.println(“你的输入有误~”); break; } ///初始化图片对象 image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif")); image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif")); image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif")); ///在这里播放音乐 654 AePlayWave aePlayWave = new AePlayWave("src\\111.wav"); aePlayWave.start();///启动线程 } ///编写记录记录记录的方法,显示我们摧毁了敌方坦克的信息 650 public void showInfo(Graphics g){ //画出玩家总分 g.setColor(Color.black);//设置画笔颜色 Font font = new Font(宋体”, Font.BOLD, 25);///设置字体,加粗,字体大小 g.setFont(font);///将上两句设置的信息添加到画笔中 g.drawString1020,30)“你累计摧毁敌方坦克”;///把这行字放在1020,30坐标 ////画敌方坦克作为小标志 drawTank(1020,60,g,0,0);///后20代表方向,坦克颜色代表 //战绩 g.setColor(Color.black);//之所以重新设置画笔颜色,因为画坦克标志时画笔的颜色发生了变化 //Recorder.getAllEnemyTankNum()+”类型转换 g.drawString(Recorder.getAllEnemyTankNum()+”,1080,100); } ///绘图方法 @Override public void paint(Graphics g) { super.paint(g); g.fillRect(0,0,1000,750);//填充矩形,默认黑色,这是坦克的游戏区 ////这里调用记录记录记录记录的方法 showInfo(g); //画出自己的坦克,我们把方法封装成一种方法,可以调用 573 if(hero !=null && hero.isLive==true) {///我们的坦克不是空的,而是存活的 drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);///这1控制坦克的颜色类型 } ///画hero射击子弹// if(hero.shot!=null && hero.shot.isLive==true){///如果子弹存在并存活,则绘制。如果子弹移动到边界,则不绘制// g.draw3DRect(hero.shot.x,hero.shot.y,1,1,false);//子弹大小 长1 高1// //this.repaint();////////重绘/// } ////画hero子弹集Vector 607 ////遍历绘制 for (int i = 0; i < hero.shots.size(); i++) { Shot shot = hero.shots.get(i);//取出一颗子弹 //如果子弹存在并存活,就画出来。如果子弹移动到边界,就不会画出来。 if(shot!=null && shot.isLive==true) { g.draw3DRect(shot.x,shot.y, 1, 1, false);//子弹大小 长1 高1 }else{///如果子弹是空的或已经被销毁,从shots的Vector集合中删除 hero.shots.remove(shot); } } //如果bombs集合中有对象,就画出 604 for (int i = 0; i < bombs.size(); i++) { //取出炸弹 Bomb bomb = bombs.get(i); ///根据当前bomb对象的life值判断相应的图片 if(bomb.life>6){ g.drawImage(image1,bomb.x, bomb.y, 60,60,this);///画大图片 }else if(bomb.life>3){ g.drawImage(image2,bomb.x, bomb.y, 60,60,this);///画中图 }else{ g.drawImage(image3,bomb.x, bomb.y, 60,60,this);///画小图片 } ///减少炸弹的生命值 bomb.lifeDown(); 如果bomblife为0,从bombs集合中删除 if(bomb.life==0){ bombs.remove(bomb); } } ///画敌人坦克,Vector集合遍历Vector for (int i = 0; i <enemyTanks.size(); i++) { ///从Vector中 取出敌人坦克 EnemyTank enemyTank = enemyTanks.get(i); if(enemyTank.isLive) {//目前敌人坦克还活着,我们才画 ///画敌人坦克 drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0); //画出 enemyTank 所有子弹 602 for (int j = 0; j < enemyTank.shots.size(); j++) { //取出敌人子弹 Shot shot = enemyTank.shots.get(j); //绘制 if (shot.isLive == true) { ///子弹存活 g.draw3DRect(shot.x, shot.y, 1, 1, false);//子弹大小 长1 高1 } else {///敌人子弹不存活 //从Vector 移除 enemyTank.shots.remove(shot); } } } } } /** * @param x 坦克的左上角 x 坐标 * @param y 坦克的左上角 y 坐标 * @param g 画笔 * @param direct 坦克方向(上下左右) * @param type 坦克类型 */ ////写作方法画坦克 public void drawTank(int x,int y,Graphics g,int direct,int type){ //不同类型的基础,设置不同的颜色 switch(type){ case 0:///敌人的坦克 g.setColor(Color.cyan); break; case 1:///我们的坦克 g.setColor(Color.yellow); break; } //按坦克方向,绘制相应方向的坦克 577 //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 ) switch(direct){ case 0://表示坦克向上 g.fill3DRect(x,y,10,60,false);//左轮////画3D矩形看起来更像 false使图像更像 g.fill3DRect(x+30,y,10,60,false);///右边的轮子 g.fill3DRect(x+10,y+10,20,40,false);//中间身体 g.fillOval(x+10,y+20,20,20);//中间炮塔 g.drawLine(x+20,y+30,x+20,y);//炮筒 break; case 1://向右 g.fill3DRect(x,y,60,10,false);//左轮////画3D矩形看起来更像 false使图像更像 g.fill3DRect(x,y+30,60,10,false);///右边的轮子 g.fill3DRect(x+10,y+10,40,20,false);//中间身体 g.fillOval(x+20,y+10,20,20);//中间炮塔 g.drawLine(x+30,y+20,x+60,y+20);//炮筒 break; case 2://向下 g.fill3DRect(x,y,10,60,false);//左轮////画3D矩形看起来更像 false使图像更像 g.fill3DRect(x+30,y,10,60,false);///右边的轮子 g.fill3DRect(x+10,y+10,20,40,false);//中间身体 g.fillOval(x+10,y+20,20,20);//中间炮塔 g.drawLine(x+20,y+30,x+20,y+60);//炮筒 break; case 3://向左 g.fill3DRect(x,y,60,10,false);//左轮////画3D矩形看起来更像 false使图像更像 g.fill3DRect(x,y+30,60,10,false);///右边的轮子 g.fill3DRect(x+10,y+10,40,20,false);//中间身体 g.fillOval(x+20,y+10,20,20);//中间炮塔 g.drawLine(x+30,y+20,x,y+20);//炮筒 break; default: System.out.println(“暂时没有其他操作”); } } ///写一个判断子弹击中坦克的方法 方法 603 public void hitTank(Shot s, Tank tank){//Tank 这里直接用父类Tank接收tank涉及多态,更方便 ///判断子弹s是否击中坦克 switch(tank.getDirect()){ case 0://向上 case 2://向下//如果子弹在坦克区,说明击中坦克 if(s.x>tank.getX() && s.x<tank.getX()+40 && s.y>tank.getY() && s.y<tank.getY()+60){ s.isLive = false; tank.isLive = false; //当我们的子弹击中敌人坦克时,将enemytank从Vector中删除 enemyTanks.remove(tank); ///当我们摧毁一辆敌方坦克时,数据allenemyTankNumm++ 650 //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank if(tank instanceof EnemyTank)(///判断敌方坦克是否为敌方坦克 Recorder.addAllEnemyTankNun(); } ///创建Bomb对象,加入bombs集合 Bomb bomb = new Bomb(tank.getX(),tank.getY()); bombs.add(bomb);///将炸弹添加到bombs的Vector集合中 } break; case 1://向右 case 3://向左 if(s.x>tank.getX() && s.x<tank.getX()+60 && s.y>tank.getY() && s.y<tank.getY()+40){ s.isLive = false; tank.isLive = false; //当我们的子弹击中敌人坦克时,将enemytank从Vector中删除 605 enemyTanks.remove(tank); ///当我们摧毁一辆敌方坦克时,数据allenemyTankNumm++ //解读, 因为 enemyTank 可以是 Hero 也可以是 EnemyTank if(tank instanceof EnemyTank)(///判断敌方坦克是否为敌方坦克 Recorder.addAllEnemyTankNun(); } ///创建Bomb对象,加入bombs集合 Bomb bomb = new Bomb(tank.getX(),tank.getY()); bombs.add(bomb);////将炸弹添加到金bombsVector集合中 } break; } } //三种方法 //有字符输出,触发 public void keyTyped(KeyEvent e) { } //按键盘,触发 ///处理按下wdsa键的情况 577 @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_W){//方向上 //改变坦克的方向 hero.setDirect(0); if(hero.getY()>0){///判断我们的坦克,在边界范围内移动 606 hero.moveUp(); } }else if(e.getKeyCode()==KeyEvent.VK_D){//方向右 hero.setDirect(1); if(hero.getX()+60<1000){ hero.moveRight(); } }else if(e.getKeyCode()==KeyEvent.VK_S){//方向下 hero.setDirect(2); if(hero.getY()+60<750){ hero.moveDown(); } }else if(e.getKeyCode()==KeyEvent.VK_A)左方向{///方向 hero.setDirect(3); if(hero.getX()>0){ hero.moveLeft(); } } //如果用户按J键,就发射子弹 if(e.getKeyCode()==KeyEvent.VK_J){ //如果子弹是空的或者子弹被摧毁了,子弹就会被发射 ,一颗子弹只能发射一次 607// if(hero.shot==null || hero.shot.isLive==false){// hero.shortEnemyTank();///调用射击方法/// } ///发射多颗子弹 if(hero.shots.size()<5){///最多发射5颗子弹 607 hero.shortEnemyTank();//调用射击方法 } } this.repaint();//面板重绘 } ///松开键盘,触发 @Override public void keyReleased(KeyEvent e) { } //当我们的坦克能够连续发射子弹时,判断每颗子弹是否击中敌人坦克 607 public void hitEnemyTank(){ for (int j = 0; j < hero.shots.size(); j++) {//遍历子弹集合 Shot shot = hero.shots.get(j);///取出集合子弹 if(shot!=null && shot.isLive){//当我们的子弹射出(即不是空的)并且 存活 //遍历敌人所有坦克的集合,看看哪辆敌人坦克被击中 for (int i = 0; i < enemyTanks.size(); i++) { EnemyTank enemyTank = enemyTanks.get(i);///取出一辆敌人坦克 hitTank(shot,enemyTank);///调用判断是否击中 } } } } ///编写方法判断敌人坦克子弹是否击中我们坦克子弹 609 public void hitHero(){ ///遍历所有敌人坦克enemytanks的Vector集合 for (int i = 0; i < enemyTanks.size(); i++) { ///取出一辆敌人坦克 EnemyTank enemyTank = enemyTanks.get(i); ///遍历敌人坦克所有子弹shots集合Vectortor for(int j=0;j<enemyTank.shots.size();j++){ //取出子弹 Shot shot = enemyTank.shots.get(j); ////判断敌人坦克子弹shot是否击中我们的hero坦克 if(hero.isLive && shot.isLive){///我们的坦克存活,敌人子弹也存活 hitTank(shot,hero); } } } } @Override public void run() { while(true){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ///判断是否击中敌人坦克 603 //这种方法只能判断当前射出的子弹击中敌人,单颗子弹//// if(hero.shot!=null && hero.shot.isLive){//当我的子弹射出(即不是空的)并且 存活// //遍历敌人所有坦克,看看哪个敌人坦克被击中/// for (int i = 0; i < enemyTanks.size(); i++) {// EnemyTank enemyTank = enemyTanks.get(i);////取出敌人坦克///// hitTank(hero.shot,enemyTank);// }// } ///调用多颗子弹击中敌人坦克 hitEnemyTank(); ////调用敌人坦克击中我们的Hero坦克方法 hitHero(); this.repaint();//面板重绘 } }}