`
李瑞辉++
  • 浏览: 20821 次
  • 性别: Icon_minigender_1
  • 来自: 信阳
社区版块
存档分类
最新评论

星雨——项目总结

 
阅读更多

 

 

一、项目主类
 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()方法.

 具体代码如下:

 Image offScreenImage = null;

  if (offScreenImage == null)
        offScreenImage = createImage(BLOCK_SIZE * COLS, BLOCK_SIZE * ROWS);
        Graphics gOff = offScreenImage.getGraphics();
        // 4.调用paint(),将缓冲图象的画笔传入
        paint(gOff);
        // 5.再将此缓冲图像一次性绘到代表屏幕的Graphics对象,即该方法传入的“g”上
        g.drawImage(offScreenImage, 0, 0, null);

 

  3、重载update(Graphics g)实现双缓冲:

    这是比较传统的做法。也是实际开发中比较常用的做法。

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);

}


   
              

  • 大小: 67.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics