How to move animation in a clockwise direction?

Asked

Viewed 187 times

2

Good guys, I’m developing a little project that aims to simulate the controlled environment of train tracks, where I have 3 trains circulating in a clockwise direction, where the three pass by the same place in certain stretches. My doubt first is, how to make the movement of these trains that in the figure below represented by comics, and consequently be able to change the speed of each one of the same.

screenshot

In my code, there is only the graphic part, because I just don’t know how to develop the animation of objects.

public class SistemasOperacionais extends JFrame {

    public SistemasOperacionais(){
        setSize(1200,900);
        setTitle("Semáforo");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);        
    }

    public void paint(Graphics g){
        g.drawRect(300, 100, 300, 170);
        g.fillRect(350, 95, 10, 10);
        g.drawRect(600, 100, 300, 170);
        g.fillRect(650, 95, 10, 10);
        g.drawRect(450, 270, 300, 170);
        g.fillRect(445, 330, 10, 10);
    }

    public static void main(String[] args) {
       new SistemasOperacionais();
    }

}
  • Question follow-up: https://answall.com/q/226640/132

1 answer

3


I got it this way:

package trens;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;

public class Trens {

    private static final double QUADROS_POR_SEGUNDO = 20.0;

    public static void preparar() {
        JFrame t = new JFrame();
        t.setLayout(null);
        t.setSize(1200, 900);
        t.setTitle("Semáforo");
        t.setLocationRelativeTo(null);
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Trilho t1 = new Trilho(300, 100, 300, 170);
        Trilho t2 = new Trilho(600, 100, 300, 170);
        Trilho t3 = new Trilho(450, 270, 300, 170);
        Trem a = new Trem(t1, Color.BLUE, 350, 100, -170.0);
        Trem b = new Trem(t2, Color.GREEN, 650, 100, 0.5);
        Trem c = new Trem(t3, Color.RED, 450, 335, 44.0);
        t.add(a);
        t.add(b);
        t.add(c);
        t.add(t1);
        t.add(t2);
        t.add(t3);
        Runnable moverTudo = () -> {
            EventQueue.invokeLater(() -> {
                a.mover(1 / QUADROS_POR_SEGUNDO);
                b.mover(1 / QUADROS_POR_SEGUNDO);
                c.mover(1 / QUADROS_POR_SEGUNDO);
            });
        };
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(moverTudo, 0, (int) (1000 / QUADROS_POR_SEGUNDO), TimeUnit.MILLISECONDS);
        t.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(Trens::preparar);
    }

    public static class Trilho extends JComponent {
        public Trilho(int x, int y, int width, int height) {
            this.setBounds(x, y, width, height);
            this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        }
    }

    public static class Trem extends JComponent {
        private Color cor;
        private Trilho trilho;
        private int x;
        private int y;
        private double velocidade; // pixels por segundo
        private double restante; // Frações de pixels que faltou andar.

        public Trem(Trilho trilho, Color cor, int x, int y, double velocidade) {
            this.trilho = trilho;
            this.cor = cor;
            this.x = x;
            this.y = y;
            this.velocidade = velocidade;
            this.setBounds(x - 5, y - 5, 10, 10);
        }

        @Override
        public void paintComponent(Graphics g) {
            g.setColor(cor);
            g.fillRect(0, 0, getWidth(), getHeight());
        }

        public void mover(double deltaT) {
            if (velocidade == 0) return;
            boolean sentidoHorario = velocidade > 0;
            double distancia = Math.abs(restante + velocidade * deltaT);
            int tLeft = trilho.getX();
            int tTop = trilho.getY();
            int tRight = tLeft + trilho.getWidth();
            int tBottom = tTop + trilho.getHeight();

            for (int i = 0; i < (int) distancia; i++) {
                // Se deve ir à esquerda:
                if (x > tLeft && y == (sentidoHorario ? tBottom : tTop)) {
                    x--;
                // Se deve ir à direita:
                } else if (x < tRight && y == (sentidoHorario ? tTop : tBottom)) {
                    x++;
                // Se deve ir para cima:
                } else if (y > tTop && x == (sentidoHorario ? tLeft : tRight)) {
                    y--;
                // Se deve ir para baixo:
                } else if (y < tBottom && x == (sentidoHorario ? tRight : tLeft)) {
                    y++;
                // Se não for nenhum dos anteriores, o trem está descarrilhado. Coloca de novo no trilho.
                } else {
                    x = tLeft;
                    y = tTop;
                }
            }
            restante = distancia % 1;
            setLocation(x - 5, y - 5);
        }
    }
}

The animation speed (not that of the trains) is defined by that constant QUADROS_POR_SEGUNDO. As defined in 20, it will (re)calculate the position of objects 20 times per second. I use the Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(...) to call a Runnable every 1/20 seconds, rounded into an integer number of milliseconds (i.e., if you want 30 frames per second, it would give 33 milliseconds per frame, not 331/3 milliseconds per frame).

The blue train is at a speed of -170.0 pixels per second. That is, it goes pretty fast counterclockwise.

The red train is at a speed of 44.0 pixels per second clockwise.

The green train is at a speed of 0.5 pixels per second. That is, it moves very slowly clockwise. I put this small value to prove that it works correctly even if the speed is less than one pixel each step and that it does not end up neither staying still nor forcing a movement in each frame of animation.

Note that I have a class for the Trem and one for the Trilho. Both inherit from JComponent, and therefore are Swing components and designed by Swing. Where it is needed, I write the method paintComponent, and not the paint.

I use the calls to EventQueue.invokeLater for do not manipulate Swing objects outside the EDT. There are three threads here: the EDT, the main thread and the Executors. Therefore, so that the components are manipulated only in the EDT, the other two threads perform all their work only through the EventQueue.invokeLater.

Already the method mover class Trem find out where part of the train is and move it in the right direction. The approach I used is not the most efficient, but it should work in your case. This approach consists of calculating the position iteratively, pixel by pixel according to the speed, so that the curves of the rails are obeyed. The ideal approach would calculate the final position without using a for for that reason.

screenshot

  • Green stays still, that’s how it works?

  • Perfect @Articuno you answered the question and backed up in a clear and efficient way, mto obgdo. Now I will try to implement the rest.

  • @Carlosdiego actually the author of this excellent answer was Victor, I only commented because after reading it, I was very curious to see it working. : D

  • @No, green moves very slowly. Watch it carefully.

  • Ah vdd, sorry... kk Mto grateful for the help @Victor Stafusa

  • In case to be able to dynamize and to choose the speed in the own screen, as it would be?

  • @Carlosdiego You could have a method setVelocidade(double) in your class Trem and put somewhere one or more JButton, JTextField, JOptionPane, etc. to call the setters.

  • huum.. I will try to apply @Victorstafusa

  • @Victorstafusa used the Slider component to set the speeds of each train, as I do to play the Jslider value on the corresponding train speed?

  • @Carlosdiego It must be something similar to a.setVelocidade(seuSlider.getValue());.

  • @Victorstafusa updated my code in the question, you can guide me, because I do not know apply in the code =[

  • @Carlosdiego In this case it would be better to create a new question, even to draw the attention of other people as well and prevent this one from becoming one chameleon question.

  • Ah understood, then blz. Create here, vlws

Show 8 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.