使用双缓冲区
该文章为本站原创,如有引用,请注明出处和作者
为什么要使用双缓冲区?通过前面的学习我们知道当要绘制屏幕时,我们只要调用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;
}
}
}