Графическое изображение Java постоянно мигает - PullRequest
0 голосов
/ 06 июня 2018

Я пытался сделать игру в тетрис.Но мой графический интерфейс jframe постоянно мигает.Но когда я комментирую приведенную ниже строку в коде, она не мигает.Может кто-нибудь помочь, пожалуйста?

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 голосов
/ 06 июня 2018

Контейнеры верхнего уровня, такие как JFrame, не имеют двойной буферизации, что вызывает мерцание.

Это только одна из многих причин, по которой вам не следует переопределять paint контейнеров верхнего уровня.Вместо этого начните с JPanel и переопределите его paintComponent. Компоненты Swing по умолчанию автоматически получают двойную буферизацию.

Посмотрите на Выполнение пользовательской рисования и Рисование в AWT и 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;

- довольно хороший признак плохого дизайна.В хорошем коде не должно быть необходимости переходить на основе «goto» или «label».

Вы должны думать о себе как о «главном цикле» в очень линейном наборе операций, обновлять состояние, проверятьдля столкновений обновите пользовательский интерфейс.Сохраняйте это простым, сохраняйте его быстрым

Вы также обнаружите, что API привязок ключей решит все проблемы наследования KeyListener

...