Java视频来源:B站韩顺平教育前端
笔者在B站上看韩顺平老师的Java基础教程,到了坦克大战的阶段,基本的架构已经搞好java
韩顺平老师这里为了巩固文件流基础,特意使用了文件的形式,保存分数和上局游戏情况架构
但老师用的是最简单的Fileoutput流来进行写入坦克的坐标,子弹坐标,各类类型等等,笔者看到这里不由想到:这么复杂,用序列化的方法会不会更好一点呢?ide
我从新用IDEA的结构看了一下坦克大战的组成,发现其实就只有两大块函数
TankGame mypanel Recoder而Mypanel保存了坦克,保存了子弹,保存了爆炸状况idea
既然如此,咱们可使用对象流保存mypanel啊 因而笔者回去复习了下对象流的使用,给mypanel实现了可序列化接口spa
首先咱们须要让Recoder随时随地更新好mypanel,咱们给Recoder添加了静态mypanel对象,而后每进行一次repaint,就给该mypanel对象进行一次赋值更新,为了保证Recoder记录的是最新的mypanel.net
更新好了之后,咱们先作保存工做插件
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<Enemytanks.size();i++)
{
Enemytank e=Enemytanks.get(i);
new Thread(e).start();
for(int j=0;j<e.shots.size();j++)
{
Shot s=e.shots.get(j);
new Thread(s).start();
}
}
if(Hero.shot!=null&&Hero.shot.islive)
{
new Thread(Hero.shot).start();
}
}
而后第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选择
代码写的很差,还请各位读者不惜赐教,如有代码错误之处,还请指出
感谢您的阅读。