Java image move along points in list and use linear interpolation

后端 未结 1 2066
孤街浪徒
孤街浪徒 2020-12-07 05:53

I\'m trying to let an image follow a path. The points of this path are stored in an ArrayList. Right now the image jumps to the next point every two seconds, so I have to us

相关标签:
1条回答
  • 2020-12-07 06:13

    Let's break this down...

    Basically you want to move from one point (A) to another (B) over a period of time (t). A given point between A and B at a given point in time is a percentage of the difference between the two (where t is normalized as a fraction between 0 and 1)

    Timeline

    So, if A is 10 and B is 20 and t is 2 seconds, at 1 second p should be 15 (((B - A) * i) + A) where i is the normalized time difference of 0.5 (50% of 2 seconds = 1 second)

    So, given any point in time, you can calculate the difference between the two points and calculate the position it should be at.

    If you're wondering why I normalized the time, consider this, if you change t to be 4 seconds instead, the calculations don't change, we just need to calculate the normalized point in time (1 / 4 = 0.25) and run that back through the calculations to give us the desired result.

    So, what you need to know is how long it will take to go from point A to point B. Then you need some mechanism which can regularly check the amount of time that has passed and calculate the current position of the object between the two points. For this you could use a Swing Timer to tick at a regular interval (like 40 milliseconds for example) until 2 seconds have elapsed.

    Move from A to B

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.geom.Ellipse2D;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private Long startTime;
            private long playTime = 2000;
    
            private Point startPoint, endPoint;
            private Point pointOnTimeLine;
            private double pointInTime; // For rendering...
    
            public TestPane() {
                startPoint = new Point(0, 95);
                endPoint = new Point(190, 95);
                pointOnTimeLine = new Point(startPoint);
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (startTime == null) {
                            startTime = System.currentTimeMillis();
                        }
                        long now = System.currentTimeMillis();
                        long diff = now - startTime;
                        if (diff >= playTime) {
                            diff = playTime;
                            ((Timer) e.getSource()).stop();
                        }
                        double i = (double) diff / (double) playTime;
                        pointInTime = i;
    
                        pointOnTimeLine.x = (int) (startPoint.x + ((endPoint.x - startPoint.x) * i));
                        pointOnTimeLine.y = (int) (startPoint.y + ((endPoint.y - startPoint.y) * i));
    
                        repaint();
                    }
                });
    
                timer.start();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(Color.RED);
                g2d.fill(new Ellipse2D.Double(startPoint.x, startPoint.y, 10, 10));
                g2d.fill(new Ellipse2D.Double(endPoint.x, endPoint.y, 10, 10));
                g2d.setColor(Color.GREEN);
                g2d.fill(new Ellipse2D.Double(pointOnTimeLine.x, pointOnTimeLine.y, 10, 10));
                g2d.dispose();
            }
    
        }
    
    }
    

    Okay, "but how does this help me?" I hear you asking. Well, the reality is, this is the basics for moving between multiple points.

    In your code you have 4 key points in time, evenly distributed, over which the object must move, this means that each point is roughly 33% apart along the time line.

    When you calculate the current position along the time line, you need to find the two points that it is between (0-33 is the first and second point, 34-66 is the second and third and 67 > is the third and forth) and then calculate the position of the object between these points.

    It's a little more complicated, as you need to take into consideration the amount of time between the two points as a fraction of the over all time, but since the distance in time between the points is mostly even, it shouldn't play a big factor.

    This is demonstrated here and here so you will have to forgive me for not reposting the code again.

    Now, for my money, I'd also invest some time into getting to know an animation library like Timing Framework and/or Trident and/or Universal Tween Engine

    0 讨论(0)
提交回复
热议问题