Move image in a spiral fashion in java

前端 未结 1 1099
抹茶落季
抹茶落季 2020-11-30 15:48

I am trying to make a simple animated intro. I have an image I am trying to move from the bottom left of the screen to the center of the screen in a clockwise spiral motion.

相关标签:
1条回答
  • 2020-11-30 16:28

    Animation is the illusion of movement over time. Normally I would use something like the Timing Framework (or Trident or Universal Tween Engine) as the base of the animation, these provide better support for things like ease-in and ease-out.

    The following example just makes uses of a simple javax.swing.Timer. I use this because it's safer to use with Swing, as it allows me to update the state of the UI from within the context of the Event Dispatching Thread, but doesn't block it (preventing it from updating the screen).

    The following example uses a concept of a timeline and key frames. That is, at some point in time, something must happen. The timeline then provides the means for blending between those "key" points in time.

    I, personally, like to work in abstract concepts, so the timeline is simply measured in a percentage from 0-1, which allows me to provide a variable time span. This allows me to adjust the speed of the animation without the need to change anything.

    Neko

    As you (should) be able to see, the last two legs only need to move half the distance, so they are slower than the other three legs, so, technically, they only need half the time to complete...but I'll leave it up to you to nut out the maths for that ;)

    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.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.Map;
    import java.util.TreeMap;
    import javax.imageio.ImageIO;
    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 {
    
            protected static final int PLAY_TIME = 6000;
    
            private Timeline timeline;
            private long startTime;
    
            private Point imgPoint;
            private BufferedImage img;
    
            public TestPane() {
    
                try {
                    img = ImageIO.read(new File("C:/Neko.png"));
    
                    imgPoint = new Point(0, 200 - img.getHeight());
    
                    timeline = new Timeline();
                    timeline.add(0f, imgPoint);
                    timeline.add(0.2f, new Point(0, 0));
                    timeline.add(0.4f, new Point(200 - img.getWidth(), 0));
                    timeline.add(0.6f, new Point(200 - img.getWidth(), 200 - img.getHeight()));
                    timeline.add(0.8f, new Point(100 - (img.getWidth() / 2), 200 - img.getHeight()));
                    timeline.add(1f, new Point(100 - (img.getWidth() / 2), 100 - (img.getHeight() / 2)));
    
                    Timer timer = new Timer(40, new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            long duration = System.currentTimeMillis() - startTime;
                            float progress = (float) duration / (float) PLAY_TIME;
                            if (progress > 1f) {
                                startTime = System.currentTimeMillis();
                                progress = 0;
                                ((Timer) (e.getSource())).stop();
                            }
    
                            System.out.println(progress);
                            imgPoint = timeline.getPointAt(progress);
                            repaint();
    
                        }
                    });
                    startTime = System.currentTimeMillis();
                    timer.start();
                } catch (IOException exp) {
                    exp.printStackTrace();
                }
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (img != null && imgPoint != null) {
                    Graphics2D g2d = (Graphics2D) g.create();
                    g2d.drawImage(img, imgPoint.x, imgPoint.y, this);
                    g2d.dispose();
                }
            }
    
        }
    
        public static class Timeline {
    
            private Map<Float, KeyFrame> mapEvents;
    
            public Timeline() {
                mapEvents = new TreeMap<>();
            }
    
            public void add(float progress, Point p) {
                mapEvents.put(progress, new KeyFrame(progress, p));
            }
    
            public Point getPointAt(float progress) {
    
                if (progress < 0) {
                    progress = 0;
                } else if (progress > 1) {
                    progress = 1;
                }
    
                KeyFrame[] keyFrames = getKeyFramesBetween(progress);
    
                float max = keyFrames[1].progress - keyFrames[0].progress;
                float value = progress - keyFrames[0].progress;
                float weight = value / max;
    
                return blend(keyFrames[0].getPoint(), keyFrames[1].getPoint(), 1f - weight);
    
            }
    
            public KeyFrame[] getKeyFramesBetween(float progress) {
    
                KeyFrame[] frames = new KeyFrame[2];
                int startAt = 0;
                Float[] keyFrames = mapEvents.keySet().toArray(new Float[mapEvents.size()]);
                while (startAt < keyFrames.length && keyFrames[startAt] <= progress) {
                    startAt++;
                }
    
                if (startAt >= keyFrames.length) {
                    startAt = keyFrames.length - 1;
                }
    
                frames[0] = mapEvents.get(keyFrames[startAt - 1]);
                frames[1] = mapEvents.get(keyFrames[startAt]);
    
                return frames;
    
            }
    
            protected Point blend(Point start, Point end, float ratio) {
                Point blend = new Point();
    
                float ir = (float) 1.0 - ratio;
    
                blend.x = (int) (start.x * ratio + end.x * ir);
                blend.y = (int) (start.y * ratio + end.y * ir);
    
                return blend;
            }
    
            public class KeyFrame {
    
                private float progress;
                private Point point;
    
                public KeyFrame(float progress, Point point) {
                    this.progress = progress;
                    this.point = point;
                }
    
                public float getProgress() {
                    return progress;
                }
    
                public Point getPoint() {
                    return point;
                }
    
            }
    
        }
    }
    
    0 讨论(0)
提交回复
热议问题