目录

  • 1.0版本
    • Java绘图
    • 具体代码:
  • 2.0版本
    • Java事件处理机制(让Tank动起来)
    • 绘制敌人的Tank
    • 代码实现
  • 3.0版本
  • 4.0版本
    • 代码:
  • 5.0版本
    • 代码
  • 6.0版本
    • 为了防止Tank重叠
    • 记录玩家的成绩
    • 记录退出游戏时敌人Tank的坐标和方向
    • 播放指定音乐
    • 最终代码

1.0版本

Java绘图

由于绘图功能比较强大实用,且内容较多,所以我决定采用链接方式。
链接地址:https://blog.csdn.net/qq_52934831/article/details/120782285

具体代码:

Tank类

package TankBattalion.TankGame01;public class Tank {private int x;private int y;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;}
}

MyTank类

package TankBattalion.TankGame01;public class MyTank extends Tank{public MyTank(int x, int y) {super(x, y);}
}

MyPanel类

package TankBattalion.TankGame01;import javax.swing.*;
import java.awt.*;//绘制Tank活动的区域
public class MyPanel extends JPanel {//定义我的TankMyTank myTank=null;public MyPanel(){myTank=new MyTank(100,100);//初始化自己的Tank}@Overridepublic void paint(Graphics g) {super.paint(g);//将画板填充,默认为黑色g.fillRect( 0,0,1000,750);drawTank(myTank.getX(),myTank.getY(), g,0,0);}//设置绘制Tank函数,需要获得Tank的初始位置,画笔g,direction坦克的方向,type敌我坦克public void drawTank(int x,int y,Graphics g,int direction,int type){switch(type){case 0://我方坦克g.setColor(Color.cyan);break;case 1://敌方坦克g.setColor(Color.yellow);break;}switch(direction){case 0://坦克朝上g.fill3DRect(x,y,10,60,false);//左履带g.fill3DRect(x+30,y,10,60,false);//右履带g.fill3DRect(x+10,y+10,20,40,false);//中间小矩形g.drawOval(x+10,y+20,20,20);//圆形炮台g.fillOval(x+10,y+20,20,20);//填补炮台g.drawLine(x+20,y,x+20,y+30);//炮管}}
}

TankGame01类

package TankBattalion.TankGame01;import javax.swing.*;
//TankGame01为了绘制出Tank
public class TankGame01 extends JFrame {private MyPanel mp=null;public static void main(String[] args) {new TankGame01();}public TankGame01(){mp=new MyPanel();this.add(mp);this.setSize(1000,750);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}
}

2.0版本

Java事件处理机制(让Tank动起来)




绘制敌人的Tank

代码实现

Tank类
p

ackage TankBattalion.TankGame02;public class Tank {private int x;private int y;private int direction;//0:向上,1向右,2向下,3向左private int speed;//控制Tank移动速度public Tank(int x, int y) {this.x = x;this.y = y;}//根据自己定义的speed控制Tank移动方法public void MoveUp() {y -= speed;}public void MoveRight() {x += speed;}public void MoveDown() {y += speed;}public void MoveLeft() {x -= speed;}public int getDirection() {return direction;}public void setDirection(int direction) {this.direction = direction;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}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;}
}

MyTank类

package TankBattalion.TankGame02;public class MyTank extends Tank {public MyTank(int x, int y) {super(x, y);}
}

EnenemyTank类

package TankBattalion.TankGame02;public class EnemyTank extends Tank{public EnemyTank(int x, int y) {super(x, y);}
}

MyPanel

package TankBattalion.TankGame02;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;//绘制Tank活动的区域
//02版本让Tank动起来以及绘制敌人的Tank
public class MyPanel extends JPanel implements KeyListener {//定义我的TankMyTank myTank = null;int EnemyTanknums=3;//为了确保线程安全使用Vector数组Vector<EnemyTank> enemyTanks=new Vector<>();public MyPanel() {myTank = new MyTank(100,100);//初始化自己的Tank//初始化Tank移动移动的速度myTank.setSpeed(3);//将敌人Tank放入vector数组for(int i=0;i<EnemyTanknums;i++){EnemyTank enemyTank=new EnemyTank(100*(i+1),0);enemyTank.setDirection(2);enemyTanks.add(enemyTank);}}@Overridepublic void paint(Graphics g) {super.paint(g);//将画板填充,默认为黑色g.fillRect(0, 0, 1000, 750);drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 0);for(int i=0;i<enemyTanks.size();i++){drawTank(enemyTanks.get(i).getX(),enemyTanks.get(i).getY(),g,enemyTanks.get(i).getDirection(),1);}}//设置绘制Tank函数,需要获得Tank的初始位置,画笔g,direction坦克的方向,type敌我坦克public void drawTank(int x, int y, Graphics g, int direction, int type) {switch (type) {case 0://我方坦克g.setColor(Color.cyan);break;case 1://敌方坦克g.setColor(Color.yellow);break;}switch (direction) {case 0: //表示向上g.fill3DRect(x, y, 10, 60, 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);//画出坦克上边轮子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);//画出坦克左边轮子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);//画出坦克上边轮子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;}}@Overridepublic void keyTyped(KeyEvent e) {}//根据键盘输入的WASD移动Tank@Overridepublic void keyPressed(KeyEvent e) {if(e.getKeyCode()==KeyEvent.VK_W){//Tank朝上myTank.setDirection(0);//Tank向上移动myTank.MoveUp();}else if(e.getKeyCode()==KeyEvent.VK_D){//Tank朝右myTank.setDirection(1);//Tank向右移动myTank.MoveRight();}else if(e.getKeyCode()==KeyEvent.VK_S){//Tank朝下myTank.setDirection(2);//Tank向下移动myTank.MoveDown();}else if(e.getKeyCode()==KeyEvent.VK_A){//Tank朝左myTank.setDirection(3);//Tank向左移动myTank.MoveLeft();}//repaint方法别忘了this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}
}

TankGame02类

package TankBattalion.TankGame02;import javax.swing.*;//TankGame02目的是为了让Tank实现朝向的改变以及移动
//以及绘制敌人的Tank
public class TankGame02 extends JFrame {private MyPanel mp = null;public static void main(String[] args) {new TankBattalion.TankGame02.TankGame02();}public TankGame02() {mp = new MyPanel();this.add(mp);this.addKeyListener(mp);//让JFrame监听mpthis.setSize(1000, 750);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}
}

3.0版本

新增功能:如何实现按J使得我们的Tank发射子弹
1.当发射一颗子弹后,就相当于启动一个线程
2. MyTank类有子弹的对象,当按下J时,我们就启动一个发射行为(线程),让子弹不停的移动,形成一个射击的效果
3.我们MyPanel需要不停的重绘,才能出现该效果.
4.当子弹移动到面板的边界时,就应该销毁

下列代码只罗列出有新增代码的类

1、新增类Bullet

package TankBattalion.TankGame03;
//3.0新增的子弹类
//将子弹看成是一个线程
public class Bullet implements Runnable{int x;int y;int directon=0;//子弹的方向,根据不同的方向,移动模式不同int speed=5;//设置子弹的速度//判断子弹线程是否已经消亡boolean isLive=true;public Bullet(int x, int y, int directon) {this.x = x;this.y = y;this.directon = directon;}@Overridepublic void run() {while(true){//子弹需要进行休眠,不然移动太快了,看不见try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//子弹不断地向规定的方向移动switch(directon){case 0://上y-=speed;break;case 1://右x+=speed;break;case 2://下y+=speed;break;case 3://左x-=speed;break;}//规定当子弹触碰到画板边界消亡if(!(x>=0&&x<=1000&&y>=0&&y<=750)){System.out.println("子弹越界消亡");isLive=false;break;//break,代表当前的子弹线程销毁}}}
}

2、MyTank类新增方法shotEnenmy()

package TankBattalion.TankGame03;public class MyTank extends Tank {//定义一个Bullet对象, 表示一个子弹(线程)Bullet bullet=null;public MyTank(int x, int y) {super(x, y);}//3.0新增//为MyTank类增加射出子弹方法public void shotEnemy(){//首先子弹需要根据MyTank炮管的位置来生成,不能乱生成switch (getDirection()){case 0://Tank朝上bullet=new Bullet(getX()+20,getY(),0);break;case 1://Tank朝右bullet=new Bullet(getX()+60,getY()+20,1);break;case 2://Tank朝下bullet=new Bullet(getX()+20,getY()+60,2);break;case 3://Tank朝左bullet=new Bullet(getX(),getY()+20,3);break;}//在这里启动bullet线程new Thread(bullet).start();}
}

3、MyPanel类paint()方法新增绘制子弹方法,以及将MyPanel当成线程不断刷新

package TankBattalion.TankGame03;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;//绘制Tank活动的区域
//02版本让Tank动起来以及绘制敌人的Tank
//03版本实现MyTank可以发射子弹,并需要让画板不断刷新,得把画板看成是一个线程,来实现能看到这个子弹
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的TankMyTank myTank = null;int EnemyTanknums = 3;//为了确保线程安全使用Vector数组Vector<EnemyTank> enemyTanks = new Vector<>();public MyPanel() {myTank = new MyTank(100, 100);//初始化自己的Tank//初始化Tank移动移动的速度myTank.setSpeed(3);//将敌人Tank放入vector数组for (int i = 0; i < EnemyTanknums; i++) {EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);enemyTank.setDirection(2);enemyTanks.add(enemyTank);}}@Overridepublic void paint(Graphics g) {super.paint(g);//将画板填充,默认为黑色g.fillRect(0, 0, 1000, 750);drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 0);//3.0新增,画出MyTank射出的子弹//为什么if()判定条件调换就错了???if (myTank.bullet != null && myTank.bullet.isLive == true) {g.drawOval(myTank.bullet.x, myTank.bullet.y, 5, 5);g.fillOval(myTank.bullet.x, myTank.bullet.y, 5, 5);}for (int i = 0; i < enemyTanks.size(); i++) {drawTank(enemyTanks.get(i).getX(), enemyTanks.get(i).getY(), g, enemyTanks.get(i).getDirection(), 1);}}//设置绘制Tank函数,需要获得Tank的初始位置,画笔g,direction坦克的方向,type敌我坦克public void drawTank(int x, int y, Graphics g, int direction, int type) {switch (type) {case 0://我方坦克g.setColor(Color.cyan);break;case 1://敌方坦克g.setColor(Color.yellow);break;}switch (direction) {case 0: //表示向上g.fill3DRect(x, y, 10, 60, 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);//画出坦克上边轮子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);//画出坦克左边轮子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);//画出坦克上边轮子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;}}@Overridepublic void keyTyped(KeyEvent e) {}//根据键盘输入的WASD移动Tank@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_W) {//Tank朝上myTank.setDirection(0);//Tank向上移动myTank.MoveUp();} else if (e.getKeyCode() == KeyEvent.VK_D) {//Tank朝右myTank.setDirection(1);//Tank向右移动myTank.MoveRight();} else if (e.getKeyCode() == KeyEvent.VK_S) {//Tank朝下myTank.setDirection(2);//Tank向下移动myTank.MoveDown();} else if (e.getKeyCode() == KeyEvent.VK_A) {//Tank朝左myTank.setDirection(3);//Tank向左移动myTank.MoveLeft();}//3.0新增用户按下J就发射子弹if (e.getKeyCode() == KeyEvent.VK_J) {//按下J键实现发射子弹myTank.shotEnemy();}//repaint方法别忘了this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}//3.0新增每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹呈现移动状态@Overridepublic void run() {//每隔100ms刷新while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}this.repaint();}}
}

4、TankGame03类新增启动MyPanel线程的方法

package TankBattalion.TankGame03;import javax.swing.*;//TankGame02目的是为了让Tank实现朝向的改变以及移动
//以及绘制敌人的Tank
public class TankGame03 extends JFrame {private MyPanel mp = null;public static void main(String[] args) {new TankGame03();}public TankGame03() {mp = new MyPanel();//3.0新增,把画板当成线程不断刷新Thread thread=new Thread(mp);thread.start();this.add(mp);this.addKeyListener(mp);//让JFrame监听mpthis.setSize(1000, 750);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}
}

4.0版本

实现新功能:
一、 让敌人的坦克也能够发射子弹(可以有多颗子弹)
1.在敌人坦克类,使用Vector保存多个Bullet
2.当每创建一个敌人坦克对象,给该敌人坦克对象初始化一个Bullet对象,同时启动Bullet
3.在绘制敌人坦克时,需要变量敌人坦克对象Vector,绘制所有的子弹,当子弹isLive == false时,就从Vector移除

二、当我方tank击中敌人tank时敌人tank消失(最好有爆炸效果)
三、 让敌人的Tank也可以只有移动
四、让Tank在指定的范围内运动

代码:

新增Bomb类

package TankBattalion.TankGame04;
//4.0新增实现Tank爆炸效果
public class Bomb {//将Bomb的vector数组放在MyPanel类中,因为只在画板上绘制它,它不属于EnemyTank或者MyTankint x;int 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;}}
}

Bullet类

package TankBattalion.TankGame04;
//3.0新增的子弹类
//将子弹看成是一个线程
public class Bullet implements Runnable{int x;int y;int directon=0;//子弹的方向,根据不同的方向,移动模式不同int speed=5;//设置子弹的速度//判断子弹线程是否已经消亡boolean isLive=true;public Bullet(int x, int y, int directon) {this.x = x;this.y = y;this.directon = directon;}@Overridepublic void run() {while(true){//子弹需要进行休眠,不然移动太快了,看不见try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//子弹不断地向规定的方向移动switch(directon){case 0://上y-=speed;break;case 1://右x+=speed;break;case 2://下y+=speed;break;case 3://左x-=speed;break;}//规定当子弹触碰到画板边界消亡//4.0新增当子弹碰到敌人Tank死亡if(!(x>=0&&x<=1000&&y>=0&&y<=750&&isLive)){System.out.println("子弹越界消亡");isLive=false;break;//break,代表当前的子弹线程销毁}}}
}

EnemyTank新增移动逻辑

package TankBattalion.TankGame04;import java.util.Vector;
//4.0新增为了让Tank随机地自由移动,需要将Tank当成一个线程
public class EnemyTank extends Tank implements Runnable{//4.0新增,在EnemyTank类中加入Vector 数组存放子弹,敌人Tank的寿命boolean isLive=true;public Vector<Bullet> bullets =new Vector<>();public EnemyTank(int x, int y) {super(x, y);}
//这里继承父类的初始速度没设置,导致Tank一直动不了@Overridepublic void run() {while (true) {//自由移动逻辑语句switch (getDirection()) {case 0://沿着当前方向继续移动30步//注意需要进行休眠,不然直接瞬移for (int i = 0; i < 30; i++) {if(getY()>0){MoveUp();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 1:for (int i = 0; i < 30; i++) {if(getX()+60<1000){MoveRight();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 2:for (int i = 0; i < 30; i++) {if(getY()+60<750){MoveDown();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 3:for (int i = 0; i < 30; i++) {if(getX()>0){MoveLeft();}                        try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;}//随机转变方法[0,4)setDirection((int) (Math.random() * 4));//优先就必须考虑什么时候退出问题if (!isLive) {break;}}}
}

MyPanel类

package TankBattalion.TankGame04;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;//绘制Tank活动的区域
//02版本让Tank动起来以及绘制敌人的Tank
//03版本实现MyTank可以发射子弹,并需要让画板不断刷新,得把画板看成是一个线程,来实现能看到这个子弹
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的TankMyTank myTank = null;int EnemyTanknums = 3;//为了确保线程安全使用Vector数组Vector<EnemyTank> enemyTanks = new Vector<>();//4.0新增炸弹数组Vector <Bomb> bombs=new Vector<>();//爆炸的三张图片Image image1=null;Image image2=null;Image image3=null;public MyPanel() {myTank = new MyTank(100, 100);//初始化自己的Tank//初始化Tank移动移动的速度myTank.setSpeed(3);//将敌人Tank放入vector数组for (int i = 0; i < EnemyTanknums; i++) {EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);enemyTank.setDirection(2);//4.0新增,在敌人Tank创建时,启动线程new Thread(enemyTank).start();//4.0新增,每绘制一个EnenmyTank就新增一个Bullet加入数组Bullet bullet = new Bullet(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());enemyTank.bullets.add(bullet);//启动bullet线程new Thread(bullet).start();enemyTanks.add(enemyTank);}//初始化图片对象image1 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_1.gif");image2 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_2.gif");image3 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_3.gif");}@Overridepublic void paint(Graphics g) {super.paint(g);//将画板填充,默认为黑色g.fillRect(0, 0, 1000, 750);drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 0);//3.0新增,画出MyTank射出的子弹//按下J键才会初始化myTank的bullet,所以需要先判定它是否为空,不然一直是false//为什么if()判定条件调换就错了???if (myTank.bullet != null && myTank.bullet.isLive == true) {g.drawOval(myTank.bullet.x, myTank.bullet.y, 5, 5);g.fillOval(myTank.bullet.x, myTank.bullet.y, 5, 5);}//在绘制敌人坦克时,需要遍历敌人坦克对象Vector,绘制所有的子弹,当子弹isLive == false时,就从Vector移除for (int i = 0; i < enemyTanks.size(); i++) {//从Vector 取出坦克EnemyTank enemyTank = enemyTanks.get(i);//4.0新增,只有当enemyTank活着时,才绘制它if (enemyTank.isLive) {drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);//画出 enemyTank 所有子弹for (int j = 0; j < enemyTank.bullets.size(); j++) {//取出子弹Bullet bullet = enemyTank.bullets.get(j);//绘制if (bullet.isLive) { //isLive == trueg.draw3DRect(bullet.x, bullet.y, 1, 1, false);} else {//从Vector 移除enemyTank.bullets.remove(bullet);}}}}//4.0新增绘制爆炸效果for(int i=0;i<bombs.size();i++){//取出炸弹Bomb bomb=bombs.get(i);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的生命值不断减少bomb.lifeDown();if(bomb.life==0){bombs.remove(bomb);}}}//设置绘制Tank函数,需要获得Tank的初始位置,画笔g,direction坦克的方向,type敌我坦克public void drawTank(int x, int y, Graphics g, int direction, int type) {switch (type) {case 0://我方坦克g.setColor(Color.cyan);break;case 1://敌方坦克g.setColor(Color.yellow);break;}switch (direction) {case 0: //表示向上g.fill3DRect(x, y, 10, 60, 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);//画出坦克上边轮子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);//画出坦克左边轮子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);//画出坦克上边轮子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;}}//4.0新增,判断子弹是否击中敌方Tankpublic  void hitTank(Bullet bullet, EnemyTank enemyTank) {//根据敌人tank方向的不同,判断子弹是否在tank的范围内switch (enemyTank.getDirection()) {case 0:case 2://上下方向是一样的if (bullet.x > enemyTank.getX() && bullet.x < enemyTank.getX() + 40&& bullet.y > enemyTank.getY() && bullet.y < enemyTank.getY() + 60) {enemyTank.isLive = false;bullet.isLive = false;//子弹消亡//别忘了将enemyTank从vector数组中拿出来,不然子弹命中Tank位置,虽然Tank消失,但是任出现爆炸效果enemyTanks.remove(enemyTank);//4.0新增根据死亡的Tank位置生成炸弹Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());bombs.add(bomb);}break;case 1:case 3://向左和向右if (bullet.x > enemyTank.getX() && bullet.x < enemyTank.getX() + 60&& bullet.y > enemyTank.getY() && bullet.y < enemyTank.getY() + 40) {enemyTank.isLive = false;bullet.isLive = false;enemyTanks.remove(enemyTank);Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());bombs.add(bomb);}break;}}@Overridepublic void keyTyped(KeyEvent e) {}//根据键盘输入的WASD移动Tank@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_W) {//Tank朝上myTank.setDirection(0);//Tank向上移动if(myTank.getY()>0)myTank.MoveUp();} else if (e.getKeyCode() == KeyEvent.VK_D) {//Tank朝右myTank.setDirection(1);//Tank向右移动if(myTank.getX()+60<1000)myTank.MoveRight();} else if (e.getKeyCode() == KeyEvent.VK_S) {//Tank朝下myTank.setDirection(2);//Tank向下移动if(myTank.getY()+60<750)myTank.MoveDown();} else if (e.getKeyCode() == KeyEvent.VK_A) {//Tank朝左myTank.setDirection(3);//Tank向左移动if(myTank.getX()>0)myTank.MoveLeft();}//3.0新增用户按下J就发射子弹if (e.getKeyCode() == KeyEvent.VK_J) {//按下J键实现发射子弹myTank.shotEnemy();}//repaint方法别忘了this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}//3.0新增每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹呈现移动状态//4.0新增在刷新途中不断判断子弹是否命中敌人Tank@Overridepublic void run() {//每隔100ms刷新while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//按下J键才会初始化myTank的bullet,所以需要先判定它是否为空,不然一直是falseif (myTank.bullet != null && myTank.bullet.isLive) {for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank tank = enemyTanks.get(i);//遍历Enemy数组,看子弹是否命中其中一只hitTank(myTank.bullet, tank);}}this.repaint();}}
}

Tank、MyTank、TankGame04类未发生改动,此处不再赘述

5.0版本

一、首先实现MyTank在原有子弹消亡后才可以发射新子弹的功能
接着近一步实现可以发射多颗子弹的功能
线程消亡不代表MyTank.bullet就置空

二、让敌人Tank可以发射多枚子弹且子弹最多为5枚
注意点:这里一定要规定在EnemyTank存活的条件下才可以发射子弹,不然死了还能发射子弹

代码

EnemyTank新增发射多颗子弹功能

package TankBattalion.TankGame04;import java.util.Vector;
//4.0新增为了让Tank随机地自由移动,需要将Tank当成一个线程
public class EnemyTank extends Tank implements Runnable{//4.0新增,在EnemyTank类中加入Vector 数组存放子弹,敌人Tank的寿命boolean isLive=true;Bullet bullet=null;public Vector<Bullet> bullets =new Vector<>();public EnemyTank(int x, int y) {super(x, y);}
//这里继承父类的初始速度没设置,导致Tank一直动不了@Overridepublic void run() {while (true) {//5.0新增敌人Tank可以发射多枚子弹//注意一定是Tank存活的条件下if(isLive&&bullets.size()<5){switch (getDirection()){case 0://Tank朝上bullet=new Bullet(getX()+20,getY(),0);break;case 1://Tank朝右bullet=new Bullet(getX()+60,getY()+20,1);break;case 2://Tank朝下bullet=new Bullet(getX()+20,getY()+60,2);break;case 3://Tank朝左bullet=new Bullet(getX(),getY()+20,3);break;}//记得将子弹加入数组,并且启动子弹线程bullets.add(bullet);new Thread(bullet).start();}//自由移动逻辑语句switch (getDirection()) {case 0://沿着当前方向继续移动30步//注意需要进行休眠,不然直接瞬移for (int i = 0; i < 30; i++) {if(getY()>0){MoveUp();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 1:for (int i = 0; i < 30; i++) {if(getX()+60<1000){MoveRight();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 2:for (int i = 0; i < 30; i++) {if(getY()+60<750){MoveDown();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 3:for (int i = 0; i < 30; i++) {if(getX()>0){MoveLeft();}                        try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;}//随机转变方法[0,4)setDirection((int) (Math.random() * 4));//优先就必须考虑什么时候退出问题if (!isLive) {break;}}}
}

MyPanel类

package TankBattalion.TankGame04;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;//绘制Tank活动的区域
//02版本让Tank动起来以及绘制敌人的Tank
//03版本实现MyTank可以发射子弹,并需要让画板不断刷新,得把画板看成是一个线程,来实现能看到这个子弹
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的TankMyTank myTank = null;int EnemyTanknums = 3;//为了确保线程安全使用Vector数组Vector<EnemyTank> enemyTanks = new Vector<>();//4.0新增炸弹数组Vector<Bomb> bombs = new Vector<>();//爆炸的三张图片Image image1 = null;Image image2 = null;Image image3 = null;public MyPanel() {myTank = new MyTank(100, 100);//初始化自己的Tank//初始化Tank移动移动的速度myTank.setSpeed(3);//将敌人Tank放入vector数组for (int i = 0; i < EnemyTanknums; i++) {EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);enemyTank.setDirection(2);//4.0新增,在敌人Tank创建时,启动线程new Thread(enemyTank).start();//5.0新增这里Tank设计逻辑太呆了出生时就发射子弹,且与Tank出生方向一致,应该做到随机
//            //4.0新增,每绘制一个EnenmyTank就新增一个Bullet加入数组
//            Bullet bullet = new Bullet(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
//            enemyTank.bullets.add(bullet);
//            //启动bullet线程
//            new Thread(bullet).start();enemyTanks.add(enemyTank);}//初始化图片对象image1 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_1.gif");image2 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_2.gif");image3 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_3.gif");}@Overridepublic void paint(Graphics g) {super.paint(g);//将画板填充,默认为黑色g.fillRect(0, 0, 1000, 750);if (myTank.isLive) {drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 0);}//3.0新增,画出MyTank射出的子弹//按下J键才会初始化myTank的bullet,所以需要先判定它是否为空,不然一直是false//为什么if()判定条件调换就错了???//5.0新增绘制多枚子弹for (int i = 0; i < myTank.bullets.size(); i++) {Bullet bullet = myTank.bullets.get(i);if (bullet != null && bullet.isLive == true) {g.drawOval(bullet.x, bullet.y, 5, 5);g.fillOval(bullet.x, bullet.y, 5, 5);}//别忘了将已经消亡的子弹从bullets数组中取出,不然一只Tank一辈子只能打5发子弹else {myTank.bullets.remove(bullet);}}//在绘制敌人坦克时,需要遍历敌人坦克对象Vector,绘制所有的子弹,当子弹isLive == false时,就从Vector移除for (int i = 0; i < enemyTanks.size(); i++) {//从Vector 取出坦克EnemyTank enemyTank = enemyTanks.get(i);//4.0新增,只有当enemyTank活着时,才绘制它if (enemyTank.isLive) {drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);//5.0新增,画出 enemyTank 所有子弹for (int j = 0; j < enemyTank.bullets.size(); j++) {//取出子弹Bullet bullet = enemyTank.bullets.get(j);//绘制if (bullet.isLive) { //isLive == trueg.draw3DRect(bullet.x, bullet.y, 1, 1, false);} else {//从Vector 移除enemyTank.bullets.remove(bullet);}}}}//4.0新增绘制爆炸效果for (int i = 0; i < bombs.size(); i++) {//取出炸弹Bomb bomb = bombs.get(i);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的生命值不断减少bomb.lifeDown();if (bomb.life == 0) {bombs.remove(bomb);}}}//设置绘制Tank函数,需要获得Tank的初始位置,画笔g,direction坦克的方向,type敌我坦克public void drawTank(int x, int y, Graphics g, int direction, int type) {switch (type) {case 0://我方坦克g.setColor(Color.cyan);break;case 1://敌方坦克g.setColor(Color.yellow);break;}switch (direction) {case 0: //表示向上g.fill3DRect(x, y, 10, 60, 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);//画出坦克上边轮子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);//画出坦克左边轮子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);//画出坦克上边轮子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;}}//4.0新增,判断子弹是否击中Tank//5.0将原本的参数EnemyTank enemyTank 改为Tank tank,这样就可以写hitMyTank和hitEnemyTank方法了public void hitTank(Bullet bullet, Tank tank) {//根据敌人tank方向的不同,判断子弹是否在tank的范围内switch (tank.getDirection()) {case 0:case 2://上下方向是一样的if (bullet.x > tank.getX() && bullet.x < tank.getX() + 40&& bullet.y > tank.getY() && bullet.y < tank.getY() + 60) {tank.isLive = false;bullet.isLive = false;//子弹消亡//别忘了将enemyTank从vector数组中拿出来,不然子弹命中Tank位置,虽然Tank消失,但是任出现爆炸效果enemyTanks.remove(tank);//4.0新增根据死亡的Tank位置生成炸弹Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;case 1:case 3://向左和向右if (bullet.x > tank.getX() && bullet.x < tank.getX() + 60&& bullet.y > tank.getY() && bullet.y < tank.getY() + 40) {tank.isLive = false;bullet.isLive = false;enemyTanks.remove(tank);Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;}}//5.0新增因为原方法是取出单独的子弹与enemyTank集合中的所有Tank一一比较,判断有没有命中//这样设计,现在可以发射多枚子弹,容易产生bullets集合中的一枚子弹击中了Tank,但没有爆炸的BUG//解决方案是将bullets集合中所有子弹取出与enemyTank中所有Tank一一比较public void hitEnemyTank() {//        //单颗子弹
//        if (myTank.bullet != null && myTank.bullet.isLive) {//            for (int i = 0; i < enemyTanks.size(); i++) {//                EnemyTank tank = enemyTanks.get(i);
//                //遍历Enemy数组,看子弹是否命中其中一只
//                hitTank(myTank.bullet, tank);
//            }
//
//        }//多颗子弹for (int i = 0; i < myTank.bullets.size(); i++) {Bullet bullet = myTank.bullets.get(i);if (bullet != null && bullet.isLive) {for (int j = 0; j < enemyTanks.size(); j++) {EnemyTank tank = enemyTanks.get(j);//遍历Enemy数组,看子弹是否命中其中一只hitTank(bullet, tank);}}}}public void hitMyTank() {for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);for (int j = 0; j < enemyTank.bullets.size(); j++) {Bullet bullet = enemyTank.bullets.get(j);if (myTank.isLive&&bullet != null && bullet.isLive) {hitTank(bullet, myTank);}}}}@Overridepublic void keyTyped(KeyEvent e) {}//根据键盘输入的WASD移动Tank@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_W) {//Tank朝上myTank.setDirection(0);//Tank向上移动if (myTank.getY() > 0)myTank.MoveUp();} else if (e.getKeyCode() == KeyEvent.VK_D) {//Tank朝右myTank.setDirection(1);//Tank向右移动if (myTank.getX() + 60 < 1000)myTank.MoveRight();} else if (e.getKeyCode() == KeyEvent.VK_S) {//Tank朝下myTank.setDirection(2);//Tank向下移动if (myTank.getY() + 60 < 750)myTank.MoveDown();} else if (e.getKeyCode() == KeyEvent.VK_A) {//Tank朝左myTank.setDirection(3);//Tank向左移动if (myTank.getX() > 0)myTank.MoveLeft();}//3.0新增用户按下J就发射子弹if (e.getKeyCode() == KeyEvent.VK_J) {//按下J键实现发射子弹myTank.shotEnemy();}//repaint方法别忘了this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}//3.0新增每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹呈现移动状态//4.0新增在刷新途中不断判断子弹是否命中敌人Tank@Overridepublic void run() {//每隔100ms刷新while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}hitEnemyTank();hitMyTank();this.repaint();}}
}

MyTank类新增发射多颗子弹功能

package TankBattalion.TankGame04;import java.util.Vector;public class MyTank extends Tank {//5.0新增功能让MyTank可以发射多枚子弹,并且限定为5颗Vector<Bullet> bullets= new Vector<>();//定义一个Bullet对象, 表示一个子弹(线程)Bullet bullet=null;public MyTank(int x, int y) {super(x, y);}//3.0新增//为MyTank类增加射出子弹方法public void shotEnemy(){//限定5颗子弹,子弹数目过5就不再newif(bullets.size()==5){return ;}//首先子弹需要根据MyTank炮管的位置来生成,不能乱生成switch (getDirection()){case 0://Tank朝上bullet=new Bullet(getX()+20,getY(),0);break;case 1://Tank朝右bullet=new Bullet(getX()+60,getY()+20,1);break;case 2://Tank朝下bullet=new Bullet(getX()+20,getY()+60,2);break;case 3://Tank朝左bullet=new Bullet(getX(),getY()+20,3);break;}//5.0新增将新生成的Bullet加入vector数组bullets.add(bullet);//在这里启动bullet线程new Thread(bullet).start();}
}

其余类不变

6.0版本

新增功能:
1.防止敌人坦克重叠运动
2.记录玩家的成绩,存盘退出【io流】
3.记录当时的敌人坦克坐标,存盘退出【io流】
4、玩游戏时,可以选择是开新游戏还是继续上局游戏

为了防止Tank重叠

可以将其分为以下八种情况

记录玩家的成绩

记录退出游戏时敌人Tank的坐标和方向

播放指定音乐

最终代码

AePlayWave类

package TankBattalion.TankGame06;import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
//6.0新增播放音乐功能
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();}}
}

Bomb类

package TankBattalion.TankGame06;
//4.0新增实现Tank爆炸效果
public class Bomb {//将Bomb的vector数组放在MyPanel类中,因为只在画板上绘制它,它不属于EnemyTank或者MyTankint x;int 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;}}
}

Bullet类

package TankBattalion.TankGame06;
//3.0新增的子弹类
//将子弹看成是一个线程
public class Bullet implements Runnable{int x;int y;int directon=0;//子弹的方向,根据不同的方向,移动模式不同int speed=5;//设置子弹的速度//判断子弹线程是否已经消亡boolean isLive=true;public Bullet(int x, int y, int directon) {this.x = x;this.y = y;this.directon = directon;}@Overridepublic void run() {while(true){//子弹需要进行休眠,不然移动太快了,看不见try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//子弹不断地向规定的方向移动switch(directon){case 0://上y-=speed;break;case 1://右x+=speed;break;case 2://下y+=speed;break;case 3://左x-=speed;break;}//规定当子弹触碰到画板边界消亡//4.0新增当子弹碰到敌人Tank死亡if(!(x>=0&&x<=1000&&y>=0&&y<=750&&isLive)){System.out.println("子弹越界消亡");isLive=false;break;//break,代表当前的子弹线程销毁}}}
}

EnemyTank类

package TankBattalion.TankGame06;import java.util.Vector;//4.0新增为了让Tank随机地自由移动,需要将Tank当成一个线程
public class EnemyTank extends Tank implements Runnable {//4.0新增,在EnemyTank类中加入Vector 数组存放子弹,敌人Tank的寿命boolean isLive = true;Bullet bullet = null;public Vector<Bullet> bullets = new Vector<>();public EnemyTank(int x, int y) {super(x, y);}public Vector<EnemyTank> enemyTanks = new Vector<>();//6.0新增功能实现EnemyTank无法出现重叠状况//为了让敌人Tank和Vector集合中其他敌人Tank进行坐标比较需要获取创建的Vector enemyTank集合,// 这里定义一个方法,在MyPanel中使用,创建一个敌人Tank就调用一次该方法public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {this.enemyTanks = enemyTanks;}//判断是否碰撞的方法public boolean isTouchEnemyTank() {//判断当前敌人坦克(this) 方向switch (this.getDirection()) {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.getDirection() == 0 || enemyTank.getDirection() == 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.getDirection() == 1 || enemyTank.getDirection() == 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.getDirection() == 0 || enemyTank.getDirection() == 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.getDirection() == 1 || enemyTank.getDirection() == 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.getDirection() == 0 || enemyTank.getDirection() == 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.getDirection() == 1 || enemyTank.getDirection() == 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.getDirection() == 0 || enemyTank.getDirection() == 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.getDirection() == 1 || enemyTank.getDirection() == 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;}//这里继承父类的初始速度没设置,导致Tank一直动不了@Overridepublic void run() {while (true) {//5.0新增敌人Tank可以发射多枚子弹//注意一定是Tank存活的条件下if (isLive && bullets.size() < 5) {switch (getDirection()) {case 0://Tank朝上bullet = new Bullet(getX() + 20, getY(), 0);break;case 1://Tank朝右bullet = new Bullet(getX() + 60, getY() + 20, 1);break;case 2://Tank朝下bullet = new Bullet(getX() + 20, getY() + 60, 2);break;case 3://Tank朝左bullet = new Bullet(getX(), getY() + 20, 3);break;}//记得将子弹加入数组,并且启动子弹线程bullets.add(bullet);new Thread(bullet).start();}//自由移动逻辑语句//6.0新增在不碰撞敌人Tank的基础上才能继续移动switch (getDirection()) {case 0://沿着当前方向继续移动30步//注意需要进行休眠,不然直接瞬移for (int i = 0; i < 30; i++) {if (getY() > 0 && !isTouchEnemyTank()) {MoveUp();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 1:for (int i = 0; i < 30; i++) {if (getX() + 60 < 1000 && !isTouchEnemyTank()) {MoveRight();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 2:for (int i = 0; i < 30; i++) {if (getY() + 60 < 750 && !isTouchEnemyTank()) {MoveDown();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 3:for (int i = 0; i < 30; i++) {if (getX() > 0 && !isTouchEnemyTank()) {MoveLeft();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;}//随机转变方法[0,4)setDirection((int) (Math.random() * 4));//优先就必须考虑什么时候退出问题if (!isLive) {break;}}}
}

MyPanel类

package TankBattalion.TankGame06;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;//绘制Tank活动的区域
//02版本让Tank动起来以及绘制敌人的Tank
//03版本实现MyTank可以发射子弹,并需要让画板不断刷新,得把画板看成是一个线程,来实现能看到这个子弹
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的TankMyTank myTank = null;int EnemyTanknums = 3;//为了确保线程安全使用Vector数组Vector<EnemyTank> enemyTanks = new Vector<>();//6.0定义node集合接受信息Vector<Node> node=null;//4.0新增炸弹数组Vector<Bomb> bombs = new Vector<>();//爆炸的三张图片Image image1 = null;Image image2 = null;Image image3 = null;//6.0定义MyPanel(String Key)方法定义按照上局信息生成对战的方法public MyPanel(String Key) {//6.0定义node接受上局的Tank信息node=Recorder.getNodeAndhitnums();//6.0将Mypanel类的enemyTanks传给Recorder类Recorder.setEnemyTanks(enemyTanks);myTank = new MyTank(800, 100);//初始化自己的Tank//初始化Tank移动移动的速度myTank.setSpeed(3);switch (Key) {case "1"://重新开始//将敌人Tank放入vector数组for (int i = 0; i < EnemyTanknums; i++) {EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);//6.0新增每创建一个enemyTank对象,就调用setEnemyTanks方法给新创建的Tank对象传递Vector enemyTanks集合enemyTank.setEnemyTanks(enemyTanks);enemyTank.setDirection(2);//4.0新增,在敌人Tank创建时,启动线程new Thread(enemyTank).start();//5.0新增这里Tank设计逻辑太呆了出生时就发射子弹,且与Tank出生方向一致,应该做到随机
//            //4.0新增,每绘制一个EnenmyTank就新增一个Bullet加入数组
//            Bullet bullet = new Bullet(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
//            enemyTank.bullets.add(bullet);
//            //启动bullet线程
//            new Thread(bullet).start();enemyTanks.add(enemyTank);}break;case "2"://继续上把//初始化敌人坦克for (int i = 0; i < node.size(); i++) {Node n = node.get(i);//创建一个敌人的坦克EnemyTank enemyTank = new EnemyTank(n.getX(), n.getY());//将enemyTanks 设置给 enemyTank !!!enemyTank.setEnemyTanks(enemyTanks);//设置方向enemyTank.setDirection(n.getDirection());//启动敌人坦克线程,让他动起来new Thread(enemyTank).start();//给该enemyTank 加入一颗子弹Bullet shot = new Bullet(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());//加入enemyTank的Vector 成员enemyTank.bullets.add(shot);//启动 shot 对象new Thread(shot).start();//加入enemyTanks.add(enemyTank);}break;}//初始化图片对象image1 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_1.gif");image2 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_2.gif");image3 = Toolkit.getDefaultToolkit().getImage("E:\\Java\\notebook\\out\\production\\bomb_3.gif");//6.0新增播放音乐功能String musicfilename="E:\\Java\\notebook\\src\\TankBattalion\\111.wav";new AePlayWave(musicfilename).start();}//6.0编写记录玩家总成绩的方法public void record(Graphics g){g.setColor(Color.black);g.setFont(new Font("宋体",Font.BOLD,30));g.drawString("您累积击毁敌方坦克",1020,30);//绘制一个敌人Tank图形drawTank(1020,60,g,0,1);//绘制击败Tank数目g.setColor(Color.black);g.drawString(Recorder.getHitnums()+"",1080,100);}@Overridepublic void paint(Graphics g) {super.paint(g);//将画板填充,默认为黑色g.fillRect(0, 0, 1000, 750);record(g);if (myTank.isLive) {drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 0);}//3.0新增,画出MyTank射出的子弹//按下J键才会初始化myTank的bullet,所以需要先判定它是否为空,不然一直是false//为什么if()判定条件调换就错了???//5.0新增绘制多枚子弹for (int i = 0; i < myTank.bullets.size(); i++) {Bullet bullet = myTank.bullets.get(i);if (bullet != null && bullet.isLive == true) {g.drawOval(bullet.x, bullet.y, 5, 5);g.fillOval(bullet.x, bullet.y, 5, 5);}//别忘了将已经消亡的子弹从bullets数组中取出,不然一只Tank一辈子只能打5发子弹else {myTank.bullets.remove(bullet);}}//在绘制敌人坦克时,需要遍历敌人坦克对象Vector,绘制所有的子弹,当子弹isLive == false时,就从Vector移除for (int i = 0; i < enemyTanks.size(); i++) {//从Vector 取出坦克EnemyTank enemyTank = enemyTanks.get(i);//4.0新增,只有当enemyTank活着时,才绘制它if (enemyTank.isLive) {drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);//5.0新增,画出 enemyTank 所有子弹for (int j = 0; j < enemyTank.bullets.size(); j++) {//取出子弹Bullet bullet = enemyTank.bullets.get(j);//绘制if (bullet.isLive) { //isLive == trueg.draw3DRect(bullet.x, bullet.y, 1, 1, false);} else {//从Vector 移除enemyTank.bullets.remove(bullet);}}}}//4.0新增绘制爆炸效果for (int i = 0; i < bombs.size(); i++) {//取出炸弹Bomb bomb = bombs.get(i);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的生命值不断减少bomb.lifeDown();if (bomb.life == 0) {bombs.remove(bomb);}}}//设置绘制Tank函数,需要获得Tank的初始位置,画笔g,direction坦克的方向,type敌我坦克public void drawTank(int x, int y, Graphics g, int direction, int type) {switch (type) {case 0://我方坦克g.setColor(Color.cyan);break;case 1://敌方坦克g.setColor(Color.yellow);break;}switch (direction) {case 0: //表示向上g.fill3DRect(x, y, 10, 60, 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);//画出坦克上边轮子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);//画出坦克左边轮子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);//画出坦克上边轮子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;}}//4.0新增,判断子弹是否击中Tank//5.0将原本的参数EnemyTank enemyTank 改为Tank tank,这样就可以写hitMyTank和hitEnemyTank方法了public void hitTank(Bullet bullet, Tank tank) {//根据敌人tank方向的不同,判断子弹是否在tank的范围内switch (tank.getDirection()) {case 0:case 2://上下方向是一样的if (bullet.x > tank.getX() && bullet.x < tank.getX() + 40&& bullet.y > tank.getY() && bullet.y < tank.getY() + 60) {tank.isLive = false;bullet.isLive = false;//子弹消亡//6.0新增假如击中的不是我方Tank,hitnums++if(tank instanceof EnemyTank) {Recorder.addAllEnemyTankNum();}//别忘了将enemyTank从vector数组中拿出来,不然子弹命中Tank位置,虽然Tank消失,但是任出现爆炸效果enemyTanks.remove(tank);//4.0新增根据死亡的Tank位置生成炸弹Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;case 1:case 3://向左和向右if (bullet.x > tank.getX() && bullet.x < tank.getX() + 60&& bullet.y > tank.getY() && bullet.y < tank.getY() + 40) {tank.isLive = false;bullet.isLive = false;//6.0新增假如击中的不是我方Tank,hitnums++if(tank instanceof EnemyTank) {Recorder.addAllEnemyTankNum();}enemyTanks.remove(tank);Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;}}//5.0新增因为原方法是取出单独的子弹与enemyTank集合中的所有Tank一一比较,判断有没有命中//这样设计,现在可以发射多枚子弹,容易产生bullets集合中的一枚子弹击中了Tank,但没有爆炸的BUG//解决方案是将bullets集合中所有子弹取出与enemyTank中所有Tank一一比较public void hitEnemyTank() {//        //单颗子弹
//        if (myTank.bullet != null && myTank.bullet.isLive) {//            for (int i = 0; i < enemyTanks.size(); i++) {//                EnemyTank tank = enemyTanks.get(i);
//                //遍历Enemy数组,看子弹是否命中其中一只
//                hitTank(myTank.bullet, tank);
//            }
//
//        }//多颗子弹for (int i = 0; i < myTank.bullets.size(); i++) {Bullet bullet = myTank.bullets.get(i);if (bullet != null && bullet.isLive) {for (int j = 0; j < enemyTanks.size(); j++) {EnemyTank tank = enemyTanks.get(j);//遍历Enemy数组,看子弹是否命中其中一只hitTank(bullet, tank);}}}}public void hitMyTank() {for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);for (int j = 0; j < enemyTank.bullets.size(); j++) {Bullet bullet = enemyTank.bullets.get(j);if (myTank.isLive && bullet != null && bullet.isLive) {hitTank(bullet, myTank);}}}}@Overridepublic void keyTyped(KeyEvent e) {}//根据键盘输入的WASD移动Tank@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_W) {//Tank朝上myTank.setDirection(0);//Tank向上移动if (myTank.getY() > 0)myTank.MoveUp();} else if (e.getKeyCode() == KeyEvent.VK_D) {//Tank朝右myTank.setDirection(1);//Tank向右移动if (myTank.getX() + 60 < 1000)myTank.MoveRight();} else if (e.getKeyCode() == KeyEvent.VK_S) {//Tank朝下myTank.setDirection(2);//Tank向下移动if (myTank.getY() + 60 < 750)myTank.MoveDown();} else if (e.getKeyCode() == KeyEvent.VK_A) {//Tank朝左myTank.setDirection(3);//Tank向左移动if (myTank.getX() > 0)myTank.MoveLeft();}//3.0新增用户按下J就发射子弹if (e.getKeyCode() == KeyEvent.VK_J) {//按下J键实现发射子弹myTank.shotEnemy();}//repaint方法别忘了this.repaint();}@Overridepublic void keyReleased(KeyEvent e) {}//3.0新增每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹呈现移动状态//4.0新增在刷新途中不断判断子弹是否命中敌人Tank@Overridepublic void run() {//每隔100ms刷新while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}hitEnemyTank();hitMyTank();this.repaint();}}
}

MyTank类

package TankBattalion.TankGame06;import java.util.Vector;public class MyTank extends Tank {//5.0新增功能让MyTank可以发射多枚子弹,并且限定为5颗Vector<Bullet> bullets= new Vector<>();//定义一个Bullet对象, 表示一个子弹(线程)Bullet bullet=null;public MyTank(int x, int y) {super(x, y);}//3.0新增//为MyTank类增加射出子弹方法public void shotEnemy(){//限定5颗子弹,子弹数目过5就不再newif(bullets.size()==5){return ;}//首先子弹需要根据MyTank炮管的位置来生成,不能乱生成switch (getDirection()){case 0://Tank朝上bullet=new Bullet(getX()+20,getY(),0);break;case 1://Tank朝右bullet=new Bullet(getX()+60,getY()+20,1);break;case 2://Tank朝下bullet=new Bullet(getX()+20,getY()+60,2);break;case 3://Tank朝左bullet=new Bullet(getX(),getY()+20,3);break;}//5.0新增将新生成的Bullet加入vector数组bullets.add(bullet);//在这里启动bullet线程new Thread(bullet).start();}
}

Node类

package TankBattalion.TankGame06;public class Node {int x;int y;int direction;public Node(int x, int y, int direction) {this.x = x;this.y = y;this.direction = direction;}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 getDirection() {return direction;}public void setDirection(int direction) {this.direction = direction;}
}

Recorder类

package TankBattalion.TankGame06;import java.io.*;
import java.util.Vector;public class Recorder {//用于保存我方击败Tank数量//在关闭界面后将数据保存private static int hitnums=0;private static BufferedWriter bfw=null;private static BufferedReader bfr=null;private static String filename="E:\\Java\\notebook\\src\\record.txt";public static int getHitnums() {return hitnums;}//6.0设置关闭窗口可以保存数据的方法//设计关闭窗口后记录退出时敌人Tank的位置和方向,要求获取Vector enemyTanksprivate static Vector<EnemyTank> enemyTanks=null;//node用来存放Tank的位置和方向private static Vector<Node> node=new Vector<>();public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {Recorder.enemyTanks = enemyTanks;}//增加一个方法返回node集合和hitnumspublic static Vector<Node> getNodeAndhitnums(){try {bfr = new BufferedReader(new FileReader(filename));hitnums = Integer.parseInt(bfr.readLine());//循环读取文件,生成nodes 集合String line = "";//255 40 0while ((line = bfr.readLine()) != null) {String[] xyd = line.split(" ");Node n = new Node(Integer.parseInt(xyd[0]), Integer.parseInt(xyd[1]),Integer.parseInt(xyd[2]));node.add(n);//放入nodes Vector}} catch (IOException e) {e.printStackTrace();} finally {if(bfr!=null){try {bfr.close();} catch (IOException e) {e.printStackTrace();}}}return node;}public static void keepRecord(){try {bfw=new BufferedWriter(new FileWriter(filename));bfw.write(hitnums+"");bfw.newLine();//6.0将Tank信息存入文档for(int i=0;i<enemyTanks.size();i++){EnemyTank enemyTank = enemyTanks.get(i);bfw.write(enemyTank.getX()+" "+enemyTank.getY()+" "+enemyTank.getDirection());bfw.newLine();}} catch (IOException e) {e.printStackTrace();} finally {if(bfw!=null){try {bfw.close();} catch (IOException e) {e.printStackTrace();}}}}public static void setHitnums(int hitnums) {Recorder.hitnums = hitnums;}//当我方坦克击毁一个敌人坦克,就应当 allEnemyTankNum++public static void addAllEnemyTankNum() {Recorder.hitnums++;}
}

Tank类

package TankBattalion.TankGame06;public class Tank {private int x;private int y;private int direction;//0:向上,1向右,2向下,3向左private int speed=3;//控制Tank移动速度public boolean isLive=true;public Tank(int x, int y) {this.x = x;this.y = y;}//根据自己定义的speed控制Tank移动方法public void MoveUp() {y -= speed;}public void MoveRight() {x += speed;}public void MoveDown() {y += speed;}public void MoveLeft() {x -= speed;}public int getDirection() {return direction;}public void setDirection(int direction) {this.direction = direction;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}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;}
}

TankGame06类

package TankBattalion.TankGame06;import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;//TankGame02目的是为了让Tank实现朝向的改变以及移动
//以及绘制敌人的Tank
public class TankGame06 extends JFrame {private MyPanel mp = null;public static void main(String[] args) {new TankGame06();}public TankGame06() {Scanner scanner = new Scanner(System.in);System.out.println("输入1:重新开始,输入2:继续上把");String choice =scanner.next();mp = new MyPanel(choice);//3.0新增,把画板当成线程不断刷新Thread thread=new Thread(mp);thread.start();this.add(mp);this.addKeyListener(mp);//让JFrame监听mpthis.setSize(1350, 750);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);//6.0在JFrame中增加能响应关闭窗口的方法this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {Recorder.keepRecord();System.exit(0);}});}
}

坦克大战(Tank Battalion)------Java代码实现相关推荐

  1. java坦克大战 实训报告_坦克大战系统《Java程序开发实训》综合实训报告.doc

    坦克大战系统<Java程序开发实训>综合实训报告 <Java程序开发实训>综合实训报告 题目: 坦克大战系统 姓名: 方庆 学号: 2010203206 班级: 10软件(2) ...

  2. Java编写坦克大战-Tank类+Bot类+Blast类

    Tank类 package com.learn.exercise.tanke;import com.learn.exercise.tanke.Direction;import java.awt.*; ...

  3. java坦克大战登录界面设计_基于JAVA的坦克大战设计和实现-代码.doc

    JISHOU UNIVERSITY 本科生毕业设计 题 目:基于JAVA的坦克大战设计与实现作 者:学 号:所属学院:专业年级:指导教师:职 称:完成时间:2012年5月7日 吉首大学 基于JAVA的 ...

  4. python 全解坦克大战 辅助类 附完整代码【雏形】

    我正在博客之星评选,欢迎投票给我 会从投票人中抽奖机械键盘+书,中了会私聊地址 投票连接是:https://bbs.csdn.net/topics/603955346 投票连接是:https://bb ...

  5. 手把手教你用Python实现“坦克大战”,附详细代码!

    小时候玩的"坦克大战",你还记得吗? 满满的回忆 ! 今天,我们使用Python以及强大的第三方库来实现一个简单的坦克大战游戏. 整体效果 环境依赖 python3.7 pygam ...

  6. 《HTML5经典坦克大战》游戏(代码)

    前几天粗略地学了HTML5,然后就用它写了一个<经典坦克大战>游戏. 现在想分享一下我写的代码,写得不好请大家多多指教. 给大家推荐一个网站,这个网站是为大学生而做,为方便学习编程的同学而 ...

  7. 坦克大战项目c语言代码,c语言 坦克大战 游戏源码下载

    [实例简介]坦克大战  C语言  源代码 [实例截图] [核心代码] void GamePlay()/*玩游戏的过程*/ { int i,j,lose=0;/*lose是1的时候表示失败*/ int ...

  8. java 坦克大战 教程_[Java教程]坦克大战(一)

    [Java教程]坦克大战(一) 0 2016-09-16 08:00:05 坦克大战(一) 相信大家对坦克大战都不陌生,并且网上也有很多用java实现的小程序,最近用了几天时间将其使用javaScri ...

  9. java 坦克大战_基于JAVA实现的坦克大战游戏

    一.课程题目 实现一个java版本的坦克大战游戏. 功能提示: 游戏要有图形用户界面,界面能够反映游戏所有的细节 界面中要有坦克,墙,树林,河流 界面中要有一个"家"," ...

最新文章

  1. 使用Opencv构建一个简单的图像相似检测器(MSE、SSIM)
  2. 别跟我说测试的坏话...
  3. 链表有环是什么意思_互联网大厂offer收割之单向链表的概念及面试题大全
  4. CommonDialog控件
  5. 防止在多模块Maven中找到“未找到插件”
  6. www,android18x.com,Android 11 LineageOS 18.1系统
  7. 计算机算法设计与分析 数字三角形
  8. NIPS风波 | 获奖者登台开炮:ML是炼金术,大神LeCun强硬回怼
  9. linux 分析系统配置,在Linux系统上部署AWStats日志分析系统
  10. [算法]在数组中找到一个局部最小的位置
  11. 用例图分析---学生成绩管理系统
  12. ssh无密码登录原理和配置方法
  13. 求职:本人从事3年工作流引擎开发,熟悉XPDL,.net3.5中WF,Biztalk,开源工作流引擎OBE,期望工作地点上海...
  14. FFmpeg获取视频旋转角度rotate获取不到的问题解决
  15. wifi文件服务器地址,wifi是服务器地址
  16. RN新架构 JSI 介绍
  17. 网上在线培训平台哪家好?
  18. 丢失LDF文件怎么办?
  19. Ps 如何制作网格背景
  20. 腾讯视频qlv获取办法

热门文章

  1. html购物页面产品展示,html5 3D交互式房间购物商品展示特效
  2. win7与VMware/VBox下linux共享文件夹方法
  3. 宝塔面板安全入口登录问题
  4. 爱因斯坦论宗教与自然科学的关系
  5. Dynamic CRM 2016 IFD配置(1)证书颁发机构配置
  6. java转行失败_转行学JAVA,成功和失败的原因
  7. 时间复杂度 O(1),O(n),O(n^2),O(logn),O(nlogn) 详解
  8. 深度学习环境配置:ubuntu 16.04 安装2080ti驱动 cuda9.0和cudnn7.3 anaconda3.7 tensorflow12.0
  9. 机器学习实战——2.3 示例:手写识别系统
  10. cgcs2000大地坐标系地图_我国大地坐标系_地图与地图制图