前言
图片闪现在游戏运行中应该算是很常见的问题了,不知道大家用的什么方法解决这个问题,我是用的双缓冲来实现的,下面是我的一些理解,希望对大家有帮助,本人也是第一次写博客,如有错误,有望指正,或者有什么其他好的方法解决,大家也可以一起讨论
一、为什么会出现图片闪现问题?
在了解图片或者动画出现双缓冲之前,我们先了解一下计算机的运行原理,计算机运行时是将最大的任务分解成多个任务,然后一个接一个的执行。假如计算机有10份事物,而需求者也就是事件有3位分别是A,B,C,他们分别需要2,3,5份事物,但不会计算机不会一下子给完A这个事件2份食物之后再去给B,而是依次轮流的一份一份去给A、B、C。在画图画的时候呢,只有一块画布,当他画完一个东西再去画另一个东西的时候,画布需要清空才可以处理,可问题来了,画布需要清空再处理,所以图片就会有交替闪烁的问题。用paint(Graphics g)函数在屏幕上直接绘图的时候i,由于执行的语句过多,程序会不断改变窗体中正在被绘制的图像,会造成绘制的缓慢,也会加剧闪烁问题的出现,解决这个问题的时候就用到了双缓冲技术。
动画出现闪烁情况的代码
public class GameWin extends JFrame {
Bg bg = new Bg();
//初始化窗口信息
void launch() {
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
this.setBounds((width - 768) / 2, (height - 700) / 2, 768, 700);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);// 设置可以关闭窗口
this.setResizable(false);// 设置窗口大小不可以调节
this.setVisible(true); // 设置窗口可见
}
@Override
public void paint(Graphics g) {
gImage.drawImage(Bg.getImage("bg.jpg"), 0, 150, 768, 600, null);
gImage.drawImage(Bg.getImage("bg1.jpg"), 0, 0, 768, 150, null);
gImage.drawImage(Bg.getImage("peo.png"), 300, 50, 120, 100, null);
g.drawImage(gImage, 0, 0, null);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
二、利用双缓冲解决问题
在知道了为什么会出现闪烁问题后,我们再来解决问题就会方便了许多。
所谓双缓冲就是在内存中开辟一片区域,作为后台图像,程序对他进行更新、修改绘制完成后再显示到屏幕上。可以简单地这样理解,将开辟区域可以理解为新建一个图层,然后将之前所建立的图片图层都放在这个图层上面,然后最他们进行合并图层合并成一个图层,然后不管再怎样刷新渲染,几个图像组件都是保持一致的,出现频率不一样的情况也就不会出现了。
通过 重载paint(Graphics g)来实现双缓冲,过程
- 首先创建一张和窗体一样大小的画布
- 将图画放到这个画布上
- 将这个新建的画布绘制到窗口中
// 定义一张画布
Image offScreenImage;
//将图画组件放到这个画布上
offScreenImage = this.createImage(768, 700);
Graphics gImage = offScreenImage.getGraphics()
//将画布绘制到窗口
g.drawImage(offScreenImage, 0, 0, null);
完整代码如下:
public class GameWin extends JFrame {
Bg bg = new Bg();
// 定义一张画布
Image offScreenImage;
//初始化窗口信息
void launch() {
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
this.setBounds((width - 768) / 2, (height - 700) / 2, 768, 700);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);// 设置可以关闭窗口
this.setResizable(false);// 设置窗口大小不可以调节
this.setVisible(true); // 设置窗口可见
}
@Override
public void paint(Graphics g) {
offScreenImage = this.createImage(768, 700);
Graphics gImage = offScreenImage.getGraphics();
gImage.drawImage(Bg.getImage("bg.jpg"), 0, 150, 768, 600, null);
gImage.drawImage(Bg.getImage("bg1.jpg"), 0, 0, 768, 150, null);
gImage.drawImage(Bg.getImage("peo.png"), 300, 50, 120, 100, null);
//将画布绘制到窗口中
g.drawImage(offScreenImage, 0, 0, null);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
总结
在其他博客上看到,双缓冲的实现方法只是消除闪烁的方法的一种。如果在swing中,组件本身就提供了双缓冲的功能,我们只需要进行简单的函数调用就可以实现组件的双缓冲,在awt中却没有提供此功能。另外,一些硬件设备也可以实现双缓冲,每次都是先把图像画在缓冲中,然后再绘制在屏幕上,而不是直接绘制在屏幕上。也还有其他软件实现消除闪烁的方法,但双缓冲也是一个不错的方法。