1

i'm working on a Pong game now and I my ball animation is going too fast. I want to add a timer to my animation but I really don't know how to do it. I tried it with some code i found on the internet but it don't work. please help me :(

here is my code :

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

}

MTHeadss
  • 245
  • 1
  • 3
  • 14
  • 1
    1) It does not work ... my crystal ball got broken very recently so please describe what you expect would happen and what actually happens 2) Here is my code ... the code you posted is way too long, and won't even compile. 3) Your whole 'animation' thing is based on calling `repaint` over and over again (in the timer and in code paths in your paint method). So I do not see the added value of the timer, and I am unsure on what you try to achieve by using it – Robin Apr 05 '12 at 21:15
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Apr 05 '12 at 21:21
  • @trashgod +1 I should have remembered that example. Would have saved me a lot of type-work. – Robin Apr 05 '12 at 21:36

3 Answers3

3

I am not too familiar with animations, but what I think you need to be doing is use the timer to move the ball a certain distance at fixed time intervals.

Your current code schedules (emphasis on schedule, and not perform) a repaint in almost every paint call (through the call to the move method). This will make it very hard to control the speed of the ball. You do not know how many repaints will actually be performed, hence you do not know how fast the ball moves (due to the fact that multiple scheduled repaints can be grouped into one repaint). Adding a Timer in the mix to perform some extra repaints will not help (and certainly not a timer which schedules repaints every second ... this would result in a 1FPS framerate, which looks so 1950 ).

If you would use your timer to change the coordinates of the ball at fixed time intervals (50ms, 100ms, ... experiment a bit) and schedule a repaint you have full control over the speed of the ball. Even if two repaint calls of the timer are grouped, the ball will skip a position but the speed will be consistent. And when you go up a level, just increase the number of times the Timer code get triggered by decreasing the delay.

You might want to read the freely available Animation chapter of the Filthy Rich Clients book, which features more free excerpts and code examples. You might also like to examine the examples seen here.

Community
  • 1
  • 1
Robin
  • 36,233
  • 5
  • 47
  • 99
1

Use a Timer from java.util package:

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)
Andrejs
  • 26,885
  • 12
  • 107
  • 96
  • Since Swing GUIs need to be constructed and updated on the EDT, it is generally simpler to use a Swing based `Timer` (which provides that feature automatically). – Andrew Thompson Apr 05 '12 at 21:20
  • Where do I need to put those line of code, because I tried it and it do nothing. Do I need to call a method ? – MTHeadss Apr 05 '12 at 21:25
  • @MTHeadss Place it In your main() or even PlayPanel() constructor – Andrejs Apr 05 '12 at 21:29
  • @AndrewThompson true, with normal timer you'd have to do SwingUtilities.invokeLater() inside run() – Andrejs Apr 05 '12 at 21:31
  • 1
    @AndrewThompson Isn't repaint not one of those few methods which can be called on any Thread, so in this case it was correct (although I do not find it in the documentation). But it is in general good advice to stick to Swing timers when working with UIs. – Robin Apr 05 '12 at 21:35
  • @Robin Your point does ring a bell, perhaps it was mentioned in an answer within the last few days. – Andrew Thompson Apr 05 '12 at 21:36
0

The problem is that You are moving the ball by one pixel for every loop, I think that you should change the x and y coordinatea from int to double, introduce a new variable named speed with the value 0.1 and adding this speed to the coordinates. Then the ball should move one pixel for every 10 game loops, maybe a smaller value should be needed, but you'll have to tweak it

Hope it helps

nMoncho
  • 370
  • 2
  • 8
  • 3
    And after tweaking like this for a few hours, you send your code/program to a friend with a much slower/faster machine, and all your tweaking was for nothing. – Robin Apr 05 '12 at 21:25
  • Yeah I forgot about that, nice catch. Although I think it should be solved if a sleep call was added so it would be posible to control the amount of loop per second – nMoncho Apr 05 '12 at 22:00
  • A sleep call on the EDT is not done. See the answer of Erkan Haspulat and the comments on that one – Robin Apr 06 '12 at 06:11