双缓冲技术解决java游戏图片闪现问题

前言

图片闪现在游戏运行中应该算是很常见的问题了,不知道大家用的什么方法解决这个问题,我是用的双缓冲来实现的,下面是我的一些理解,希望对大家有帮助,本人也是第一次写博客,如有错误,有望指正,或者有什么其他好的方法解决,大家也可以一起讨论


一、为什么会出现图片闪现问题?

在了解图片或者动画出现双缓冲之前,我们先了解一下计算机的运行原理,计算机运行时是将最大的任务分解成多个任务,然后一个接一个的执行。假如计算机有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)来实现双缓冲,过程

  1. 首先创建一张和窗体一样大小的画布
  2. 将图画放到这个画布上
  3. 将这个新建的画布绘制到窗口中

// 定义一张画布
	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中却没有提供此功能。另外,一些硬件设备也可以实现双缓冲,每次都是先把图像画在缓冲中,然后再绘制在屏幕上,而不是直接绘制在屏幕上。也还有其他软件实现消除闪烁的方法,但双缓冲也是一个不错的方法。


  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值