当前位置: 代码迷 >> 综合 >> 坦克大战(Tank Battalion)------Java代码实现
  详细解决方案

坦克大战(Tank Battalion)------Java代码实现

热度:66   发布时间:2023-11-25 22:44:47.0

目录

  • 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);}});}
}
  相关解决方案