星雨——项目总结
?
?
一、项目主类:
?1.Ball(子弹);2.BallListener(监听线程——暂废弃);
?3.Config(相关配置);4.DrawPanel(战场类);
?
?5.GameListener(游戏监听)
?6.Plane(飞机);7.ThreadControl(程序总控制);
?8.WAR_Earth(主界面)
二、结构组成
???????? 本项目主要有两大线程组成,一个是子弹线程,另一个则是飞机线程,其中每个线程又分为敌我两个线程,每一种线程对象 对应不同的属性数据。? 由于线程任务分配的不规律性,所以 项目在运行时,采用边运行,边监听的的模式,以达到准确的 对每个线程进行操作。
三、项目流程
? 1.相关配置,其中的配置主要有两种,一种是用来存放线程对象的队列,另一种就是上面提到的战场类的对象,这是考虑到整个流程操作,战场面板贯穿整个流程,所以把它归为配置中。
? 2.完成主界面,界面主要包括两部分,一是菜单条——主要是对游戏一些的说明,二是战场面板——这是作战的整个范围,另外就是负责对我方飞机属性的一些描述,整个界面采用边界布局。
? 3.战场类的的处理:由于无论是子弹线程,还是飞机线程,他们在运行时,各自的对象都是一直在不停地运动,所以需要不停地 刷新界面,最终都要经过paint函数,所以在子弹线程和飞机线程中并不负责绘制各自对象,他们只是负责处理数据,整个的绘制都是通过借用队列里的数据在paint函数里完成。
? 4.监听器,主要负责通过键盘获得触发时间信息,完成对游戏的操作,包括开始、暂停、继续、结束,我方飞机的移动和发子弹。另外在监听器中还包含两个计时器,一个是负责敌方飞机的定时产生,另一个则是负责对界面的定时刷新。
? 5.飞机线程和子弹线程:发射子弹是飞机的一个属性,所以在飞机线程里包含一个定时发子弹的计时器,以负责子弹的发出。飞机的属性包括生命值、被打爆后的经验值以及速度方向,子弹的属性主要包括伤害值和速度方向。另外每个线程都有控制自己单个线程结束与否的属性。
? 6.整个线程的总开关,主要实现对整个进程的开始,暂停,继续,结束,以及对数据的清空处理等操作.
?
四、主要问题:
?1.Panel 对象? Warpanel? 的大小设置,和画布获取?
?
分析:在整个项目的开始进行时,对对象的绘制是在各自的线程内部完成的,但由于静态对象在所有对象创建之前被加载,
?????????? 在游戏监听器的构造器里获得通过Warpanel获得的画笔是空的,但有一点暂时任然不明白,就是我在类DrawPanel的构造器已经通过?? setPreferredSize(new Dimension(width, height)); 给对象设定了大小,但从其他类里用getWidth()得到 的却是0,令人费解,后来我又在上面的语句后加上 setSize(new Dimension(width, height));这样问题就解决了,但我不知是什么原因,不知道是不是我把Warpanel放在接口里作为静态对象处理的结果。希望某位大侠帮忙解决一下
?2.监听线程达不到一枪一个的效果,直接导致无法计分?
?
?分析:由于线程任务分配的不规律性,所以即使子弹打中对方,但并没有立刻进行数据处理,而是等到分配到了再处理,所以果 断舍弃监听线程,采用边监听,边运行的模式,具体就是在每个线程内部每运行一次就判断一次,然后立刻处理
????????????
?3.屏幕狂闪?
?
?分析:由于每一个线程对象移动一次 ,就要对整个屏幕进行重绘,加上每次重绘时数据也比较多,而且是整个屏幕重绘,所以程序需要
?不断地改变窗体中正在被绘制的图象,造成绘制的缓慢,加剧了闪烁,概括一下就是屏幕的更新方法有问题,所以必须采用双缓冲(原理见附录);
?
?4.飞机的定时产生,会有重叠?
?
?分析:这也算是第二个问题的延续了,由于在飞机产生时位置是随机产生的,所以并不能确保会不会有重叠,解决方法就是 加一句判断语句,但这个问题我可是找了好久,特别是两个敌方飞机完全重叠,完全以假乱真了
五、附录
?1.?双缓冲技术的工作原理:先在内存中分配一个和我们动画窗口一样大的空间(在内存中的空间我们是看不到的),然后利用getGraphics()方法去获得双缓冲画笔,
?? 接着利用双缓冲画笔给空间我们想画的东西,最后将它全部一次性的显示到我门的屏幕上.这样在我门的动画窗口上面是显示出来就非常的流畅了.避免了上面的闪烁效果。
2.?双缓冲的使用
? 它的执行过程是这样的:repaint() 到update()再到paint(),而我们的双缓冲代码就写在update()里。
?? 1)定义一个Graphics对象gOff和一个Image对象offScreenImage。按屏幕大小建立一个缓冲对象给offScreenImage。然后取得offScreenImage的Graphics赋给gOff。此处可以把gOff理解为逻辑上的缓冲屏幕,而把offScreenImage理解为缓冲屏幕上的图象。
? 2) 在gOff(逻辑上的屏幕)上用paint(Graphics g)函数绘制图象。
?? 3)将后台图象offScreenImage全部一次性的绘制到我们的动画窗口,然后把我们内存中分配的空间窗口关闭调用dispose()方法.
?具体代码如下:
private Image iBuffer;private Graphics gBuffer;//重载paint(Graphics scr)函数:public void paint(Graphics scr){ scr.setColor(Color.RED); scr.fillOval(90,ypos,80,80);}//重载update(Graphics scr)函数:public void update(Graphics scr){ if(iBuffer==null) { iBuffer=createImage(this.getSize().width,this.getSize().height); gBuffer=iBuffer.getGraphics(); } gBuffer.setColor(getBackground()); gBuffer.fillRect(0,0,this.getSize().width,this.getSize().height); paint(gBuffer); scr.drawImage(iBuffer,0,0,this);}
???
??????????????