day06-IO流应用01

Java坦克大战06

8.IO流应用01

坦克大战6.0版

增加功能:

  1. 防止敌人坦克重叠运动
  2. 记录玩家的成绩(累计击毁坦克数),存盘退出
  3. 记录当时的敌人坦克坐标,存盘退出
  4. 玩游戏时,可以选择是开新游戏还是继续上局游戏

8.1防止敌人坦克重叠运动

8.1.1思路分析

按照目标坦克的向右下左四种情况分析,每一种情况又分为两种小情况,一种八种情况。

8.1.2代码实现

8.1.2.1修改处1

在EnemyTank类中:

  1. 增加了增加一个成员属性,EnemyTank 可以得到敌人坦克成员的 Vector,用于循环比较是否重叠
  2. 新增一个方法setEnemyTanks,可以将MyPanel的成员 Vector enemyTanks = new Vector<>() 设置到Enemy 的成员enemyTank
  3. 编写方法isTouchEnemyTank(),判断当前敌人坦克是否和enemyTanks中的其他坦克发生了重叠或碰撞
  4. 在run方法中,在根据坦克的方法来继续移动的判断条件中,调用isTouchEnemyTank方法,如果返回值不为true,则可以继续运行
package li.TankGame.version06;

import java.util.Vector;

public class EnemyTank extends Tank implements Runnable {

    //在敌人坦克类使用Vector保存多个shot
    Vector<Shot> shots = new Vector<>();
    boolean isLive = true;
    //增加一个成员,EnemyTank 可以得到敌人坦克成员的Vector,用于循环比较是否重叠
    Vector<EnemyTank> enemyTanks = new Vector<>();

    public EnemyTank(int x, int y) {
        super(x, y);
    }

    //这里提供一个方法,可以将MyPanel的成员 Vector<EnemyTank> enemyTanks = new Vector<>();
    // 设置到Enemy 的成员enemyTank
    public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
        this.enemyTanks = enemyTanks;
    }

    /**
     * 编写方法,判断当前敌人坦克是否和enemyTanks中的其他坦克发生了重叠或碰撞
     * 思路:读取一个坦克的坐标,在前进之前先将该坦克坐标与当前所有坦克的坐标依次比较,
     * 如果到达某个坦克的边缘则不能再前进,则更改方向前进
     */
    public boolean isTouchEnemyTank() {
        //判断当前敌人坦克(this)方向
        switch (this.getDirect()) {
            case 0://向上
                //让当前的this敌人坦克和其他所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
                    //Vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
                        //如果敌人坦克是上/下方向
                        /**
                         * 情况1.this坦克向上,如果敌人的坦克是上/下方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
                         * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
                         * */
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //this坦克的左上角的坐标(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;//如果进入左上角了该范围,说明发生了碰撞,返回true
                            }
                            //this坦克的右上角的坐标(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;//如果右上角进入了该范围,说明发生了碰撞,返回true
                            }

                        }

                        //如果敌人坦克是右/左方向
                        /**
                         * 情况2.this坦克向上,如果敌人的坦克是右/左方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
                         * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
                         * */
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //this坦克的左上角的坐标(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;//如果进入左上角了该范围,说明发生了碰撞,返回true
                            }

                            //this坦克的右上角的坐标(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;//如果右上角进入了该范围,说明发生了碰撞,返回true
                            }

                        }
                    }
                }
                break;
            case 1://向右
                //让当前的this敌人坦克和其他所有的敌人坦克比较
                for (int i = 0; i < enemyTanks.size(); i++) {
                    //Vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
                        //如果敌人坦克是上/下方向
                        /**
                         * 情况3.this坦克向右,如果敌人的坦克是上/下方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
                         * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
                         * */
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //this坦克的右上角的坐标(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;//如果进入右上角了该范围,说明发生了碰撞,返回true
                            }
                            //this坦克的右下角的坐标(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;//如果右下角进入了该范围,说明发生了碰撞,返回true
                            }

                        }

                        //如果敌人坦克是右/左方向
                        /**
                         * 情况4.this坦克向右,如果敌人的坦克是右/左方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
                         * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
                         * */
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //this坦克的右上角的坐标(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;//如果进入右上角了该范围,说明发生了碰撞,返回true
                            }

                            //this坦克的右下角的坐标(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;//如果右下角进入了该范围,说明发生了碰撞,返回true
                            }
                        }
                    }
                }
                break;
            case 2://向下
                for (int i = 0; i < enemyTanks.size(); i++) {
                    //Vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
                        //如果敌人坦克是上/下方向
                        /**
                         * 情况5.this坦克向下,如果敌人的坦克是上/下方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
                         *    敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
                         * */
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //this坦克的左下角的坐标(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;//如果进入左下角了该范围,说明发生了碰撞,返回true
                            }
                            //this坦克的右下角的坐标(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;//如果右下角进入了该范围,说明发生了碰撞,返回true
                            }

                        }

                        //如果敌人坦克是右/左方向
                        /**
                         * 情况6.this坦克向下,如果敌人的坦克是右/左方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
                         * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
                         * */
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //this坦克的左下角的坐标(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;//如果进入左下角了该范围,说明发生了碰撞,返回true
                            }

                            //this坦克的右下角的坐标(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;//如果右下角进入了该范围,说明发生了碰撞,返回true
                            }
                        }
                    }
                }
                break;
            case 3://向左
                for (int i = 0; i < enemyTanks.size(); i++) {
                    //Vector 中取出一个敌人坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (enemyTank != this) {
                        //如果敌人坦克是上/下方向
                        /**
                         * 情况7.this坦克向左,如果敌人的坦克是上/下方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
                         *    敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
                         * */
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //this坦克的左上角的坐标(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;//如果进入左上角了该范围,说明发生了碰撞,返回true
                            }
                            //this坦克的左下角的坐标(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;//如果左下角进入了该范围,说明发生了碰撞,返回true
                            }

                        }

                        //如果敌人坦克是右/左方向
                        /**
                         * 情况8.this坦克向左,如果敌人的坦克是右/左方向
                         * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
                         * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
                         * */
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //this坦克的左上角的坐标(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;//如果进入左下角了该范围,说明发生了碰撞,返回true
                            }

                            //this坦克的左下角的坐标(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;//如果右下角进入了该范围,说明发生了碰撞,返回true
                            }
                        }
                    }
                }
                break;
        }
        return false;
    }


    @Override
    public void run() {
        while (true) {

            //这我们先判断当前的坦克是否存活
            // 在判断shots.size<3是否真,为真,说明当前的3颗子弹已经消亡了,
            // 就创建一颗子弹,放到shots集合中,并启动线程
            if (isLive && (shots.size() < 3)) {//可以通过控制数字来修改敌人坦克一次发射几颗子弹
                Shot s = null;
                //判断坦克的方创建对应的子弹
                switch (getDirect()) {
                    case 0://向上
                        s = new Shot(getX() + 20, getY(), 0);
                        break;
                    case 1://向右
                        s = new Shot(getX() + 60, getY() + 20, 1);
                        break;
                    case 2://向下
                        s = new Shot(getX() + 20, getY() + 60, 2);
                        break;
                    case 3://向左
                        s = new Shot(getX(), getY() + 20, 3);
                        break;
                }
                shots.add(s);
                new Thread(s).start();
            }

            //根据坦克的方法来继续移动
            switch (getDirect()) {
                case 0://上
                    //让坦克保持一个方向走50步
                    for (int i = 0; i < 50; i++) {
                        if (getY() > 0 && !isTouchEnemyTank()) {
                            moveUp();
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1://右
                    //让坦克保持一个方向走50步
                    for (int i = 0; i < 50; i++) {
                        if (getX() + 60 < 700 && !isTouchEnemyTank()) {//700为面板宽度
                            moveRight();//走一步
                        }
                        try {
                            Thread.sleep(50);//每走一步就休眠50毫秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2://下
                    for (int i = 0; i < 50; i++) {
                        if (getY() + 60 < 550 && !isTouchEnemyTank()) {//550为面板宽度
                            moveDown();
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3://左
                    for (int i = 0; i < 50; i++) {
                        if (getX() > 0 && !isTouchEnemyTank()) {
                            moveLeft();
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
            }
            //随机地改变坦克的方向 0-3
            setDirect((int) (Math.random() * 4));//[0,4)的取整
            //如果被击中了,就退出线程
            if (!isLive) {
                break;//退出线程
            }
        }
    }
}
8.1.2.2修改处2

在MyPanel类中的MyPanel()方法,初始化敌人坦克时,将enemyTanks集合设置给 enemyTank

//将enemyTanks集合设置给 enemyTank
enemyTank.setEnemyTanks(enemyTanks);

可以看到,两个坦克移动到相邻的时候不再发生碰撞/重叠:

image-20220914193037133

8.2记录玩家的成绩,存盘退出

8.2.1思路

创建Recorder类,记录我方击毁敌方坦克的数量。

image-20220914211447127

8.2.2代码实现

8.2.2.1修改处1

在MyPanel类中的paint方法先增加一个方法,用来显示信息

/**
 * 编写方法,显示我方击毁敌方坦克的信息
 */
public void showInfo(Graphics g) {
    //画出 玩家的总成绩
    g.setColor(Color.BLACK);//设置画笔颜色
    Font font = new Font("宋体", Font.BOLD, 20);
    g.setFont(font);
    g.drawString("您累计击毁敌方坦克", 730, 30);//画出“您累计击毁敌方坦克”的字样
    drawTank(760, 55, g, 0, 0);//画一个敌方坦克图案
    g.setColor(Color.BLACK);//重新设置画笔颜色
    g.drawString(Recorder.getAllEnemyTankNum()+"", 850, 95);

}
8.2.2.2修改处2

在paint方法中调用showInfo方法:

image-20220914220607991

8.2.2.3修改处3

新增Recorder类:

package li.TankGame.version06;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

/**
 * @author 李
 * @version 6.0
 * 该类用于记录相关信息,和文件交互
 */
public class Recorder {
    //定义变量,记录我方击毁敌人坦克数
    private static int allEnemyTankNum = 0;
    //定义IO对象,用于写入到文件中
    private static BufferedWriter bw = null;//处理流
    private static String recordFile = "d:\myRecord.txt";//记录文件的路径

    public static int getAllEnemyTankNum() {
        return allEnemyTankNum;
    }

    public static void setAllEnemyTankNum(int allEnemyTankNum) {
        Recorder.allEnemyTankNum = allEnemyTankNum;
    }

    //当我方击毁一辆敌人坦克时,就应该allEnemyTankNum++
    public static void addAllEnemyTankNum() {
        Recorder.allEnemyTankNum++;
    }

    //增加一个方法,当游戏退出时,将allEnemyTankNum保存到myRecord.txt文件中
    public static void keepRecord() {
        try {
            bw = new BufferedWriter(new FileWriter(recordFile));
            bw.write(allEnemyTankNum + "
");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bw != null) {
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
8.2.2.4修改处4

在TankGame06类中的构造器TankGame06方法中,增加相应关闭窗口的处理(在关闭窗口时进行数据存储)

public TankGame06(){
    mp = new MyPanel();
    //将mp放入到Thread,并启动
    Thread thread = new Thread(mp);
    thread.start();
    this.add(mp);//把面板(就是游戏的绘图区域)添加进来
    this.setSize(950,600);//设置大小
    this.addKeyListener(mp);//让JFrame监听mp的键盘事件
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击窗口的叉时停止运行
    this.setVisible(true);//设置显示

    //在JFrame中增加相应关闭窗口的处理
    this.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            Recorder.keepRecord();
            System.exit(0);
        }
    });

}

image-20220914221223505
image-20220914221237833

PS:这里发现之前子弹击中敌坦克的判断条件有误,修正了坦克向左边打其他坦克会瞬间爆炸的bug

修正250行、268行后:

image-20220914222901157

image-20220914222936893

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » day06-IO流应用01