如何解决不良双缓冲 [英] How to fix bad Double-Buffering

查看:292
本文介绍了如何解决不良双缓冲的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试着跟随双缓冲的教程,我真的不知道我做错了什么。它的工作原理之前,在那之前我做了教程,但仍有和偶尔闪烁在这里和那里。我有两个文件,​​游戏和gameLoop

游戏

 进口java.awt.Graphics;
公共类游戏扩展gameLoop
{
    公共无效的init()
    {
        的setSize(854480);
        主题日=新主题(本);
        th.start();
        屏幕外=的createImage(854480);
        D = offscreen.getGraphics();
    }
    公共无效漆(图形G)
    {
        d.clearRect(0,0,854,480);
        d.drawImage(磁盘,X,Y,这一点);
        g.drawImage(屏幕外,0,0,这一点);
    }
    公共无效更新(图形GFX)
    {
        油漆(GFX);
    }
}

gameLoop

 进口java.applet.Applet中;
进口java.awt.Graphics;
进口java.awt.Image中;
进口java.awt.MouseInfo;
进口java.awt.Point中;
进口java.awt.PointerInfo;
进口java.awt.event.KeyEvent中;
进口java.awt.event.KeyListener;
进口java.awt.event.MouseEvent中;
进口java.awt.event.MouseListener;
进口java.awt.event.MouseMotionListener;
进口java.awt.image.BufferedImage中;
进口的java.io.File;
进口java.io.IOException异常;进口javax.imageio.ImageIO中;公共类gameLoop扩展的Applet实现Runnable,MouseListener的,的MouseMotionListener
{
    公众诠释的x,y,计数器,mouseX,mouseY的;
    公众形象屏幕外;
    公共图形D组;
    公共布尔上,下,左,右,pressed;
    公众的BufferedImage DISK1,DISK2,磁盘3,DISK4,盘;
    公众诠释ballSpeed​​X = -6;
    公众诠释ballSpeed​​Y = -3;    公共无效的run()
    {
        X = 400;
        Y = 200;
        尝试{
            磁盘1 = ImageIO.read(新文件(disk1.png));
            DISK2 = ImageIO.read(新文件(disk2.png));
            磁盘3 = ImageIO.read(新文件(disk3.png));
            DISK4 = ImageIO.read(新文件(disk4.png));
        }赶上(IOException异常E1){
            e1.printStackTrace();
        }
        而(真)
        {
            如果(X> =(854 - 150))
            {
                    ballSpeed​​X = ballSpeed​​X * -1;
            }
            如果(Y> =(480 - 140))
            {
                    ballSpeed​​Y = ballSpeed​​Y * -1;
            }
            如果(γ≤(0 - 10))
            {
                    ballSpeed​​Y = ballSpeed​​Y * -1;
            }
            如果(X≤(0-10))
            {
                    ballSpeed​​X = ballSpeed​​X * -1;
            }            X = X + ballSpeed​​X;
            Y = Y + ballSpeed​​Y;            反++;
            如果(计数器> = 4)
                计数器= 0;            如果(反== 0)
                磁盘= disk1的;
            如果(计数器== 1)
                磁盘= DISK2;
            如果(计数器== 2)
                磁盘= disk3的;
            如果(反== 3)
                磁盘= DISK4;            的System.out.println(柜);            重绘();            尝试{
                视频下载(30);
            }赶上(InterruptedException的E){
                e.printStackTrace();
            }
        }
    }    公共无效的mouseClicked(的MouseEvent E){}
    公共无效的mouseEntered(的MouseEvent E){}
    公共无效的mouseExited(的MouseEvent E){}
    公共无效的mouseMoved(的MouseEvent米){}    公共无效鼠标pressed(的MouseEvent米)
    {    }    公共无效的mouseReleased(的MouseEvent米)
    {
        pressed = FALSE;
    }    公共无效的mouseDragged(的MouseEvent E){
        PointerInfo一个= MouseInfo.getPointerInfo();
        点b = a.getLocation();
        mouseX =(int)的b.getX();
        mouseY的=(INT)b.getY();
        ballSpeed​​X = mouseX;
        ballSpeed​​Y = mouseY的;
    }
}


解决方案

有许多不同类型的双缓冲的。基本就是你更新一个简单的关闭屏幕图像,这被画到屏幕上,而不是。如果做得正确,画的形象往往是更快然后绘制图形到屏幕上。

另一种类型是页面翻转。也就是说,你有一个活跃的缓冲区,始终呈现在屏幕和关闭屏幕/临时缓冲区这就是你真正呈现到。然后,翻转这些缓冲区,当你准备渲染的对屏幕的更新(这是更接近电影动画是如何工作的)。

下面的例子是翻页的很基本的例子。

 进口java.applet.Applet中;
进口java.awt.BorderLayout中;
进口java.awt.Color中;
进口java.awt.Dimension中;
进口java.awt.Graphics;
进口java.awt.Graphics2D中;
进口java.awt.Panel;
进口java.awt.image.BufferedImage中;
引入静态testdoublebuffer.TestDoubleBuffer.UPDATE;公共类AppletDoubleBuffer扩展的Applet {    私人BufferedPane窗格;    @覆盖
    公共无效的init(){
        窗格=新BufferedPane();
        的setLayout(新的BorderLayout());
        加(面板);
    }    @覆盖
    公共无效的start(){
        pane.start();
    }    @覆盖
    公共无效停止(){
        pane.stop();
    }    公共类BufferedPane扩展面板{        私人的BufferedImage activeBuffer;
        私人的BufferedImage划伤;
        私人布尔运行= FALSE;        公共BufferedPane(){
        }        公共无效的start(){
            如果(!运​​行){
                运行= TRUE;
                线程线程=新主题(新的主循环());
                thread.setDaemon(真);
                thread.start();
            }
        }        公共无效停止(){
            运行= FALSE;
        }        @覆盖
        公共尺寸的get preferredSize(){
            返回新尺寸(200,200);
        }        @覆盖
        公共无效无效(){
            同步(更新){
                activeBuffer = NULL;
                从无到有= NULL;
            }
            super.invalidate();
        }        @覆盖
        公共无效更新(图形G){
            如果(activeBuffer!= NULL){
                Graphics2D的G2D =(Graphics2D的)g.create();
                g2d.drawImage(activeBuffer,0,0,这一点);
                g2d.dispose();
            }
        }        公共类主循环实现Runnable {            私人INT延迟= 1000至25年;
            私人INT X = 0;
            私人诠释速度= 5;
            私人诠释大小= 10;            公共无效更新(){                X + =速度;
                如果(X +尺寸> =的getWidth()){
                    X =的getWidth() - 大小;
                    速度* = -1;
                }否则如果(X LT; = 0){
                    X = 0;
                    速度* = -1;
                }                如果(的getWidth()大于0&放大器;&放大器;的getHeight()大于0){
                    同步(更新){
                        如果(刮== NULL){
                            从无到有=新的BufferedImage(的getWidth()的getHeight(),BufferedImage.TYPE_INT_ARGB);
                        }
                        Graphics2D的G2D = scratch.createGraphics();
                        INT Y =(的getHeight() - 大小)/ 2;
                        g2d.setBackground(Color.BLUE);
                        g2d.clearRect(0,0,的getWidth(),的getHeight());
                        g2d.setColor(Color.RED);
                        g2d.fillOval(X,Y,尺寸,大小);
                        g2d.dispose();                        //翻转缓冲区...
                        BufferedImage的TMP = activeBuffer;
                        activeBuffer =划伤;
                        从无到有= tmp目录;
                    }
                }            }            @覆盖
            公共无效的run(){
                而(运行){                    长STARTTIME = System.currentTimeMillis的();                    更新();
                    重绘();                    持续时间长= System.currentTimeMillis的() - startTime时;
                    如果(持续时间LT;延迟){
                        尝试{
                            视频下载(延迟);
                        }赶上(InterruptedException的前){
                        }
                    }                }
            }
        }
    }
}

我个人,只想跳过使用AWT和移动到Swing提供更好的/内置的功能,这类型的事情。

I tried following a double buffering tutorial, and I really don't know what I did wrong. It works before then before I did the tutorial, but there is still and occasional flicker here and there. I have two files Game and gameLoop

Game:

import java.awt.Graphics;
public class Game extends gameLoop
{
    public void init()
    {
        setSize(854,480);
        Thread th = new Thread(this);
        th.start();
        offscreen = createImage(854,480);
        d = offscreen.getGraphics();
    }
    public void paint(Graphics g)
    {
        d.clearRect(0, 0, 854, 480);
        d.drawImage(disk, x, y, this);
        g.drawImage(offscreen , 0, 0, this);
    }
    public void Update(Graphics gfx)
    {
        paint(gfx);
    }
}

gameLoop

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class gameLoop extends Applet implements Runnable, MouseListener, MouseMotionListener 
{
    public int x, y, counter, mouseX, mouseY;
    public Image offscreen;
    public Graphics d;
    public boolean up, down, left, right, pressed;
    public BufferedImage disk1, disk2, disk3, disk4, disk;
    public int ballSpeedX = -6;
    public int ballSpeedY = -3;

    public void run() 
    {
        x = 400;
        y = 200;
        try {
            disk1 = ImageIO.read(new File("disk1.png"));
            disk2 = ImageIO.read(new File("disk2.png"));
            disk3 = ImageIO.read(new File("disk3.png"));
            disk4 = ImageIO.read(new File("disk4.png"));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        while(true)
        {
            if(x >= (854 - 150))
            {
                    ballSpeedX = ballSpeedX * -1;
            }
            if(y >= (480 - 140))
            {
                    ballSpeedY = ballSpeedY * -1;
            }
            if(y < (0 - 10))
            {
                    ballSpeedY = ballSpeedY * -1;
            }
            if(x < (0- 10))
            {
                    ballSpeedX = ballSpeedX * -1;
            }

            x = x + ballSpeedX;
            y = y + ballSpeedY;

            counter ++;
            if(counter >= 4)
                counter = 0;

            if(counter == 0)
                disk = disk1;
            if(counter == 1)
                disk = disk2;
            if(counter == 2)
                disk = disk3;
            if(counter == 3)
                disk = disk4;

            System.out.println(counter);

            repaint();

            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }



    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseMoved(MouseEvent m) {}

    public void mousePressed(MouseEvent m) 
    {

    }

    public void mouseReleased(MouseEvent m) 
    {
        pressed = false;
    }

    public void mouseDragged(MouseEvent e) {
        PointerInfo a = MouseInfo.getPointerInfo();
        Point b  = a.getLocation();
        mouseX = (int)b.getX();
        mouseY = (int)b.getY();
        ballSpeedX = mouseX;
        ballSpeedY = mouseY;
    }
}

解决方案

There are a number of different types "double buffers". The basic is a simple off screen image that you update and this gets painted to the screen instead. If done right, painting the image is often faster then drawing graphics to the screen.

Another type is page flipping. That is, you have an active buffer which is always rendered to the screen and a off screen/scratch buffer which is what you actually render to. You then flip these buffers when you are ready to render the updates to the screen (this is closer to how film animation works).

The following example is a REALLY basic example of page flipping.

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.image.BufferedImage;
import static testdoublebuffer.TestDoubleBuffer.UPDATE;

public class AppletDoubleBuffer extends Applet {

    private BufferedPane pane;

    @Override
    public void init() {
        pane = new BufferedPane();
        setLayout(new BorderLayout());
        add(pane);
    }

    @Override
    public void start() {
        pane.start();
    }

    @Override
    public void stop() {
        pane.stop();
    }

    public class BufferedPane extends Panel {

        private BufferedImage activeBuffer;
        private BufferedImage scratch;
        private boolean running = false;

        public BufferedPane() {
        }

        public void start() {
            if (!running) {
                running = true;
                Thread thread = new Thread(new MainLoop());
                thread.setDaemon(true);
                thread.start();
            }
        }

        public void stop() {
            running = false;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        public void invalidate() {
            synchronized (UPDATE) {
                activeBuffer = null;
                scratch = null;
            }
            super.invalidate();
        }

        @Override
        public void update(Graphics g) {
            if (activeBuffer != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.drawImage(activeBuffer, 0, 0, this);
                g2d.dispose();
            }
        }

        public class MainLoop implements Runnable {

            private int delay = 1000 / 25;
            private int x = 0;
            private int velocity = 5;
            private int size = 10;

            public void update() {

                x += velocity;
                if (x + size >= getWidth()) {
                    x = getWidth() - size;
                    velocity *= -1;
                } else if (x <= 0) {
                    x = 0;
                    velocity *= -1;
                }

                if (getWidth() > 0 && getHeight() > 0) {
                    synchronized (UPDATE) {
                        if (scratch == null) {
                            scratch = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
                        }
                        Graphics2D g2d = scratch.createGraphics();
                        int y = (getHeight() - size) / 2;
                        g2d.setBackground(Color.BLUE);
                        g2d.clearRect(0, 0, getWidth(), getHeight());
                        g2d.setColor(Color.RED);
                        g2d.fillOval(x, y, size, size);
                        g2d.dispose();

                        // Flip the buffers...
                        BufferedImage tmp = activeBuffer;
                        activeBuffer = scratch;
                        scratch = tmp;
                    }
                }

            }

            @Override
            public void run() {
                while (running) {

                    long startTime = System.currentTimeMillis();

                    update();
                    repaint();

                    long duration = System.currentTimeMillis() - startTime;
                    if (duration < delay) {
                        try {
                            Thread.sleep(delay);
                        } catch (InterruptedException ex) {
                        }
                    }

                }
            }
        }
    }
}

I personally, would just skip using AWT and move to Swing which provides better/built in functionality for this type of thing.

这篇关于如何解决不良双缓冲的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆