Search code examples
javaswinganimationrectangles

Animating a Rectangle in a specific pattern


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

Solution

  • 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.