2012-04-05 67 views
1

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

这里是我的代码:

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

}

+1

1)它不工作...我的水晶球最近坏了,所以请描述你期望会发生什么,实际发生了什么2)这是我的代码...你发布的代码太长了,甚至不会编译。 3)你的整个'动画'是基于重复调用'repaint'(在定时器和绘图方法中的代码路径中)。所以我没有看到定时器的附加价值,我不确定你试图通过使用它达到什么 – Robin 2012-04-05 21:15:17

+0

为了更好地帮助,请发布[SSCCE](http://sscce.org/)。 – 2012-04-05 21:21:58

+0

@trashgod +1我应该记住这个例子。本来会为我节省很多打字工作。 – Robin 2012-04-05 21:36:24

回答

3

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

您当前的代码时间表(强调时间表,而不是执行),几乎在每一个paint调用repaint(通过调用move方法)。这将会很难控制球的速度。你不知道有多少repaint实际上将被执行,因此你不知道球的移动速度有多快(因为多个计划重绘可以被分组成一个重绘)。在混音中添加Timer以执行一些额外的重绘将无济于事(当然,不是每秒计划重绘的计时器......这会导致1FPS帧率,看起来如此)。

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

您可能想要阅读Filthy Rich Clients这本书的freely available Animation chapter,该书有更多的免费摘录和代码示例。您可能还想查看看到的例子here

+0

谢谢,我将致力于此 – MTHeadss 2012-04-05 21:34:57

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) 
+0

由于Swing GUI需要在EDT上构建和更新,因此使用基于Swing的Timer(自动提供该功能)通常更简单。 – 2012-04-05 21:20:02

+0

我需要把那些代码行放在哪里,因为我试过了,它什么都不做。我需要调用一个方法吗? – MTHeadss 2012-04-05 21:25:26

+0

@Metheadss把它放在你的main()或者甚至是PlayPanel()构造函数中 – Andrejs 2012-04-05 21:29:24

0

的问题是,你是通过移动球每个循环一个像素,我认为你应该将x和y坐标从int变为double,引入一个名为的新变量速度的值为0.1,并将该速度添加到坐标。 然后将球移动到1个像素,每10圈的比赛,也许应该需要一个较小的值,但你必须调整它

希望它可以帮助

+3

经过几个小时的调整之后,您可以使用更慢/更快的机器将您的代码/程序发送给朋友,而您所做的所有调整都是无用的。 – Robin 2012-04-05 21:25:22

+0

是的,我忘记了,很好。虽然我认为如果加入睡眠呼叫应该可以解决,所以可以控制每秒循环的次数 – nMoncho 2012-04-05 22:00:58

+0

EDT上的睡眠呼叫没有完成。请参阅Erkan Haspulat的回答以及关于该问题的评论 – Robin 2012-04-06 06:11:07