【问题标题】:Sprite Elliptical Movement精灵椭圆运动
【发布时间】:2011-06-16 07:26:43
【问题描述】:

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

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

【问题讨论】:

    标签: java math


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 将复杂的维基百科表达式翻译成可用代码并不是我的强项。该页面包含生成椭圆的 JavaScript,如果调整它就可以工作,但我不喜欢必须为每个精灵的每个运动矢量存储 36 个(或多或少)点的想法。我希望有一个解决方案可以让我计算椭圆中任何位置的 X 和 Y 坐标,我希望类似于我在另一个应用程序中使用的一些旧的贝塞尔代码。
    【解决方案2】:

    如果您希望它沿椭圆移动,我所知道的最简单的方法是将 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 坐标但没有椭圆的中心,那么我认为获得中心的最简单方法就是找出其余变量,然后将它们代入方程.那里的数学应该不会太难。

    【讨论】:

      【解决方案3】:

      我认为这个问题最好通过一系列坐标变换来解决。为了符号简单,我们假设你有两个点是 u 和 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 |
      

      翻译后u和v的位置由TuTv给出。我们将这些点称为 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)。您可以验证此向量是否垂直于 (x3, y3),因为它们的点积为零。

      给定这些向量,我们可以定义一个变换,将 (1, 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 的椭圆路径。但这很容易通过另一个坐标变换来纠正,这次将坐标系的高度缩放1 / h,这样我们要追踪的椭圆的高度为 1。这可以通过以下缩放矩阵来完成:

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

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

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

      那么,问题是 (SRT)-1 是什么。幸运的是,我们有 (SRT)-1 = T-1R-1S-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 / ||u|| = (x3, y3)。
      3. 在时间 t(对于 0 ≤ t ≤ 1),设 p = (cos(π t), sin(π t))
      4. 计算 p' = S-1p = (cos(π t), h sin(π t))
      5. 计算 p'' = R-1p' = (x3 cos(π t) - y3 sin(π t), y3 cos(π t) + x3 sin(π t))
      6. 计算 p''' = T-1p'' = (x3 cos(π t) - y3 sin(π t) + x2, y3 cos(π t) + x3 sin( π t) + y2)
      7. 输出 p''' 作为你的观点。

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

      【讨论】:

      • 它的描述性很好,虽然我看不出我会在哪里用我的任何半径值修改值以形成椭圆曲线而不是完美的球体。
      • @latreides- 请注意,S 变换按 h 缩放,我认为它是指椭圆的第二个轴的长度(第一个是两个原始点之间的距离)。这不是你的想法吗?
      【解决方案4】:

      我相信您正在寻找贝塞尔曲线,请查看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)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多