- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图让图像跟随路径。此路径的点存储在 ArrayList 中。现在图像每两秒跳到下一个点,所以我必须使用线性插值来使移动平滑。但是如何在 update() 方法中使用线性插值呢?我在网上搜索了这个问题,但找不到太多关于更新方法中的线性插值与带点的 ArrayList 相结合的信息。
更新方法
public void update(){
repaint();
if(counter < Lane.firstLane.size()){
startPoint = new Point(carPosition.x, carPosition.y);
endPoint = new Point(Lane.firstLane.get(counter).x, Lane.firstLane.get(counter).y);
pointOnTimeLine = new Point(startPoint);
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (startTime == null) {
startTime = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long diff = now - startTime;
if (diff >= playTime) {
diff = playTime;
((Timer) e.getSource()).stop();
}
double i = (double) diff / (double) playTime;
pointInTime = i;
//pointOnTimeLine.x = (int) (startPoint.x + ((endPoint.x - startPoint.x) * i));
//pointOnTimeLine.y = (int) (startPoint.y + ((endPoint.y - startPoint.y) * i));
//carPosition.setLocation(pointOnTimeLine);
carPosition.x=(int) lerp(startPoint.x,endPoint.x,i);
carPosition.y=(int)lerp(startPoint.y,endPoint.y,i);
System.out.println("Car position: x"+carPosition.x+": y"+carPosition.y );
//System.out.println("Point"+pointOnTimeLine);
repaint();
counter++;
}
});
timer.start();
}
else{
//System.out.println("Destination reached");
}
//carPosition.x+=1;
//repaint();
}
double lerp(double a, double b, double t) {
return a + (b - a) * t;
}
移动汽车的线程
public void moveCar() {
Runnable helloRunnable = new Runnable() {
public void run() {
car.update();
repaint();
}
};
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(helloRunnable, 0, 40, TimeUnit.MILLISECONDS);
}
车道.cs
public class Lane {
public static List<Point> firstLane = new ArrayList<>(Arrays.asList(new Point(10,135),new Point(124,190),new Point(363,190),new Point(469,210)));
}
编辑:我已根据 MadProgrammers 的建议更改了我的代码。动画作品现在是动画电影http://gyazo.com/e6a28b87cb905c0ff5eb023d68955321 .我的 OP 更新了我当前的代码。下一步是转向部分,但我认为有一种更优雅的方法可以调用 moveCar 中的汽车更新方法和 repaint()。我已将此线程中的时间指定为与计时器中的时间相同的长度 (40ms)。有没有更好的方法来调用 car.update() 并在 moveCar() 中重绘?
最佳答案
让我们分解一下...
基本上,您想在一段时间 (t
) 内从一点 (A
) 移动到另一点 (B
)。在给定时间点 A
和 B
之间的给定点是两者之间差异的百分比(其中 t
被归一化为0 和 1 之间的分数)
所以,如果 A
是 10
并且 B
是 20
并且 t
是 2 秒,在 1 秒 p
应该是 15
(((B - A) * i) + A
) 其中 i
是 0.5
的归一化时间差(2 秒的 50% = 1 秒)
因此,给定任意时间点,您可以计算出两点之间的差异,并计算出它应该在的位置。
如果你想知道为什么我将时间归一化,考虑一下,如果你将 t
改为 4 秒,计算不会改变,我们只需要计算归一化点时间 (1/4 = 0.25
) 并通过计算将其返回给我们想要的结果。
因此,您需要知道从点 A
到点 B
需要多长时间。然后你需要一些机制来定期检查已经过去的时间量并计算对象在两点之间的当前位置。为此,您可以使用 Swing Timer
定期计时(例如 40 毫秒),直到 2 秒过去。
import java.awt.Color;
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.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
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 {
private Long startTime;
private long playTime = 2000;
private Point startPoint, endPoint;
private Point pointOnTimeLine;
private double pointInTime; // For rendering...
public TestPane() {
startPoint = new Point(0, 95);
endPoint = new Point(190, 95);
pointOnTimeLine = new Point(startPoint);
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (startTime == null) {
startTime = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long diff = now - startTime;
if (diff >= playTime) {
diff = playTime;
((Timer) e.getSource()).stop();
}
double i = (double) diff / (double) playTime;
pointInTime = i;
pointOnTimeLine.x = (int) (startPoint.x + ((endPoint.x - startPoint.x) * i));
pointOnTimeLine.y = (int) (startPoint.y + ((endPoint.y - startPoint.y) * i));
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();
g2d.setColor(Color.RED);
g2d.fill(new Ellipse2D.Double(startPoint.x, startPoint.y, 10, 10));
g2d.fill(new Ellipse2D.Double(endPoint.x, endPoint.y, 10, 10));
g2d.setColor(Color.GREEN);
g2d.fill(new Ellipse2D.Double(pointOnTimeLine.x, pointOnTimeLine.y, 10, 10));
g2d.dispose();
}
}
}
好的,“但这对我有什么帮助?”我听到你在问。好吧,事实是,这是在多个点之间移动的基础。
在您的代码中,您有 4 个均匀分布的关键时间点,对象必须在这些时间点上移动,这意味着每个点沿时间线大约相隔 33%。
当你沿着时间线计算当前位置时,你需要找到它之间的两个点(0-33是第一点和第二点,34-66是第二点和第三点,67>是第三点等等),然后计算物体在这些点之间的位置。
有点复杂,因为您需要考虑两点之间的时间量占总时间的一小部分,但由于两点之间的时间距离大部分是偶数,所以它不应该发挥重要作用。
这是演示here和 here所以您将不得不原谅我没有再次重新发布代码。
现在,为了我的钱,我还会花一些时间来了解像 Timing Framework 这样的动画库。和/或 Trident和/或 Universal Tween Engine
关于Java图像沿列表中的点移动并使用线性插值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28961352/
我是一名优秀的程序员,十分优秀!