JavaScript分离轴定理

时间:2012-05-01 06:25:06

标签: javascript collision-detection overlap

我正试图用JavaScript中的分离轴定理来检测两个正方形碰撞(一个旋转,一个不旋转)。尽管我努力尝试,但我无法弄清楚JavaScript中会出现什么样的情况,也无法找到任何JavaScript示例。请帮助,使用普通数字或JavaScript代码进行解释最有用。


更新:在研究了大量的几何和数学理论后,我决定在GitHub仓库中推出简化的SAT实现。您可以在此处找到JavaScript中SAT的工作副本:https://github.com/ashblue/canvas-sat

1 个答案:

答案 0 :(得分:4)

转换多边形

首先,你需要变换凸多边形的所有点(在这种情况下是正方形),因为它们都在同一个空间中,通过应用angle的旋转。

为了将来支持缩放,翻译等,我建议通过矩阵变换来实现。您必须编写自己的Matrix类代码或找到一些已经具有此功能的库(我确信有很多选项)。

然后你将徒劳地使用代码:

var transform = new Matrix();
transform.appendRotation(alpha);
points = transform.transformPoints(points);

其中pointsPoint个对象的数组。

碰撞算法概述

所以之前的所有都会遇到任何碰撞事件。关于碰撞算法,标准做法是尝试使用以下步骤分离2个凸多边形(在您的情况下为正方形):

  • 对于每个多边形边(多边形0和多边形1的边):
    • 将两个polgyons分类为“在前面”,“跨越”或“后面”边缘。
    • 如果两个多边形位于不同的边上(前面1英寸,后面1英寸),则没有碰撞,你可以停止算法(提前退出)。
  • 如果你到了这里,没有边缘可以分开polgyons:多边形相交/碰撞。

请注意,从概念上讲,“分离轴”是垂直于我们用多边形分类的边缘的轴。

根据边缘对多边形进行分类

为了做到这一点,我们将根据边缘对多边形的点/顶点进行分类。如果所有点都在一侧,那么多边形就在那一侧。否则,多边形跨越边缘(部分位于一侧,部分位于另一侧)。

要对点进行分类,我们首先需要获得边缘的正常值:

// this code assumes p0 and p1 are instances of some Vector3D class

var p0 = edge[0]; // first point of edge
var p1 = edge[1]; // second point of edge
var v = p1.subtract(p0);
var normal = new Vector3D(0, 0, 1).crossProduct(v);
normal.normalize();

上面的代码使用边缘方向和z向量的交叉积来得到法线。当然,你应该为每个边缘预先计算这个。

注意:法线表示与SAT分离的轴。

接下来,我们可以通过首先使它相对于边缘(减去边缘点),并使用带正常的点积来对任意点进行分类:

// point is the point to classify as "in front" or "behind" the edge
var point = point.subtract(p0);
var distance = point.dotProduct(normal);
var inFront = distance >= 0;

现在,如果该点位于前方或边缘,则inFronttrue,否则为false

请注意,当您在多边形的点上循环以对多边形进行分类时,如果前面至少有1个点,后面有1个点,那么也可以提前退出,因为那时已确定多边形是跨越多边形的边缘(而不是在前面或后面)。

正如您所看到的,您仍然需要进行相当多的编码。找到一些包含MatrixVector3D类的js库,并使用它来实现上述内容。将碰撞形状(多边形)表示为PointEdge实例的序列。

希望这会让你开始。