Java Graphics绘图不断闪烁

时间:2018-06-06 08:01:17

标签: java graphics awt graphics2d repaint

我试图制作俄罗斯方块游戏。但我的jframe GUI连续闪烁。但是,当我在代码中评论下面的行时,它不会闪烁。有人可以帮忙吗?

map.draw((Graphics2D) g);

JDK版本 - 1.8 NetBeans - 7.4

代码文件链接如下。

package GUI;

import Maps.MapGenerator;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.Timer;

public class BrickBreaker extends javax.swing.JFrame implements KeyListener, ActionListener {

private MapGenerator map;

public BrickBreaker() {
    initComponents();
    this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
    this.setTitle("Test Tetris");
    //Map
    map = new MapGenerator(3, 7);
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
    time = new Timer(delay, this);
    time.start();
}

public void paint(Graphics g) {

    //background
    g.setColor(Color.black);
    g.fillRect(1, 1, 692, 592);

    //map
    map.draw((Graphics2D) g);

    //score
    g.setColor(Color.white);
    g.setFont(new Font("serif", Font.BOLD, 25));
    g.drawString("" + score, 560, 30);

    //border
    g.setColor(Color.yellow);
    g.fillRect(0, 0, 3, 592);
    g.fillRect(0, 0, 692, 3);
    g.fillRect(691, 0, 3, 592);

    //paddle
    g.setColor(Color.green);
    g.fillRect(playerPosX, 550, 100, 8);

    //ball
    g.setColor(Color.red);
    g.fillOval(ballPosX, ballPosY, 20, 20);

    g.dispose();
}

private boolean play = false;
private int score = 0;
private int totalBricks = 21;

private Timer time;
private int delay = 8;

private int playerPosX = 310;

private int ballPosX = 210;
private int ballPosY = 350;
private int ballXDir = -1;
private int ballYDir = -2;

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setPreferredSize(new java.awt.Dimension(700, 600));

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 525, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 403, Short.MAX_VALUE)
    );

    pack();
}// </editor-fold>                        

public static void main(String args[]) {
    /* Set the Nimbus look and feel */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
     * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new BrickBreaker().setVisible(true);
        }
    });
}

// Variables declaration - do not modify                     
// End of variables declaration                   
@Override
public void keyTyped(KeyEvent e) {
}

@Override
public void keyPressed(KeyEvent e) {
    try {

        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            if (playerPosX >= 600) {
                playerPosX = 600;
            } else {
                moveRight();
            }
        }

        if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            if (playerPosX < 10) {
                playerPosX = 10;
            } else {
                moveLeft();
            }
        }

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

public void moveRight() {
    play = true;
    playerPosX += 20;
}

public void moveLeft() {
    play = true;
    playerPosX -= 20;
}

@Override
public void keyReleased(KeyEvent e) {
}

@Override
public void actionPerformed(ActionEvent e) {
    time.start();

    if (play) {

        if (new Rectangle(ballPosX, ballPosY, 20, 20).intersects(new Rectangle(playerPosX, 550, 100, 8))) {
            ballYDir = -ballYDir;
        }

        A:
        for (int i = 0; i < map.map.length; i++) {
            for (int j = 0; j < map.map[0].length; j++) {
                if (map.map[i][j] > 0) {
                    int brickX = j * map.brickWidth + 60;
                    int brickY = i * map.brickHeight + 50;
                    int brickWidht = map.brickWidth;
                    int brickHeight = map.brickHeight;

                    Rectangle rect = new Rectangle(brickX, brickY, brickWidht, brickHeight);
                    Rectangle ballRect = new Rectangle(ballPosX, ballPosY, 20, 20);
                    Rectangle brickRect = rect;

                    if (ballRect.intersects(brickRect)) {
                        map.setBrickValue(0, i, j);
                        totalBricks--;
                        score += 2;

                        if (ballPosX + 19 <= brickRect.x || ballPosX + 1 >= brickRect.x + brickRect.width) {
                            ballXDir = -ballXDir;
                        } else {
                            ballYDir = -ballYDir;
                        }

                        break A;
                    }
                }
            }
        }

        ballPosX += ballXDir;
        ballPosY += ballYDir;
        if (ballPosX < 0) {
            ballXDir = -ballXDir;
        }
        if (ballPosY < 0) {
            ballYDir = -ballYDir;
        }
        if (ballPosX > 670) {
            ballXDir = -ballXDir;
        }
    }
    repaint();

}
}

地图生成器

package Maps;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;


public class MapGenerator {

public int map[][];
public int brickWidth;
public int brickHeight;

public MapGenerator(int row, int col) {
    map = new int[row][col];
    for (int i = 0; i < map.length; i++) {
        for (int j = 0; j < map[0].length; j++) {
            map[i][j] = 1;
        }
    }

    brickWidth = 240 / row;
    brickHeight = 150 / col;
}

public void draw(Graphics2D g) {
    for (int i = 0; i < map.length; i++) {
        for (int j = 0; j < map[0].length; j++) {
            if (map[i][j] > 0) {
                g.setColor(Color.black);
                g.fillRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);

                g.setStroke(new BasicStroke(3));
                g.setColor(Color.white);
                g.drawRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);

            }
        }
    }
}

public void setBrickValue(int value, int row, int col) {
    map[row][col] = value;
}

}

1 个答案:

答案 0 :(得分:0)

顶级容器(如JFrame)不是双缓冲的,这会导致闪烁。

这只是您不应该覆盖paint顶级容器的众多原因之一。相反,从JPanel开始并覆盖它paintComponent,默认情况下,Swing组件会自动为您双重缓冲。

请查看Performing Custom PaintingPainting in AWT and Swing,了解有关绘画在Swing中如何运作的详细信息。

更合适的解决方案可能会开始看起来像这样......

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private boolean play = false;
        private int score = 0;
        private int totalBricks = 21;

        private Timer timer;
        private int delay = 8;

        private int playerPosX = 310;

        private int ballPosX = 210;
        private int ballPosY = 350;
        private int ballXDir = -1;
        private int ballYDir = -2;
        private MapGenerator map;

        public TestPane() {
            setBackground(Color.BLACK);
            map = new MapGenerator(3, 7);
            timer = new Timer(delay, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (play) {

                        if (new Rectangle(ballPosX, ballPosY, 20, 20).intersects(new Rectangle(playerPosX, 550, 100, 8))) {
                            ballYDir = -ballYDir;
                        }

                        for (int i = 0; i < map.map.length; i++) {
                            for (int j = 0; j < map.map[0].length; j++) {
                                if (map.map[i][j] > 0) {
                                    int brickX = j * map.brickWidth + 60;
                                    int brickY = i * map.brickHeight + 50;
                                    int brickWidht = map.brickWidth;
                                    int brickHeight = map.brickHeight;

                                    Rectangle rect = new Rectangle(brickX, brickY, brickWidht, brickHeight);
                                    Rectangle ballRect = new Rectangle(ballPosX, ballPosY, 20, 20);
                                    Rectangle brickRect = rect;

                                    if (ballRect.intersects(brickRect)) {
                                        map.setBrickValue(0, i, j);
                                        totalBricks--;
                                        score += 2;

                                        if (ballPosX + 19 <= brickRect.x || ballPosX + 1 >= brickRect.x + brickRect.width) {
                                            ballXDir = -ballXDir;
                                        } else {
                                            ballYDir = -ballYDir;
                                        }
                                    }
                                }
                            }
                        }

                        ballPosX += ballXDir;
                        ballPosY += ballYDir;
                        if (ballPosX < 0) {
                            ballXDir = -ballXDir;
                        }
                        if (ballPosY < 0) {
                            ballYDir = -ballYDir;
                        }
                        if (ballPosX > 670) {
                            ballXDir = -ballXDir;
                        }
                    }
                    repaint();
                }
            });
            timer.start();
        }

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

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            //map
            map.draw((Graphics2D) g);

            //score
            g.setColor(Color.white);
            g.setFont(new Font("serif", Font.BOLD, 25));
            g.drawString("" + score, 560, 30);

            //border
            g.setColor(Color.yellow);
            g.fillRect(0, 0, 3, 592);
            g.fillRect(0, 0, 692, 3);
            g.fillRect(691, 0, 3, 592);

            //paddle
            g.setColor(Color.green);
            g.fillRect(playerPosX, 550, 100, 8);

            //ball
            g.setColor(Color.red);
            g.fillOval(ballPosX, ballPosY, 20, 20);

            g2d.dispose();
        }

    }

    public class MapGenerator {

        public int map[][];
        public int brickWidth;
        public int brickHeight;

        public MapGenerator(int row, int col) {
            map = new int[row][col];
            for (int i = 0; i < map.length; i++) {
                for (int j = 0; j < map[0].length; j++) {
                    map[i][j] = 1;
                }
            }

            brickWidth = 240 / row;
            brickHeight = 150 / col;
        }

        public void draw(Graphics2D g) {
            for (int i = 0; i < map.length; i++) {
                for (int j = 0; j < map[0].length; j++) {
                    if (map[i][j] > 0) {
                        g.setColor(Color.black);
                        g.fillRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);

                        g.setStroke(new BasicStroke(3));
                        g.setColor(Color.white);
                        g.drawRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);

                    }
                }
            }
        }

        public void setBrickValue(int value, int row, int col) {
            map[row][col] = value;
        }

    }

}

观测...

此...

A:
for (int i = 0; i < map.map.length; i++) {
    //...
            //...
                break A;

是糟糕设计的一个很好的迹象。不应该需要一个&#34; goto&#34;或&#34;标签&#34;基于良好的代码跳跃。

你必须想到你&#34;主循环&#34;在非常线性的操作集中,更新状态,检查冲突,更新UI。保持简单,保持快速

您还会发现the Key Bindings API将解决KeyListener

的所有继承问题