乒乓球比赛 - 为球类动画添加计时器

时间:2012-04-05 21:04:41

标签: java swing timer jpanel pong

我正在制作Pong游戏,而我的球动画速度太快了。我想为我的动画添加一个计时器,但我真的不知道该怎么做。我尝试了一些我在互联网上找到的代码,但它不起作用。请帮帮我:(

这是我的代码:

private static final long serialVersionUID = 1L;

private int posX = SCREEN_WIDTH / 2;
private int posY;
int x;
int y;
private int scoreCountPlayer1 = 0;
private int scoreCountComputer = 0;

private int delay = 10;

  // Create a timer with delay 1000 ms
private Timer timer = new Timer(delay, new TimerListener());


private Rectangle ballRect;
private Rectangle padRect;

private int upLimit;
private int downLimit;
private int padPosition;

public boolean backX = false;
public boolean backY = false;
public boolean move = true;

public Point posMouse = new Point();

private int playPanelWidth;
private int playPanelHeight;

private int padPanelWidth;
private int padPanelHeight;

private int panPanelWidth;
private int panPanelHeight;

private JLabel player1Score = new JLabel("1");
private JLabel ComputerScore = new JLabel("0");

private JPanel panPlayer1;
public JPanel panComputer;

public JPanel padPlayer1;
public JPanel padComputer;

public ScorePanel scorePanel;

private JButton but_Escape = new JButton("Press Space to continue !");

/*
 * Constructeur de classe : PlayPanel.java
 */
// ==============================================
public PlayPanel() {
    super(new BorderLayout());
    setBackground(PANPLAY_COLOR);

    scorePanel = new ScorePanel();

    panPlayer1 = new JPanel();
    panComputer = new JPanel();

    padPlayer1 = new JPanel();
    padComputer = new JPanel();

    padPlayer1.setBackground(Color.DARK_GRAY);
    padComputer.setBackground(Color.DARK_GRAY);

    padPlayer1.setPreferredSize(PADPANEL_SIZE);
    padComputer.setPreferredSize(PADPANEL_SIZE);

    panPlayer1.setBackground(PANPLAY_COLOR);
    panComputer.setBackground(PANPLAY_COLOR);

    panPlayer1.add(padPlayer1);
    panComputer.add(padComputer);

    add(panPlayer1, BorderLayout.WEST);
    add(panComputer, BorderLayout.EAST);
    add(scorePanel, BorderLayout.SOUTH);

    player1Score.setFont(FONT_SCORE);
    ComputerScore.setFont(FONT_SCORE);

    addMouseMotionListener(this);

    timer.start();

}

/*
 * Add the ball
 */
// ==============================================
public void paintComponent(Graphics g) {

    super.paintComponent(g);

    Graphics2D g2 = (Graphics2D) g;

    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(Color.BLACK);

    initBall(g2);

    // trait épais
    g2.setColor(Color.DARK_GRAY);

    g2.setStroke(new BasicStroke(10));
    g2.drawLine((getPlayPanelWidth() / 2) - 5, getPlayPanelHeight(),
            (getPlayPanelWidth() / 2) - 5, 0);
}

/*
 * Init ball
 */
// ==============================================
private void initBall(Graphics2D graphics2d) {

    Graphics2D g2 = graphics2d;

    x = getPosX();
    y = getPosY();

    ballRect = new Rectangle(posX, posY, BALL_WIDTH, BALL_HEIGHT);
    padRect = new Rectangle(playPanelWidth
            - (getPanComputer().getWidth() + 2), (int) getPosMouse().getY()
            - getPadPanelHeight() / 2, padPanelWidth, padPanelHeight);

    g2.fillOval(posX, posY, BALL_WIDTH, BALL_HEIGHT);

    if (posX == 763) {

        if (ballRect.intersects(padRect)) {

            System.out.println("collision");
            Move();

        } else {

            int posMouseY = getPosMouse().y;
            System.out.println("pas collision");
            stopBall(g2, posMouseY);
        }

    } else {
        Move();

    }
}

private void Move() {

    if (x < 1 + 15) {
        backX = false;
        scorePanel.getLab_Player1().setText("" + scoreCountPlayer1);
    }

    if (x > getWidth() - 52) {
        backX = true;
    }

    if (y < 1) {
        backY = false;
    }

    if (y > getHeight() - (SCOREPANEL_SIZE.getHeight() + BALL_HEIGHT)) {
        backY = true;
    }

    if (!backX) {
        setPosX(++x);
    }

    else {
        setPosX(--x);
    }

    if (!backY) {
        setPosY(++y);
    } else {
        setPosY(--y);
    }

    repaint();
}

private void stopBall(final Graphics2D g2, int posBallY) {
    move = false;
}

@Override
public void mouseDragged(MouseEvent arg0) {
}

@Override
public void mouseMoved(MouseEvent arg0) {

    // Définit les limite de le souris, la position
    // des pads et de la souris.
    upLimit = getPadPanelHeight() / 2;
    downLimit = playPanelHeight - scorePanel.getScorePanHeight()
            - (getPadPanelHeight() / 2);
    padPosition = playPanelHeight - scorePanel.getScorePanHeight()
            - (getPadPanelHeight());

    posMouse.setLocation(arg0.getX(), arg0.getY());

    setPosMouse(posMouse);


    if (arg0.getY() >= downLimit) {

        padPlayer1.setLocation(getPanPanelWidth() - 10, padPosition);
        padComputer.setLocation(0, padPosition);


    } else if (arg0.getY() <= upLimit) {

        padPlayer1.setLocation(getPanPanelWidth() - 10, 0);
        padComputer.setLocation(0, 0);


    } else {

        padPlayer1.setLocation(getPanPanelWidth() - 10,
                (int) posMouse.getY());
        padComputer.setLocation(0, (int) posMouse.getY()
                - (getPadPanelHeight() / 2));
    }
}

private class TimerListener implements ActionListener {
    /** Handle the action event */
    public void actionPerformed(ActionEvent e) {
      repaint();
    }
  }

}

3 个答案:

答案 0 :(得分:3)

我对动画并不太熟悉,但我认为你需要做的是使用计时器以固定的时间间隔将球移动一定距离。

您当前的代码计划(强调日程安排,而不是执行)几乎每次repaint次调用paint(通过调用move方法)。这将使得控制球的速度变得非常困难。你不知道实际会执行多少repaint,因此你不知道球移动的速度有多快(因为多个预定的重绘可以分成一个重绘)。在混合中添加Timer以执行一些额外的重新绘制将无济于事(当然也不是每秒安排重新绘制的计时器......这将导致1FPS帧速率,看起来如此1950)。

如果您使用计时器以固定的时间间隔(50ms,100ms,......实验一下)更改球的坐标并安排repaint您可以完全控制球的速度。即使计时器的两个repaint次呼叫被分组,球也将跳过一个位置,但速度将保持一致。当你上升一个级别时,只需通过减少延迟来增加触发Timer代码的次数。

您可能需要阅读freely available Animation chapter本书的Filthy Rich Clients,其中包含更多免费摘录和代码示例。您可能还想查看here所见的示例。

答案 1 :(得分:1)

使用java.util包中的计时器:

new Timer().scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            repaint();
        }
    }, 20, 20); // replace 20 with how often you want it to be called (in milliseconds)

答案 2 :(得分:0)

问题在于你为每个循环移动球一个像素,我认为你应该将x和y坐标从int更改为double,引入一个名为 speed 的新变量值0.1并将此速度添加到坐标。 然后球应该每10个游戏循环移动一个像素,可能需要一个较小的值,但你必须调整它

希望有所帮助