如果您在 2D 多边形内有一个“球”,由 4 个充当边界墙的线段组成,您如何计算球与不规则倾斜的墙碰撞后的角度?
如果墙壁是水平的、垂直的或呈 45 度角,我知道如何让球反弹。我还设置了代码来检测与墙壁的碰撞。
我读过点积和法线,但我不知道如何在 Java / Android 中实现这些。我完全被难住了,感觉我现在已经在 Google 中查找了 10 页深度的所有内容 10 次。我已经筋疲力尽地试图弄清楚这一点,我希望有人能提供帮助。
如果您在 2D 多边形内有一个“球”,由 4 个充当边界墙的线段组成,您如何计算球与不规则倾斜的墙碰撞后的角度?
如果墙壁是水平的、垂直的或呈 45 度角,我知道如何让球反弹。我还设置了代码来检测与墙壁的碰撞。
我读过点积和法线,但我不知道如何在 Java / Android 中实现这些。我完全被难住了,感觉我现在已经在 Google 中查找了 10 页深度的所有内容 10 次。我已经筋疲力尽地试图弄清楚这一点,我希望有人能提供帮助。
提前道歉:我不知道正确的 Android 类型。我假设您有一个具有属性“x”和“y”的向量类型。
如果墙是水平的并且当前速度是“矢量”,那么它就像:
vector.y = -vector.y;
并且您将不理会 x 组件。所以你需要做一些类似的,但更普遍的事情。
为此,您可以用线法线(垂直于线的向量)的概念来代替 y 轴(垂直于水平线)的硬编码。
由于法线与直线正交,因此将直线旋转 90 度即可找到。在 2d 中,向量 (a, b) 可以通过将其转换为 (-b, a) 来旋转 90 度。因此,如果您有一条从 (x1, y1) 到 (x2, y2) 的线,那么您可以通过以下方式获得法线:
vectorAlongLine.x = x2 - x1;
vectorAlongLine.y = y2 - y1;
normal.x = -vectorAlongLine.y;
normal.y = vectorAlongLine.x;
您实际上并不关心原始行有多长(当您不想要它时它会影响以后的计算),因此您希望使法线的长度为 1 而不管其当前长度如何。您可以通过将其除以当前长度来做到这一点。所以,例如
lengthOfNormal = Math.sqrt(normal.x*normal.x + normal.y*normal.y);
normal.x /= lengthOfNormal;
normal.y /= lengthOfNormal;
在那里使用勾股定理得到长度。
对于水平线,在 y 轴上翻转与(i)计算向量沿 y 轴延伸的范围相同;并且 (ii) 将该数量减去两次——一次使该方向上的速度为 0,再次使其成为原始的负数。也就是说,它与以下内容相同:
distanceAlongNormal = vector.y;
vector.y -= 2.0 * distanceAlongNormal;
在一般情况下使用点积来计算向量沿法线延伸的距离。因此,它与采用 vector.y 对水平线的作用相同。在这里,您可能需要采取一些信念的飞跃。这是点积的属性,您可以通过检查直角三角形来说服自己。但是现在,如果你有一条水平线,你最终会得到正常的 (0, 1)。由于点积将是:
vector.x * normal.x + vector.y * normal.y
你会计算:
distanceAlongNormal = vector.x * 0.0 + vector.y * 1.0;
这显然与仅采用 y 分量相同。
计算出沿法线的距离后,您实际上想要减去该量乘以法线乘以 2。这里唯一的附加步骤是乘以法线来获得要减去的 2d 量。那是因为您要按正常顺序进行减法。因此,基于之前计算的法线,完整的代码是:
distanceAlongNormal = vector.x * normal.x + vector.y * normal.y;
vector.x -= 2.0 * distanceAlongNormal * normal.x;
vector.y -= 2.0 * distanceAlongNormal * normal.y;
如果您没有将正常长度设为 1,那么您需要在此处除以长度,因为点积会将 distanceAlongNormal 值缩放该数量。