韩顺平Java坦克大战-记录上局游戏->使用对象流保存

Java视频来源:B站韩顺平教育

笔者在B站上看韩顺平老师的Java基础教程,到了坦克大战的阶段,基本的架构已经搞好

韩顺平老师这里为了巩固文件流基础,特地使用了文件的形式,保存分数和上局游戏状况

但老师用的是最简单的Fileoutput流来进行写入坦克的坐标,子弹坐标,各种类型等等,笔者看到这里不禁想到:这么复杂,用序列化的方法会不会更好一点呢?

我重新用IDEA的结构看了一下坦克大战的组成,发现其实就只有两大块

TankGame mypanel Recoder而Mypanel保存了坦克,保存了子弹,保存了爆炸情况

既然如此,我们可以使用对象流保存mypanel啊 于是笔者回去复习了下对象流的使用,给mypanel实现了可序列化接口

首先我们需要让Recoder随时随地更新好mypanel,我们给Recoder添加了静态mypanel对象,然后每进行一次repaint,就给该mypanel对象进行一次赋值更新,为了保证Recoder记录的是最新的mypanel

更新好了以后,我们先做保存工作

public static void recoder() throws IOException {
       ObjectOutputStream op=new ObjectOutputStream(new FileOutputStream(path1));
       op.writeObject(all);
       op.close();
    }

为了方便和区分,我们将游戏信息作为另一个文件进行存储,建立对象流op进行写入,记住一定要close!(这里的all就是静态对象)

那么保存好以后,我们就要做读取工作了,首先我们要明白,什么时候读取?看源码我们知道,mypanel的创建是在Tankgame,也就是主函数中调用的,我们如果要进行上一局游戏,就得分不同情况去创建这个mypanel,于是来到主函数

我们默认mypanel是null的,如果该对象是null,那就说明还没开始游戏,那就直接new,如果对象不为null,那就说明该对象已经是上一局游戏的了!

那我们就需要读取mypanel了对吧?但读取之前得先让Recoder加载,所以要写一个加载方法

 public static void refunc() throws IOException, ClassNotFoundException {

        mypanel m=null;
        if(new File(path1).exists()) {
            ObjectInputStream oi=new ObjectInputStream(new FileInputStream(path1));
             m= (mypanel) oi.readObject();
        }
        all=m;
    }

将该文件读取出来,如果不存在,那么就直接赋值为null,存在就赋值为文件里的mypanel

主函数中:

public TankGame() throws IOException, ClassNotFoundException {
        Recoder.refunc();
        if(Recoder.getall()==null)
        {
            mp=new mypanel();
        }
        else
        {
            mp=Recoder.getall();
        }

调取函数之后,就正常让这个mp加入到我们的画框里即可,但是,报错了,显示NotSe什么什么的,意思就是mp这个对象还没有实现序列化,可是不是已经添加了么?随后一看,是tank和shot还没添加,我添加了过后,还是报错,最后仔细一看,发现我们的爆炸图片还没序列化,但我们总不能去源码那里给他加上去吧,这里,我们可以新建一个Imagefortmp类,,再实行序列化,再将三个image添加到里边,改为静态对象,然后直接在mypanel类里调用即可,可以直接在该类中加载好图片,能解决有时候不出现爆炸图片的现象,在mypanel里添加也可以

这该类的代码

public class Imagefortmp  implements Serializable {
    static Image n1;
    static Image n2;
    static Image n3;

}

最后编译,发现能通过了,第二局游戏也确实是继续游戏,但有个奇怪的事,自己坦克可以动,敌方坦克和子弹却动不了?我们仔细想想,可以发现,新游戏的子弹和坦克的线程都是创建过后才开启的,换言之,你如果已经有了这两个了,线程得自己去开启,那么我们就需要写一个函数,去遍历每一个坦克和每一个坦克子弹合集,分别给他们开启,当然自己坦克的线程是归属于Keylistener的,在主函数中开启的,这也就是为什么我们可以动的原因 然后写好后在主函数,开启了mp线程后调用mp线程的该方法,

该方法代码

   public void startgame()
    {
        for(int i=0;i

然后第N次debug的时候,居然直接报错了,显示InvalidClassException

我上网查了好久,最终得到原因和解决方案,每个对象流在保存的时候和读取的时候的序列号要一样,改变对象属性等操作会导致序列号发生改变,如果序列号不一样,解码就解不出来,自然而然就会崩溃,而每个类都有一个序列号,由于我们只有一个mypanel对象,所以我们需要指定好这个序列号,于是在mypanel下边添加这一句即可,可能大致意思解读的不太对,有兴趣的读者可以转到java.io.InvalidClassException异常解决_csdn565973850的博客-CSDN博客_java.io.invalidclassexceptionjava.io.InvalidClassException异常解决1.什么是serialVersionUID2.java.io.InvalidClassException产生原因?3.java.io.InvalidClassException解决方案4.idea推荐插件1.什么是serialVersionUID       ...https://blog.csdn.net/csdn565973850/article/details/88977061

进行了解,

private static final long serialVersionUID=7981560250804078637l;

这样就可以保证序列号的统一

总体合成以后,再更新就无多大问题了,要想做到新游戏和继续游戏的话,可以在前端新增if语句进行输入判断,由玩家的输入进行选择,也可以新建一个画框,利用画框来让用户使用ASWD选择

代码写的不好,还请各位读者不惜赐教,若有代码错误之处,还请指出

感谢您的阅读。

你可能感兴趣的