如何从一个 x,y 坐标动画到另一个?(Java/处理) [英] How to animate from one x,y coordinate to another? (Java/Processing)

查看:25
本文介绍了如何从一个 x,y 坐标动画到另一个?(Java/处理)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理中制作一个简单的动画.我想将图像从其起点动画化到屏幕上定义的 x,y 值.

I am making a simple animation in Processing. I want to animate an image from its starting point to a defined x,y value on the screen.

我有 2 个方法,update()draw(),它们在每个刻度上运行.update() 是代码将去处理 x/y 坐标以在下一个刻度上提供给 draw() 方法的地方.

I have 2 methods, update() and draw(), which are run on every tick. update() is where the code will go to process the x/y coordinates to provide to the draw() method on the next tick.

draw() 方法然后绘制图像,传入更新的 x 和 y 值.

The draw() method then draws the image, passing in the updated x and y values.

最小示例:

class ScrollingNote {
  float x;
  float y;
  float destX;
  float destY;
  PImage noteImg;

  ScrollingNote(){
    noteImg = loadImage("image-name.png");
    this.x = width/2;
    this.y = 100;
    this.destX = 100;
    this.destY = height;
  }

  void update(){
    // TODO: adjust this.x and this.y 
    // to draw the image slightly closer to
    // this.destX and this.destY on the redraw
    // ie in this example we are animating from x,y to destX, destY
  }

  void draw(){
    image( noteImg, this.x, this.y );
  }
}

我需要进行什么样的计算来调整 x/y 坐标以使图像稍微靠近目的地?

What sort of calculation do I need to make to adjust the x/y coordinates to make the image draw slightly closer to the destination?

推荐答案

这是一个基于时间段的动画的非常基本的例子

This is a very basic example of time period based animation

它将在 5 秒内为 Animatable 对象设置动画.如果您想变得有趣,您可以简单地使用 List 并同时更新/绘制多个对象.

It will animate a Animatable object over a 5 second period. You could simply use a List and update/paint multiple objects simultaneously if you wanted to get fancy.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class AnimationTest {

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

    public AnimationTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Animatable {

        public void update(double progress);
        public void draw(Graphics2D g2d);

    }

    public static class FlyingSquiral implements Animatable {

        private final Point startPoint;
        private final Point targetPoint;
        private final double startAngel;
        private final double targetAngel;

        private Point location;
        private double angle;

        public FlyingSquiral(Point startPoint, Point targetPoint, double startAngel, double targetAngel) {
            this.startPoint = startPoint;
            this.targetPoint = targetPoint;
            this.startAngel = startAngel;
            this.targetAngel = targetAngel;

            location = new Point(startPoint);
            angle = startAngel;
        }

        @Override
        public void update(double progress) {

            location.x = (int)Math.round(startPoint.x + ((targetPoint.x - startPoint.x) * progress));
            location.y = (int)Math.round(startPoint.y + ((targetPoint.y - startPoint.y) * progress));
            angle = startAngel + ((targetAngel - startAngel) * progress);

        }

        @Override
        public void draw(Graphics2D g2d) {

            Graphics2D clone = (Graphics2D) g2d.create();

            clone.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            clone.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            clone.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            clone.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            clone.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            clone.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            clone.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            clone.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
            AffineTransform at = new AffineTransform();
            at.translate(location.x, location.y);
            at.rotate(Math.toRadians(angle), 25, 25);
            clone.setTransform(at);
            clone.draw(new Rectangle(0, 0, 50, 50));
            clone.dispose();

        }

    }

    public static class TestPane extends JPanel {

        public static final long DURATION = 5000;
        private long startTime;
        private boolean started = false;

        private FlyingSquiral squiral;

        public TestPane() {
            squiral = new FlyingSquiral(
                    new Point(0, 0), 
                    new Point(150, 150), 
                    0d, 360d);
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!started) {
                        startTime = System.currentTimeMillis();
                        started = true;
                    }
                    long time = System.currentTimeMillis();
                    long duration = time - startTime;
                    if (duration > DURATION) {
                        duration = DURATION;
                        ((Timer)e.getSource()).stop();
                    }
                    double progress = (double)duration / (double)DURATION;
                    squiral.update(progress);
                    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();
            squiral.draw(g2d);
            g2d.dispose();
        }
    }

}

同样,您可以使用基于约束的动画,其中对象不断移动,直到满足所需的约束(角度/位置).各有利弊.

Equally, you could use a constraint based animation, where by the object keeps moving until it meets it's required constraints (angel/position). Each has pros and cons.

我更喜欢基于时间段的方法,因为它允许我应用不同的转换而无需关心预先计算增量.试试这个,把目标angel从360改成720,再运行一次.

I prefer a time period based approach as it allows me to apply different transformations without needing to care about pre-calculating the delta. Try this, change the target angel from 360 to 720 and run it again.

我也更喜欢使用动画库,因为它们添加了额外的功能,比如插值,允许在某些时间点改变动画的速度而不改变持续时间,这将允许你做一些事情,比如慢进,减速(加速/减速)效果,使动画更具吸引力.

I also prefer to use an animation library, as they add additional features, like interpolation, allowing to change the speed of the animation at certain points in time without changing the duration, this would allow you to do things like slow in, slow out (ramp up/out) effects, making the animation more appealing.

看看...

这篇关于如何从一个 x,y 坐标动画到另一个?(Java/处理)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆