7

想知道是否有人能指出我正确的方向,我开发了一个乒乓球游戏,由于闪烁,它需要双缓冲。我尝试了这里的一些帖子以尝试使其工作,但我仍然是摇摆 awt suff 的初学者,任何帮助都会非常感谢。

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);
 }
}
4

4 回答 4

6

这里有一个非常好的教程,它描述了如何使用BufferStrategy来生成不闪烁的动画。

重点是:

  • 调用setIgnoreRepaint(true)顶层Canvas以防止 AWT 重新绘制它,因为您通常会在动画循环中自己执行此操作。
  • 从(而Graphics2D不是BufferStrategy使用通过paintComponent(Graphics g).
于 2010-01-14T11:15:36.633 回答
3

AWT 和 Swing 中的绘画机制必读

在 AWT 和 Swing 中绘画

于 2010-01-14T11:21:43.353 回答
2

基本问题是,你违反了 Swing 的基本绘画系统。Swing 使用“被动渲染”算法,仅在需要时执行绘制。您可以通过调用向 API 提出关于何时更新某些内容的建议repaint

根据您的代码,基本问题是,您正在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();
        }
    }
}
  • Swing 不是线程安全的,您不应该从事件调度线程的上下文之外更新 UI
  • 你永远不应该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 使用的被动渲染系统的怪异之处

于 2018-05-17T05:36:23.973 回答
-1

我认为你可以调用super(true); 第一件事,这只是告诉JPanel它它是双缓冲的......因为其中一个JPanel构造函数是:

public Jpanel(boolean isDoubleBuffered) {...}

我希望这对某人有所帮助,即使已经将近四年了。

于 2014-06-24T19:25:27.357 回答