Java 中的 repaint() 方法是否需要计时器或动作?

Does the repaint() method in Java require a timer or action?

我一直在研究一个小的 "game,",我认为它叫做 Pachinko。我上传了一张游戏画面的图片。我会丢球,让它们看起来像是从钉子上滚下来,最终被卡在底部 "gates."

我的问题是我无法使用 repaint() 方法。 repaint() 方法是否需要计时器或操作才能工作?请看这两个 classes。我在 GameWindow class(靠近底部)内创建了一个 Ball class 对象,并想更新球的 x/y 值使用 BallsetPos() 方法,然后重新绘制,因此球似乎在移动。

我做错了什么?我是否需要 update() 方法才能使用 repaint() 方法?

游戏Window图片:

public class GameWindow extends JPanel{

    private int numBalls = 0;

    // GameWindow Constructor (Sets Ball amount from user)
    public GameWindow(int balls){

        JFrame myFrame = new JFrame("Game Window");
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Globally set ball amount
        setBallAmount(balls);

        myFrame.add(this);  

        myFrame.setSize(325, 790);
        myFrame.setLocationRelativeTo(this);
        myFrame.setResizable(false);
        myFrame.setVisible(true);

    } // End GameWindow Constructor

    // Function setPegAmount;
    // Passes the amount of balls the user to class variable.
    public void setBallAmount(int balls)
    {
        numBalls = balls * 2;
    }

    public void paintComponent(Graphics g){

        super.paintComponent(g); // housekeeping, etc.
        this.setBackground(Color.WHITE); // Background

        int counter = 0; // count what number peg we are painting
        int row = 1;     // calculate what row we are creating
        int rowSpacer = 55;
        boolean evenRow = false;
        int columnSpacer = 60;

        // DRAW PEGS TO SCREEN (4 rows of 8, 4 rows of 7)
        for (int x = 0; x < 60; x++)
        {
            // For odd rows
            if (row % 2 == 1)
            {
                g.setColor(Color.BLACK);
                g.fillOval(rowSpacer - 40, columnSpacer, 10, 10);
                rowSpacer += 40;
                counter++;
            }
            // For Even rows
            else 
            {
                g.setColor(Color.BLACK);
                g.fillOval(rowSpacer - 20, columnSpacer, 10, 10);
                rowSpacer += 40;
                counter++;
            }

            // Check to see if we are finished with odd row
            if (counter % 8 == 0 && evenRow == false)
            {
                row++;
                rowSpacer = 55;
                columnSpacer += 60;
                evenRow = true;
                counter = 0;
            }
            else if(counter % 7 == 0 && evenRow == true) 
            {
                row++;
                rowSpacer = 55;
                columnSpacer += 60;
                evenRow = false;
                counter = 0;
            }
        } // END DRAWING PEGS TO SCREEN

        // DRAW RECTANGULAR WALLS TO SCREEN
        g.setColor(Color.BLACK);    // Wall Color
        g.fillRect(0, 0, 5, 760);   // LEFT Wall
        g.fillRect(315, 0, 5, 760); // RIGHT Wall
        g.fillRect(0, 0, 315, 5);   // TOP Wall
        g.fillRect(0, 755, 320, 5); // BOTTOM Wall

        // DRAW BOTTOM GATES
        int gateSeperator = 35;
        for (int x = 0; x < 7; x++)
        {
            g.setColor(Color.BLACK);
            g.fillRect(gateSeperator, 500, 10, 255);
            gateSeperator += 40;
        }

        // Create instance of ball object
        Ball myBall = new Ball();

        // Test draw ball
        myBall.drawBall(g);    // The ball is drawn to screen
        myBall.setPos(50, 50); // Change the x and y coordinates of the Ball

        repaint(); // Also tried "this.repaint();" but neither does anything


    } // Ends paintComponent

} // End GameWindow Class

Ball.java:

public class Ball{

    private int x = 5;
    private int y = 30;

    public void setPos(int xPos, int yPos)
    {
        x = xPos;
        y = yPos;
    }

    public void drawBall(Graphics g)
    {
        g.setColor(Color.GREEN);
        g.fillOval(x, y, 30, 30);

    }
}

我认为这不是解决问题的方法。 Swing 不是我的专长,但根据我的经验,在 paintComponent 中调用 repaint 是不正确的。

例如,告诉组件 repaint 本身。

/**
 * Tells the view to repaint itself.
 */
public void update() {
    repaint();
}

As soon as possiblerepaint 最终通过 paint 调用 paintComponent

/**
 * Paints the component.
 * @param g The graphics object for the view.
 */
@Override
protected void paintComponent(Graphics g) {
    // Draw some stuff...
}

所以在 paintComponent 内部调用 repaint 可能不是您想要的。你应该做的是使用 repaint 调用 paintComponent.

我认为您不能依赖于将 repaintupdate 放在 paintComponent 的末尾,因为我相信,多次调用 repaint 得到合并为一个 update。所以,是的,要正确地为对象设置动画,您应该考虑使用 Swing Timer。例如,

Timer timer = Timer(delay, action);
timer.start();

上面的计时器将在以毫秒为单位的延迟上调用给定的操作。请参阅 this 了解更多详情。