Java 如何修复坏的双缓冲

Java 如何修复坏的双缓冲,java,graphics,awt,flicker,double-buffering,Java,Graphics,Awt,Flicker,Double Buffering,我试着遵循双缓冲教程,但我真的不知道我做错了什么。在我学习本教程之前,它是可以工作的,但是这里和那里仍然会偶尔闪烁。我有两个文件Game和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 ja

我试着遵循双缓冲教程,但我真的不知道我做错了什么。在我学习本教程之前,它是可以工作的,但是这里和那里仍然会偶尔闪烁。我有两个文件Game和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;
    }
}
import 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.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入javax.imageio.imageio;
公共类gameLoop扩展小程序实现Runnable、MouseListener、MouseMotionListener
{
公共整数x,y,计数器,鼠标,鼠标;
屏幕外的公众形象;
公共图形d;
公共布尔值向上、向下、向左、向右、按下;
公共缓冲区映像disk1、disk2、disk3、disk4、disk;
公共int ballSpeedX=-6;
公共int=3;
公开募捐
{
x=400;
y=200;
试一试{
disk1=ImageIO.read(新文件(“disk1.png”);
disk2=ImageIO.read(新文件(“disk2.png”);
disk3=ImageIO.read(新文件(“disk3.png”);
disk4=ImageIO.read(新文件(“disk4.png”);
}捕获(IOE1异常){
e1.printStackTrace();
}
while(true)
{
如果(x>=(854-150))
{
ballSpeedX=ballSpeedX*-1;
}
如果(y>=(480-140))
{
鲍尔斯皮蒂=鲍尔斯皮蒂*-1;
}
如果(y<(0-10))
{
鲍尔斯皮蒂=鲍尔斯皮蒂*-1;
}
如果(x<(0-10))
{
ballSpeedX=ballSpeedX*-1;
}
x=x+ballSpeedX;
y=y+y;
计数器++;
如果(计数器>=4)
计数器=0;
如果(计数器==0)
disk=disk1;
如果(计数器==1)
disk=disk2;
如果(计数器==2)
disk=disk3;
如果(计数器==3)
disk=disk4;
系统输出打印项次(计数器);
重新油漆();
试一试{
睡眠(30);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公共无效mouseClicked(MouseEvent e){}
公共无效mouseenterned(MouseEvent e){}
公共无效mouseExited(MouseEvent e){}
public void mouseMoved(MouseEvent m){}
公共空间鼠标按下(MouseEvent m)
{
}
公共无效MouseEvent(MouseEvent m)
{
按下=假;
}
公共无效鼠标标记(鼠标事件e){
PointerInfo a=MouseInfo.getPointerInfo();
点b=a.getLocation();
mouseX=(int)b.getX();
mouseY=(int)b.getY();
ballSpeedX=鼠标;
巴利=老鼠;
}
}
当您试图覆盖小程序中的
update(Graphics g)
方法时,应为小写

应该如此

@Override
public void update(Graphics gfx)
{
    paint(gfx);
}
至于改变背景,背景只是一个覆盖屏幕的大矩形,使其成为某种颜色。在
绘制
中,您正在执行
clearRect
,这将清除屏幕。设置颜色后,只需将其切换到
fillRect

可能看起来像

public void paint(Graphics g)
{
    //setColor to whatever you want
    //fillRect to cover the screen
}
但在执行此操作时,必须记住的一件事是不要混淆两个图形对象。作为一个概念,双缓冲的工作原理是先将其绘制到内存(在屏幕外的图像上绘制),然后再绘制到屏幕。您希望始终在屏幕外的图像上绘制,因为它的速度要快得多(并且我们会丢失闪烁)

因此,请确保您正在执行
imageGraphicsObject.setColor
not
screenGraphicsObject.setColor
或imageGraphicsObject.fillRect
not
screenGraphicsObject.fillRect`。否则你就不再是双缓冲了

当您试图覆盖小程序中的
update(Graphics g)
方法时,应为小写

应该如此

@Override
public void update(Graphics gfx)
{
    paint(gfx);
}
至于改变背景,背景只是一个覆盖屏幕的大矩形,使其成为某种颜色。在
绘制
中,您正在执行
clearRect
,这将清除屏幕。设置颜色后,只需将其切换到
fillRect

可能看起来像

public void paint(Graphics g)
{
    //setColor to whatever you want
    //fillRect to cover the screen
}
但在执行此操作时,必须记住的一件事是不要混淆两个图形对象。作为一个概念,双缓冲的工作原理是先将其绘制到内存(在屏幕外的图像上绘制),然后再绘制到屏幕。您希望始终在屏幕外的图像上绘制,因为它的速度要快得多(并且我们会丢失闪烁)


因此,请确保您正在执行
imageGraphicsObject.setColor
not
screenGraphicsObject.setColor
或imageGraphicsObject.fillRect
not
screenGraphicsObject.fillRect`。否则就不再是双缓冲。

有许多不同类型的“双缓冲区”。基本的是一个简单的屏幕外图像,您可以更新它,并将其绘制到屏幕上。如果操作正确,绘制图像通常比在屏幕上绘制图形更快

另一种类型是翻页。也就是说,您有一个始终渲染到屏幕的活动缓冲区和一个实际渲染到的屏幕外/临时缓冲区。然后,在准备将更新渲染到屏幕时翻转这些缓冲区(这更接近于电影动画的工作方式)

下面的示例是翻页的一个非常基本的示例

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) {
                        }
                    }

                }
            }
        }
    }
}

import java.applet.applet;
导入java.awt.BorderLayout;
进口