【问题标题】:Wanted to make an object bounce inside a circle, ended up making the object move along the rim of the circle想让一个物体在一个圆圈内反弹,最终让物体沿着圆圈的边缘移动
【发布时间】:2012-08-20 15:26:22
【问题描述】:

这是有问题的代码:

public void calculate() {
        // Center of circle is at (250, 250).
        //THIS ALGORITHM IS NOW PROVEN TO BE WORSE THAN I FEARED...

        /*      What it does:
         *          Moves object around in a circle.
         *          Does not move the object towards the center.
         *          Object always stays on the rim of the circle.
         * 
         *      Algorithm I used. (DOES NOT WORK):
         *          N is normalized vector. 
         *          R = -2*(V dot N)*N + V
         */

        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
        double nx = x - 250;
        double ny = y - 250;
        double nd = Math.hypot(nx, ny);
        if (nd == 0)
            nd = 1;
        nx /= nd;
        ny /= nd;
        double dotProduct = vx * nx + vy * ny;
        vx += (float) (-2 * dotProduct * nx);
        vy += (float) (-2 * dotProduct * ny);
        x -= vx * 2;
        y -= vy * 2;
        vx *= 0.99;
        vy *= 0.99;
    }

这就是发生的事情。

您看到的黑线是紫色对象(框)移动的位置。它恰好在我用Canvas.drawCircle() 画的圆线上。

我不明白为什么反射不起作用。如果一个物体要撞到圆形墙,它不应该反映物体的速度方向,这就是算法的本意吗?还是我使用了错误的算法?

感谢任何帮助。提前致谢。

【问题讨论】:

  • 你的初始条件是什么?轨迹究竟是如何从它们演变而来的?如果您从篮筐开始,那将是圆点所在的位置,但如果您从中心开始,那么在接触篮筐时必定会发生某事。会发生什么?
  • 你在公式中丢失了一个减号。
  • @MarkoTopolnik 如果我从圆圈内开始,物体将越来越靠近中心,然后快速旋转。它一直在旋转,直到我给出的摩擦力停止了物体的速度。如果我让物体朝着给定方向加速,物体最终会到达一个点,它的加速度和速度使物体圆形边缘,无论物体是否在圆圈之外.我会告诉你更多,但它会变得越来越奇怪。
  • @n.m.真的???我没看到。我遵循了代码注释部分中给出的算法,并且在代码中没有看到与算法不匹配的任何内容。如果您的意思是速度减去位置,那部分是正确的。有一些 API 使用反向轴,我正在使用其中一个 API。
  • WTF?!?!今天,我只是 $%#% 意识到我是多么愚蠢。此算法适用于圆到对象、在圆外并从外部撞击圆、碰撞响应。更糟糕的是,这个算法比 PDF 版本要好,这在我比较两者时是出乎意料的。伙计,我很生气,并意识到我在这一切之前浪费了几个月的工作,现在我痛苦地哭了。

标签: java collision-detection game-physics


【解决方案1】:

你能从任意角度的直墙上反弹吗?这应该是第一步。 (您可能会发现速度矢量的极坐标表示更易于使用。)

一旦你完成了这项工作,它应该是相当简单的:从一个圆反弹就像从一个在接触点接触它的圆的切线反弹。

您可以通过观察它垂直于接触点的半径矢量(即从物体所在位置到圆心的矢量)来计算此切线

【讨论】:

  • 请问,出于好奇,是否有基于矢量的实现,而不依赖于角度?
  • 作为一个不喜欢使用角度的开发者,我可以确认。
【解决方案2】:

是否有基于矢量的实现,而不依赖于角度?

是的,请参阅2-Dimensional Elastic Collisions without Trigonometry,在此KineticModel 中说明。您的实现似乎缺少切线组件。详情请见Ensemble#collideAtoms()

【讨论】:

  • 我刚刚检查了切向分量。不幸的是,我不知道发生了什么。如果物体在圆圈内高速旋转,则会出现一种奇怪的效果,它会导致物体向外移动,然后它就会离开屏幕。我仔细检查了 PDF,按照 PDF 说明进行了一些计算,但我就是找不到问题所在。我感谢你给了我一本额外的午夜故事书来阅读。 :D
【解决方案3】:

这就是我所拥有的,我将与大家分享我的发现。

public void calculate() {
    // Center of circle is at (250, 250). Radius is 40.
    //THIS ALGORITHM IS PROVEN TO BE BETTER THAN I FEARED...

    /*      What it does:
     *          Moves object around in a circle, if object is 
     *              inside of circle.
     *          Does not move the object towards the center, 
     *              nor outwards. This is crucial.
     *          Object always stays on the rim of the circle, 
     *              if the collision detection allows it to.
     * 
     *      Algorithm I used. (DOES WORK, NOT EXPECTING THIS THOUGH.):
     *          N is normalized vector. 
     *          R = -2*(V dot N)*N + V
     */



    double nx = x - 250;
    double ny = y - 250;
    double nd = Math.hypot(nx, ny);
    if (nd < 40){
        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
        x -= vx;
        y -= vy;
        vx *= 0.9;
        vy *= 0.9;
        return;
    }

    vx += Accelero.X * 0.1;
    vy += Accelero.Y * 0.1;


    if (nd == 0)
        nd = 1;
    nx /= nd;
    ny /= nd;
    double dotProduct = vx * nx + vy * ny;
    vx += (float) (-2 * dotProduct * nx);
    vy += (float) (-2 * dotProduct * ny);
    x -= vx * 2;
    y -= vy * 2;
    vx *= 0.99;
    vy *= 0.99;
}

我在我的函数中嵌入了一个碰撞检测,基本上使这个函数尽可能地不高效。忽略它,因为它不是主要焦点。

圆的半径是40,(x,y)位置是(250,250)。

只有当物体在圆上,或者离圆心更远时,我们才应该计算碰撞响应,由算法R = -2*(V dot N)*N + V给出,其中法线向量 N 已经归一化。

算法确实是正确的,我的碰撞检测的布尔条件是导致对象停留在圆的边缘并在圆上绕圈的原因。

我没有说@trashgod 提供的其他算法是错误的。这是因为一些奇怪的问题导致对象异常移动。我猜这是我使用的 API 的错,它不允许双打,但我可能不正确。我只是找不到问题的根源。我也很高兴不再进一步研究它。

碰撞检测布尔条件本身可以改变一切,只要稍微改变一下。如果不是因为@n.m。指出我似乎忘记了一个减号(在这种情况下,一个非符号),我可能永远不会意识到它是多么微不足道。

【讨论】:

  • 是的,过冲是个问题。 Boucescope 示例也解决了这个问题。
猜你喜欢
  • 2022-06-29
  • 2023-03-29
  • 1970-01-01
  • 2011-03-10
  • 1970-01-01
  • 2014-10-15
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多