我尝试过双缓冲教程,我真的不知道我做错了什么。它在我做教程之前就已经工作了,但是这里和那里仍然偶尔闪烁。我有两个文件Game和gameLoop
游戏:
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;
}
}
答案 0 :(得分:2)
public void Update(Graphics gfx)
{
paint(gfx);
}
应该是小写,因为您试图覆盖Applet中的update(Graphics g)
方法。
所以它应该是
@Override
public void update(Graphics gfx)
{
paint(gfx);
}
至于改变背景,背景只是一个覆盖屏幕并使其成为特定颜色的大矩形。在paint
中,您正在执行clearRect
,这会清除屏幕。而是在设置颜色后将其切换到fillRect
。
它可能看起来像
public void paint(Graphics g)
{
//setColor to whatever you want
//fillRect to cover the screen
}
当你这样做时,你必须要记住的一件事是不要混淆你的两个图形对象。作为一个概念,双缓冲通过首先绘制到内存(在屏幕外图像上绘制)然后到屏幕来工作。你想要总是在这个屏幕外的图像上绘制,因为它更快(并且我们失去了闪烁)。
因此,请确保您正在执行imageGraphicsObject.setColor
而非screenGraphicsObject.setColor
或imageGraphicsObject.fillRect not
screenGraphicsObject.fillRect`。否则你就不再是双缓冲了。
答案 1 :(得分:2)
有许多不同类型的“双缓冲区”。基本是一个简单的屏幕外图像,您更新后会将其绘制到屏幕上。如果做得好,绘制图像通常会更快,然后将图形绘制到屏幕上。
另一种类型是页面翻转。也就是说,你有一个活动缓冲区,它总是呈现在屏幕上,一个屏幕外/暂存缓冲区就是你实际呈现的内容。然后,当您准备好向屏幕呈现更新时,您可以翻转这些缓冲区(这更接近电影动画的工作方式)。
以下示例是页面翻转的一个非常基本的示例。
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) {
}
}
}
}
}
}
}
我个人,只是跳过使用AWT并转移到Swing,为这类事物提供更好/内置的功能。