How to move animation clockwise?

3

Well, I'm developing a project that simulates the controlled environment of train tracks, where I have 3 trains running clockwise, where the three pass through the same place in certain sections. My first question is, how to make the movement of these trains that in the figure below represented by comics, and consequently to be able to change the speed of each one of them.

Inmycode,thereisonlythegraphicpart,becauseIjustdonotknowhowtodevelopanimationobjects.

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

}
    
asked by anonymous 03.08.2017 / 20:31

1 answer

3

I was able to do this:

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 speed of the animation (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 Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(...) to call a Runnable every 1/20 seconds, rounded to an integer of milliseconds (that is, if you want 30 frames per second, it would give 33 milliseconds per frame, not 33 1 / 3 milliseconds per frame).

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

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 at each step and that it does not end up either standing still or forcing a movement in every frame of animation.

Note that I have a class for Trem and one for Trilho . Both inherit from JComponent , and therefore are Swing components and drawn by Swing. Where I need to, I override method paintComponent , not paint .

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

The mover method of the Trem class discovers where the train is and moves it in the proper direction. The approach I used is not the most efficient, but it should work for you. This approach consists of calculating the position iteratively, pixel by pixel according to speed, so that the curves of the rails are obeyed. The ideal approach would calculate the final position without having to use for for this.

    
03.08.2017 / 22:25