[英]How to animate from one x,y coordinate to another? (Java/Processing)
我正在處理中制作一個簡單的動畫。 我想從圖像的起點到屏幕上定義的x,y值設置動畫。
我有2個方法, update()
和draw()
,它們在每個刻度上都運行。 update()
是代碼將在下一個刻度上處理x / y坐標以提供給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();
}
}
}
同樣,您可以使用基於約束的動畫,其中對象一直移動直到滿足其所需的約束(角度/位置)。 每個都有優點和缺點。
我更喜歡基於時間的方法,因為它允許我應用不同的變換而無需擔心預先計算增量。 嘗試此操作,將目標天使從360
更改為720
,然后再次運行。
我還更喜歡使用動畫庫,因為它們添加了諸如插值之類的附加功能,可以在不改變持續時間的情況下在某些時間點更改動畫的速度,這將使您能夠進行慢進,慢出(效果),使動畫更具吸引力。
看一眼...
如果您使用的是Processing 2.0,則可以通過Ani庫完成。 要獲得與@MadProgrammer相同的輸出,您只需使用Ani.init(this)
設置基本草圖,然后在draw()
函數中通過translate()
移動框並通過rotate()
函數對其進行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);
}
手動增加繪制循環中的posX
, posY
和angleRotation
即可獲得相似的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.