繁体   English   中英

精灵椭圆运动

[英]Sprite Elliptical Movement

我试图得到一个2d精灵以“弧”(半椭圆)而不是直线移动。 我有X和Y的起始位置和结束位置以及所需的半径。

实现这个的最佳方法是什么?

如果你想让它在椭圆中移动,我所知道的最简单的方法是将y值作为时间与sin的函数,并将x值作为时间与cos的函数。 假设您正在使用System.currentTimeMillis();,您将初始时间存储在变量中(例如,double startTime = System.currentTimeMillis()),然后在每个帧中,您将通过从中减去当前时间来获得经过时间开始时间。 (例如elapsedTme = System.currentTimeMillis() - startTime)。 那么y值将是(y方向上的半径)* sin(elapsedTime * speed)+椭圆中心的y值,x值将是(x方向上的半径)* cos(elapsedTime * speed)椭圆中心的+ x值。

编辑:如果您有起始X和Y坐标但不是椭圆的中心,那么我认为获得中心的最简单方法是找出其余的变量,然后将它们插入等式中。 那里的数学不应该太难。

您可能希望使用椭圆的参数形式,此处显示的公式

http://en.wikipedia.org/wiki/Ellipse#General_parametric_form

因为你有一个起始点,结束pt,你需要在两端解决t,

然后以相对较小的增量从t开始到结束。

我认为这个问题最好通过一系列坐标变换来解决。 对于符号简单性,让我们假设你有两点是你和v。

假设您在一个非常简单的情况下工作 - 点u和v分别位于(1,0)和(-1,0),并且椭圆上的长轴长度为1.然后你'只是描绘出一个半圆形。 假设您想以恒定速度在点之间进行插值,则可以使用以下公式:

x(t) = cos(pi * t)
y(t) = sin(pi * t)

当然,你不一定很幸运能够参与这个设置,所以我们可以进行一系列的坐标转换,让你进入这个配置。 首先,让我们将点w定义为u =(x0,y0)和v =(x1,y1)之间的中间点。 那是:

w = (x2, y2) = ((x0 + x1) / 2, (y0 + y1) / 2)

现在,假设您翻译u和v以使w位于原点。 这意味着u和v沿着相反的向量与原点等距。 如果我们使用矩阵和齐次坐标,那么你可以将其表示为

     | 1  0 -x2 |
 T = | 0  1 -y2 |
     | 0  0   1 |

然后, TuTv给出该翻译后u和v的位置。 我们将这些点称为u'和v'。 他们是由

u' = (x0 - x2, x1 - y2) = (x0 / 2 - x1 / 2, y0 / 2 - y1 / 2)
v' = (x1 - x2, y1 - y2) = (x1 / 2 - x0 / 2, y1 / 2 - y0 / 2)

我们现在更接近于解决原始问题,但是我们遇到的问题是u'和v'与x轴没有很好地对齐,因为它们在原始问题中。 为了解决这个问题,我们将应用一个旋转变换,使得u'最终为(1,0),v'最终为(0,1)。 为此,我们需要设置一个坐标系,其中一个基矢量位于u'方向,另一个位于垂直于它的方向。 为此,我们将选择我们的单位向量,如下所示:

e0 = u' / ||u||
e1 = perp(e0)

其中perp是一些垂直于e0单位向量。 得到这个的一种方法是,如果e0 = (x3, y3) ,那么e1 = perp(e0) = (-y3, x3) e0 = (x3, y3) e1 = perp(e0) = (-y3, x3) 您可以验证此向量是否垂直于(x3, y3)因为它们的点积为零。

给定这些向量,我们可以定义一个转换,将(0,0)映射到e0和(0,1)到e1

|x3 -y3  0|
|y3  x3  0|
| 0   0  1|

(最后一列是针对齐次坐标系)

当然,这与我们想要的相反 - 我们试图从e0映射到(1,0),从e1映射到(0,1)。 为了得到这个矩阵,我们只是反转上面的矩阵。 幸运的是,由于我们选择e0e1为正交,因此上面的矩阵是正交的,所以它的逆是它的转置:

    | x3 y3 0|
R = |-y3 x3 0|
    |  0  0 1|

现在,如果我们将R应用于u'v' ,我们最终会得到向量(1,0)和(-1,0),这就是我们想要它们的位置。 现在的问题是我们想要追踪的椭圆不一定具有单位高度。 例如,如果我们将其高度称为h ,那么我们将描绘出具有半长轴h和半轴1的椭圆路径。 但是这可以通过另一个坐标变换轻松校正,这次将corodinate系统的高度缩放1 / h以便我们想要跟踪的椭圆的高度为1.这可以通过以下缩放矩阵来完成:

    | 1  0  0 |
S = | 0 1/h 0 |
    | 0  0  1 |

这个设置有用的原因是我们知道如果我们在uv之间的所需椭圆上取任何点,然后将矩阵SRT应用于它,那么我们最终将它转换为使用单位圆上的相应点,这是从(1,0)到(-1,0)的路径。 但更重要的是,这种方式相反。 如果我们将SRT SRT应用于单位圆上的任何点,我们最终会回到uv之间的原始椭圆路径上的相应点! 为了达成协议,我们知道如何在(1,0)到(-1,0)的路径上找到点,因此我们有一个算法来解决这个问题:

  1. 对于给定的时间t ,如果您在时间t从(1,0)移动到(-1,0),则找到您在单位圆上的点。 叫它p
  2. 计算p'=(SRT) -1 p。
  3. p'是你要找的点。

那么,问题是(SRT) -1是什么。 幸运的是,我们有(SRT) -1 = T -1 R -1 S -1 ,所有这些矩阵都可以很容易地计算出来:

     | 1  0 -x2 |          | 1  0  x2 |
 T = | 0  1 -y2 |   T^-1 = | 0  1  y2 |
     | 0  0   1 |          | 0  0   1 |

     | x3  y3  0|          | x3 -y3 0 |
 R = |-y3  x3  0|   R^-1 = | y3  x3 0 |
     |  0   0  1|          |  0   0 1 |

     | 1  0   0 |          | 1  0   0 |
 S = | 0 1/h  0 |   S^-1 = | 0  h   0 |
     | 0  0   1 |          | 0  0   1 |

简而言之,最终的算法如下:

  1. 给定u =(x0,y0)和v =(x1,y1),令w =(x2,y2)=((x0 + x1)/ 2,(y0 + y1)/ 2)。
  2. 让你'= u / || u || =(x3,y3)。
  3. 在时间t(对于0≤t≤1),令p =(cos(πt),sin(πt))
  4. 计算p'= S -1 p =(cos(πt),h sin(πt))
  5. 计算p''= R -1 p'=(x3 cos(πt) - y3 sin(πt),y3 cos(πt)+ x3 sin(πt))
  6. 计算p''= T -1 p''=(x3 cos(πt) - y3 sin(πt)+ x2,y3 cos(πt)+ x3 sin(πt)+ y2)
  7. 输出p''作为您的观点。

对不起,如果这是很多数学,但你的答案应该(希望!)由上述程序给出。

我相信你正在寻找Bezier曲线,请查看http://www.math.ucla.edu/~baker/java/hoefer/Bezier.htm 源也可以在同一链接中获得。

如果您使用的是SWT,可以查看http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/GC.html#drawArc (int ,int,int,int,int,int)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM