簡體   English   中英

如何從一個x,y坐標向另一個動畫? (爪哇/處理)

[英]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);
}

手動增加繪制循環中的posXposYangleRotation即可獲得相似的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM