作者:潇潇  出处:www.j2mefans.com
该文章为本站原创,如有引用,请注明出处和作者



     为什么要使用双缓冲区?通过前面的学习我们知道当要绘制屏幕时,我们只要调用paint函数即可。其中我们可以使用绘图方法来绘制任何文字图形图像。可是 当我们绘制的东西多了之后,你就会发现又是屏幕上的显示根本不是我们要的结果,很杂乱。细想想,会知道因为paint函数中,我们是一边绘制一边显示,所 以当内容过多,就会产生没绘制完成,就显示到屏幕上的结果。
   因此,双缓冲区就提供了一个完美的解决方案。我们可以在缓冲区2中绘制图像,而是用缓冲区1来输出到屏幕。这样我们就可以控制绘制和现实的过程,从而避免上面的现象。
对于MIDP2.0来说,因为GameCanvas类本身带有双缓冲区的功能,所以我们在代码中可以看到这样的结构:
//这里添加对屏幕的绘制
    public void paint(Graphics g)
    {
        // 清除屏幕
        g.setColor(0xffffffff);
        g.fillRect(0, 0, getWidth(), getHeight());
    
        //绘制屏幕
        g.setColor(0,0,0);
        g.fillRect(x,y,20,20);

        // 刷新屏幕缓冲区
        flushGraphics();
    }
通过代码我们可以知道绘制屏幕部分,并不是直接在屏幕上绘制,而是现在一个和屏幕一般大小的内存中绘制,在通过flushGraphics函数输出到屏幕的。

但对MIDP1。0就没那么简单了。我们必须显示的创建一个和屏幕相当的内存区,在其中绘制图像,完成后,通过输出该缓冲区图像来绘制屏幕。典型的代码:
private Image offScreenBuffer; //定义屏幕缓冲区

public OCanvas()
{
    ……
    //在画布的构造函数或者start函数中添加下面代码

    initResources();
}

Private void initResources()
{
    //创建屏幕缓冲区
    offScreenBuffer = Image.createImage(getWidth(),getHeight());
}

Protected void paint(Graphics g)
{
    //在下面的函数中绘制图形
    renderWorld();
    //使用下面的语句来输出屏幕缓冲区到屏幕上
    graphics.drawImage(offScreenBuffer,0,0,Graphics.LEFT|Graphics.TOP);
}

这样我们就可以在initResources函数中,初始化绘图变量,在renderWorld函数中真正进行绘制。
下面是一段例程:

/**
*  文件名:Ocanvas.java
*  画布类
*/

import javax.microedition.lcdui.*;
import java.io.*;
import java.util.*;
import java.lang.Thread;

public class OCanvas extends Canvas implements Runnable
{
    //定义变量
    private Display display;
    private boolean sleeping;
    private long    frameDelay;
    
    //双缓冲区
    private Image offScreenBuffer;

    private int     XSpeed,YSpeed;
    private int     x,y;

    private static int statusLineHeight = 10;
    private int laneHeight = 0;
    private static final int topMargin =3 ;

    public OCanvas(Display d)
    {
        //类构造函数,初始化类变量
        super();
        display = d;

        // 设置帧频 (30 fps)
        frameDelay = 33;
    }

    void start()
    {
        
         // 设置这个画布为当前屏幕
        display.setCurrent(this);
    
        // 初始化一些游戏中的变量,载入相关图片
        x=getWidth()/2-10;
        y=getHeight()/2-10; 
        

         //建立双缓冲区
         initResources();

         // 开始动画线程
         sleeping = false;
         Thread t = new Thread(this);
         t.start();
    }

    private void initResources()
    {
        offScreenBuffer = Image.createImage(getWidth(), getHeight());

        int heightMinusStatus = getHeight()- statusLineHeight;
        laneHeight = ((heightMinusStatus)/9);
    }

     public void stop() {
        // 停止动画线程
        sleeping = true;
    }
  
     public void run() {
         // 动画线程开始后运行
           
        // 主游戏循环
        while (!sleeping) {
             
            //更新屏幕显示
            repaint();
            //线程休眠             try {
                 Thread.sleep(frameDelay);
                }
             catch (InterruptedException ie) {}
        }
     }

        
    //这里添加对屏幕的绘制
    public void paint(Graphics g)
    {
        // 清除屏幕
        g.setColor(0xffffffff);
        g.fillRect(0, 0, getWidth(), getHeight());
    
        // 重绘屏幕
        renderWorld();
        g.drawImage(offScreenBuffer,0,0,Graphics.LEFT | Graphics.TOP);

    }

    private void renderWorld()
    {
        Graphics osg = offScreenBuffer.getGraphics();
        int y1=0;
        //绘制路边
        osg.setColor(0x00209020);
        y1+=(laneHeight)+topMargin;
        osg.fillRect(0,0,getWidth(),y1);
        //绘制边线
        osg.setColor(0x00808080);
        osg.drawLine(0,y1-2,getWidth(),y1-2);
        osg.setColor(0x00000000);
        osg.drawLine(0,y1-1,getWidth(),y1-1);
        
        //绘制马路
        osg.setColor(0x00000000);
        osg.fillRect(0,y1,getWidth(),laneHeight *3);
        
        //绘制马路线
        osg.setStrokeStyle(Graphics.DOTTED);
        osg.setColor(0x00AAAAAA);
        y1+= laneHeight; osg.drawLine(0,y1,getWidth(),y1);
        y1+= laneHeight; osg.drawLine(0,y1,getWidth(),y1);
        y1+= laneHeight; osg.drawLine(0,y1,getWidth(),y1);

        //绘制中间马路
        osg.setColor(0x00666666);
        osg.fillRect(0,y1-2,getWidth(),2);
        osg.setColor(0x00aaaaaa);
        osg.fillRect(0,y1,getWidth(),laneHeight);
        y1+=laneHeight;
        osg.setColor(0x00666666);
        osg.fillRect(0,y1-2,getWidth(),2);

        //绘制马路
        osg.setColor(0x00000000);
        osg.fillRect(0,y1,getWidth(),laneHeight *3);

        //绘制马路线
        osg.setStrokeStyle(Graphics.DOTTED);
        osg.setColor(0x00AAAAAA);
        y1+= laneHeight; osg.drawLine(0,y1,getWidth(),y1);
        y1+= laneHeight; osg.drawLine(0,y1,getWidth(),y1);
        y1+= laneHeight; osg.drawLine(0,y1,getWidth(),y1);

        osg.setStrokeStyle(Graphics.SOLID);
        osg.setColor(0x00808080);

        osg.drawLine(0,y1,getWidth(),y1);
        y1++;
        osg.setColor(0x00000000);
        osg.drawLine(0,y1,getWidth(),y1);

        //绘制路边
        osg.setColor(0x00209020);
        osg.fillRect(0,y1,getWidth(),y1+(laneHeight)+topMargin);


        //绘制方块
        osg.setColor(255,255,255);
        osg.fillRect(x,y,20,20);
    }

    //处理按键信息
    public void keyPressed(int keyCode) 
 {
      int keystates = getGameAction(keyCode);
  switch(keystates)
  {
   case UP:
    y = Math.max(0, y - 2);
    break;
   case DOWN:
    y = Math.min(getHeight()-20, y + 2);
    break;
   case LEFT:
    x = Math.max(0, x - 2);
    break;
   case RIGHT:
    x = Math.min(getWidth(), x + 2);
    break;
  }
 }

}