如何从一个x,y坐标动画到另一个? (爪哇/处理)

我在Processing中制作一个简单的动画。 我想将图像从其起点设置为屏幕上定义的x,y值。

我有两个方法, update()draw() ,它们在每个tick上运行。 update()是代码将处理x / y坐标以在下一个tick上提供draw()方法的地方。

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

最小的例子:

 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坐标以使图像稍微靠近目的地?

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

它将在5秒的时间内为Animatable对象制作Animatable 。 您可以简单地使用List并同时更新/绘制多个对象,如果您想要获得幻想。

在此处输入图像描述

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

同样,您可以使用基于约束的动画,其中对象保持移动,直到满足其所需的约束(天使/位置)。 每个人都有利有弊。

我更喜欢基于时间段的方法,因为它允许我应用不同的转换而无需关心预先计算delta。 试试这个,将目标天使从360改为720并再次运行。

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

看一眼…

  • 时间框架
  • 三叉戟
  • Unviersal Tween引擎

如果您使用的是Processing 2.0,可以通过Ani库完成。 要获得与@MadProgrammer相同的输出,您只需使用Ani.init(this)设置基本草图,然后在draw()函数中通过translate()移动框并通过rotate()函数旋转它。 第一次鼠标点击后,整个动画开始。

 import de.looksgood.ani.*; import de.looksgood.ani.easing.*; float posX = 25, posY = 25; float angleRotation = 0; void setup () { size (200, 200); background (99); noFill (); stroke (0); Ani.init(this); frameRate (30); rectMode(CENTER); } void draw () { background (225); translate(posX, posY); rotate(radians(angleRotation)); rect(0, 0, 50, 50); } void mousePressed() { Ani.to(this, 5, "posX", 175, Ani.LINEAR); Ani.to(this, 5, "posY", 175, Ani.LINEAR); Ani.to(this, 5, "angleRotation", 360, Ani.LINEAR); } 

手动,你可以通过增加绘制循环中的posXposYangleRotation来获得类似的结果。