1

I want to animate a rectangle in a specific pattern. I was told to use a SwingTimer for animation instead of a Thread.

My plan was to animate a rectangle moving forward until it hits the end of the frame. Then it moves down by one unit(The height of the rectangle, so in my case 30), and then moves backwards; and when it hits the end, there it moves down again and so on.

Here´s a sketch of how I want it to move

Now the problem with the SwingTimer is that the whole operation is a continuous loop so the rectangle doesn´t move the way I want it to. In order for this to work, I guess I´ve to start and stop the loop of some methods which is complicated and I don´t know how to do it properly .

So how can I animate the rectangle the way I want it to? Is SwingTimer really the proper way to do such things or are other methods better?

Here´s the code I´ve got so far. I´m aware that it´s not much and that ActionPerformed does a completely different animation.

import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;


    public class Test extends javax.swing.JPanel implements ActionListener{
    
        private int x = 0;
        private int y = 0;
        Timer tm = new Timer(50, this);
    
        public Test() {
            initComponents();
        }
    
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(new java.awt.Color(102, 102, 102));
            g.fillRect(x, y, 30, 30);
            tm.start();
        }
    
        public void moveForward() {
            x = x + 30;
            repaint();
            System.out.println("(" + x + "|" + y + ")");
        }
    
        public void moveBackwards() {
            x = x - 30;
            repaint();
            System.out.println("(" + x + "|" + y + ")");
        }
    
        public void moveDown() {
            y = y + 30;
            repaint();
            System.out.println("(" + x + "|" + y + ")");
        }
    
        public void moveUp() {
            y = y - 30;
            repaint();
            System.out.println("(" + x + "|" + y + ")");
        }
    
        public void actionPerformed(ActionEvent e) {
           moveForward();
           if (x >= 270){
               moveDown();
              }
            }
        
        public static void main(String[] args) {
            Test t = new Test();
            JFrame f = new JFrame();
            f.setSize(300, 300);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(t);
            f.setVisible(true);
        }
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • @trashgod i think he tried to say that this is his implementation of `actionPerformed()` and he does not know how to change it to be correct. – Tobias Nov 02 '20 at 13:07
  • *Now the problem with the SwingTimer is that the whole operation is a continuous loop* - no it is not a loop. All a Timer does is generate an event. You then respond to the event. See: https://stackoverflow.com/a/33907282/131872 for a simple example of scrolling text. Your logic will be different because need to change the "state" of the scrolling dynamically to either scroll forward or backwards. But the key point is that there is no looping code in the ActionListener. – camickr Nov 02 '20 at 15:14

1 Answers1

3

What you have done so far looks pretty good. You only need your action method to work properly. For that i would use a class variable called direction:

private boolean direction = true;

Now in your action method you move the rectangle either forward or backwards, depending on direction. And if it hits the end you move the rectangle down and invert direction:

public void actionPerformed(ActionEvent e) {
    
    if (direction){
        moveForward();
    }
    else {
        moveBackwards();
    }

    //Check if it is at the end
    if(((x >= 270) && (direction)) || ((x <= 30) && (!direction))) {
        moveDown();
        direction = !direction;
    }
}

The if clause is a little bit complicated, but you can split it up, if you want it to be more readable.

Tobias
  • 383
  • 2
  • 12