很久没打开eclipse了,把电脑重装了系统,重新装了JDK,重新装了eclipse,花了几天时间重新适应一下程序的编写,发现以前非常熟悉的东西现在也就仅仅是知道有那么个东西而基本不会写了。哎!杯具。。。
今天写了个swing+Thread最简单的小游戏,就是手动控制两个小方块的碰撞(包括方块和墙的碰撞),因为我准备写个小时候玩的小霸王游戏—坦克大战,今天就算是起步。
在线程run()方法中调用repaint()方法来对界面重绘,也就达到动画的效果。一切over,当运行程序的时候发现,屏幕闪的厉害。查看程序,发现线程run()中while()循环每循环一次界面就要重绘一次,这才导致屏幕频繁的闪烁。。
深入分析,这个repaint()方法是从父类JFrame继承来的,当repaint方法执行的时候会调用update(Graphics g)方法,而update()方法里面首先判断是否轻量组件,如果是那么用背景色覆盖掉界面g.clearRect(0,0,width,height),然后再调用paint()方法,意思就是先清理掉当前,然后画下一个画面,所谓屏幕闪烁就是清理和重绘的过程,那么如何解决呢,貌似要达到动画的效果就必须先清理再重绘。。。咋办呢
屏幕闪动总是那么的让人无法忍受,于是我上网搜了一下解决方法,乍看下去都是说的用双缓冲技术来解决。。小弟为了让屏幕冷静下来不要那么激动就自学了一下,下面我来说说我的理解。。
所谓双缓冲,就是在内存中重新开辟新空间,作为后台图像,然后把本来要在界面上进行的清理和重绘在后台处理好,生成一幅新的画面,最后再显示在界面上。
原理总是很简单的,实现起来时怎样呢?
首先要定义两个私有变量,一个是后台图像iBuffer,一个是后台图像的画布对象gBuffer。这也就是所谓的双缓冲。然后通过一段程序来帮助理解:
//重写paint方法
public void paint(Graphics scr){
//判断后台图像是否为空
if(iBuffer == null){
//如果为空,则创建一个和当前界面一样大小的缓冲图像,再取得这个图像的画布对象gBuffer
iBuffer = createImage((int)this.getSize().getWidth(),(int)this.getSize().getHeight());
gBuffer = iBuffer.getGraphics();
}
//用背景色填充图像(清理画面)
gBuffer.setColor(getBackground());
gBuffer.fillRect(0, 0, (int)this.getSize().getWidth(), (int)this.getSize().getHeight());
//然后再绘制下一幅画面在缓冲图像
gBuffer.setColor(Color.RED);
gBuffer.fillOval(90, ypos, 80, 80);
//在界面上直接画出缓冲图像
scr.drawImage(iBuffer,0,0,this);
}
//重写update方法,不用再实现画面的
public void update(Graphics scr){
paint(scr);
}
将本来要在界面上实现的操作(画面的清理和重绘)在后台就实现好,然后绘制成一幅画面,最后在界面上显示这个画面,从而消除屏幕的闪烁,问题也随之解决。
然而,一个目的的达到,当然也会大大小小的付出相应的代价,只是付出代价值不值得的问题了。利用双缓冲消除闪烁到底付出了什么代价呢?哦,原来是加大了内存的开销,因为这一过程是在新开辟的内存中实现的,那到底开销了多少呢?值不值得呢?这个我还真没研究过。但是不是界面上所有的东西都要在后台清理了重绘呢,为了减少内存不必要的开销,我觉得只需要把变的东西放在iBuffer中就行了,这样付出的代价也就小一点,何乐而不为呢。。
小试牛刀还真找到了以前的感觉,把一件事做好很简单,难就难在一直把事做好。这就需要坚持不懈的精神。。。
铁杵不是一天或者一个周或者一个月甚至不是一个年能磨成针的~