想知道是否有人能指出我正确的指示,我已经开发了一个乒乓球游戏,它需要双重缓冲,因为闪烁。我在这里尝试了一些帖子尝试使其工作,但我仍然是一个摇摆awt的初学者,任何帮助将是非常感谢。
public class PongPanel extends JPanel implements Runnable {
private int screenWidth = 500;
private int screenHeight = 300;
private boolean isPaused = false;
private boolean isGameOver = false;
private int playToPoints = 10;
private Padel player1,player2;
private Ball ball;
private Thread gameThread;
private Image dbImage;
private Graphics dbg;
public PongPanel() {
setPreferredSize(new Dimension(screenWidth,screenHeight));
setBackground(Color.BLACK);
setDoubleBuffered(true);
setFocusable(true);
requestFocus();
player1 = new Padel(Position.LEFT,screenWidth,screenHeight);
player2 = new Padel(Position.RIGHT,screenWidth,screenHeight);
ball = new Ball(10,screenWidth/2,screenHeight/2,Color.WHITE);
}
public void addNotify(){
super.addNotify();
startGame();
}
private void startGame(){
gameThread = new Thread(this);
gameThread.start();
}
@Override
public void run() {
while (!isGameOver) {
dbImage = createImage(screenWidth,screenHeight);
dbg = this.getGraphics();
if(!isPaused){
if(!gameOverCheck()){
updateGame();
paintComponents(dbg);
}
}else if(isPaused){
dbg.setColor(Color.ORANGE);
dbg.setFont(new Font("serif",Font.BOLD,50));
dbg.drawString("Paused", screenWidth/2-82, screenHeight/2);
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {e.printStackTrace();}
}
}
private boolean gameOverCheck(){
if(player1.getScore() == playToPoints){
dbg.setColor(player1.getColour());
dbg.setFont(new Font("serif",Font.BOLD,50));
dbg.drawString("Player 1 Wins!", screenWidth/2 - 161, screenHeight/2);
setGameOver(true);
return true;
}else if(player2.getScore() == playToPoints){
dbg.setColor(player2.getColour());
dbg.setFont(new Font("serif",Font.BOLD,50));
dbg.drawString("Player 2 Wins!", screenWidth/2 - 161, screenHeight/2);
setGameOver(true);
return true;
}
return false;
}
private void updateGame(){
ball.move(screenWidth,screenHeight,player1,player2);
player1.aiForPadel(screenWidth, screenHeight, ball.getX(), ball.getY());
player2.aiForPadel(screenWidth, screenHeight, ball.getX(), ball.getY());
}
@Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
dbg.setColor(Color.BLACK);
dbg.fillRect(0, 0, screenWidth+20, screenHeight+20);
dbg.setColor(Color.WHITE);
dbg.drawLine(screenWidth/2, 0, screenWidth/2, screenHeight);
dbg.setFont(new Font("serif",Font.BOLD,32));
dbg.drawString(player1.getScore()+"", screenWidth/2-40, screenHeight - 20);
dbg.drawString(player2.getScore()+"", screenWidth/2+20, screenHeight - 20);
ball.drawBall(dbg);
player1.drawPadel(dbg);
player2.drawPadel(dbg);
}
}
答案 0 :(得分:6)
有一个非常好的教程here,它描述了如何使用BufferStrategy来制作非闪烁动画。
重点是:
setIgnoreRepaint(true)
上调用Canvas
以阻止AWT重新绘制它,因为您通常会在动画循环中自行完成此操作。Graphics2D
获取BufferStrategy
对象(而不是使用通过paintComponent(Graphics g)
传入的实例。答案 1 :(得分:3)
必须阅读AWT和Swing中的绘画机制
答案 2 :(得分:2)
基本问题是,你违反了Swing的基本绘画系统。 Swing使用“被动渲染”算法,只有在需要时才执行绘制。您可以通过repaint
调用向API提出有关何时应更新内容的建议。
根据您的代码,基本问题是,您使用自己的paintComponents
上下文调用Graphics
,但是系统正在使用它的油漆涂料通知将其丢弃,您正在与涂漆系统,而不是使用它。
如果操作正确,Swing组件已经是双缓冲的,因此除了实际使用API /系统之外,您不需要做任何“额外”操作。
我强烈建议您查看:
更好地了解绘画在Swing中的运作方式。
所以,让我们从...开始......
@Override
public void run() {
while (!isGameOver) {
dbImage = createImage(screenWidth, screenHeight);
dbg = this.getGraphics();
if (!isPaused) {
if (!gameOverCheck()) {
updateGame();
paintComponents(dbg);
}
} else if (isPaused) {
dbg.setColor(Color.ORANGE);
dbg.setFont(new Font("serif", Font.BOLD, 50));
dbg.drawString("Paused", screenWidth / 2 - 82, screenHeight / 2);
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
paint
方法。当系统要更新组件时,系统将执行此操作。我强烈建议阅读:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.text.Position;
public class PongPanel extends JPanel implements Runnable {
private int screenWidth = 500;
private int screenHeight = 300;
private boolean isPaused = false;
private boolean isGameOver = false;
private int playToPoints = 10;
private Padel player1, player2;
private Ball ball;
private Timer gameThread;
public PongPanel() {
setPreferredSize(new Dimension(screenWidth, screenHeight));
setBackground(Color.BLACK);
setDoubleBuffered(true);
setFocusable(true);
requestFocus();
player1 = new Padel(Position.LEFT, screenWidth, screenHeight);
player2 = new Padel(Position.RIGHT, screenWidth, screenHeight);
ball = new Ball(10, screenWidth / 2, screenHeight / 2, Color.WHITE);
}
public void addNotify() {
super.addNotify();
startGame();
}
private void startGame() {
gameThread = new Timer(30, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateGame();
gameOverCheck();
if (isGameOver) {
repaint();
return;
}
if (!isPaused) {
if (!gameOverCheck()) {
updateGame();
}
}
repaint();
}
});
gameThread.start();
}
private boolean gameOverCheck() {
if (player1.getScore() == playToPoints) {
setGameOver(true);
return true;
} else if (player2.getScore() == playToPoints) {
setGameOver(true);
return true;
}
return false;
}
private void updateGame() {
ball.move(screenWidth, screenHeight, player1, player2);
player1.aiForPadel(screenWidth, screenHeight, ball.getX(), ball.getY());
player2.aiForPadel(screenWidth, screenHeight, ball.getX(), ball.getY());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, screenWidth + 20, screenHeight + 20);
g2d.setColor(Color.WHITE);
g2d.drawLine(screenWidth / 2, 0, screenWidth / 2, screenHeight);
g2d.setFont(new Font("serif", Font.BOLD, 32));
g2d.drawString(player1.getScore() + "", screenWidth / 2 - 40, screenHeight - 20);
g2d.drawString(player2.getScore() + "", screenWidth / 2 + 20, screenHeight - 20);
ball.drawBall(g2d);
player1.drawPadel(g2d);
player2.drawPadel(g2d);
if (isGameOver) {
if (player1.getScore() == playToPoints) {
g2d.setColor(player1.getColour());
g2d.setFont(new Font("serif", Font.BOLD, 50));
g2d.drawString("Player 1 Wins!", screenWidth / 2 - 161, screenHeight / 2);
} else if (player2.getScore() == playToPoints) {
g2d.setColor(player2.getColour());
g2d.setFont(new Font("serif", Font.BOLD, 50));
g2d.drawString("Player 2 Wins!", screenWidth / 2 - 161, screenHeight / 2);
}
} else if (isPaused) {
g2d.setColor(Color.ORANGE);
g2d.setFont(new Font("serif", Font.BOLD, 50));
g2d.drawString("Paused", screenWidth / 2 - 82, screenHeight / 2);
}
g2d.dispose();
}
}
BufferedStrategy
已经有人建议,BufferStrategy
是一个可行的解决方案,可以让您完全控制绘画系统。它更复杂,但可以解决Swing使用的被动渲染系统的奇怪之处
答案 3 :(得分:-1)
我想你可以致电super(true);
第一件事,这只是告诉JPanel
它是双缓冲的...因为JPanel
的一个构造函数是:
public Jpanel(boolean isDoubleBuffered) {...}
我希望这可以帮助某人,即使它已经将近四年了。