2012-04-05 66 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