代码之家  ›  专栏  ›  技术社区  ›  Ivo Wetzel

多边形交集失败,碰撞“大小”太大

  •  5
  • Ivo Wetzel  · 技术社区  · 15 年前

    好吧,所以我要做一个简单的小行星克隆。一切正常,除了碰撞检测。

    我有两个不同的版本,第一个使用java.awt.geom.面积:

    // polygon is a java.awt.Polygon and p is the other one
    final Area intersect = new Area();
    intersect.add(new Area(polygon));
    intersect.intersect(new Area(p.polygon));
    return !intersect.isEmpty();
    

    所以我在网上搜索了著名的分离轴定理,因为我不太擅长我的数学实现 here 并将其转换为适合我的Java需求:

    public double dotProduct(double x, double y, double dx, double dy) {
            return x * dx + y * dy;
        }
    
        public double IntervalDistance(double minA, double maxA, double minB,
                double maxB) {
            if (minA < minB) {
                return minB - maxA;
            } else {
                return minA - maxB;
            }
        }
    
        public double[] ProjectPolygon(double ax, double ay, int p, int[] x, int[] y) {
            double dotProduct = dotProduct(ax, ay, x[0], y[0]);
            double min = dotProduct;
            double max = dotProduct;
            for (int i = 0; i < p; i++) {
                dotProduct = dotProduct(x[i], y[i], ax, ay);
                if (dotProduct < min) {
                    min = dotProduct;
                } else if (dotProduct > max) {
                    max = dotProduct;
                }
            }
            return new double[] { min, max };
        }
    
        public boolean PolygonCollision(Asteroid ast) {
            int edgeCountA = points;
            int edgeCountB = ast.points;
            double edgeX;
            double edgeY;
    
            for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) {
                if (edgeIndex < edgeCountA) {
                    edgeX = xp[edgeIndex] * 0.9;
                    edgeY = yp[edgeIndex] * 0.9;
                } else {
                    edgeX = ast.xp[edgeIndex - edgeCountA] * 0.9;
                    edgeY = ast.yp[edgeIndex - edgeCountA] * 0.9;
                }
    
                final double x = -edgeY;
                final double y = edgeX;
                final double len = Math.sqrt(x * x + y * y);
                final double axisX = x / len;
                final double axisY = y / len;
    
                final double[] minMaxA = ProjectPolygon(axisX, axisY, points, xp,
                        yp);
                final double[] minMaxB = ProjectPolygon(axisX, axisY, ast.points,
                        ast.xp, ast.yp);
    
                if (IntervalDistance(minMaxA[0], minMaxA[1], minMaxB[0], minMaxB[1]) > 0) {
                    return false;
                }
            }
            return true;
        }
    

    以下是两张图片进行比较:
    http://www.spielecast.de/stuff/asteroids1.png
    http://www.spielecast.de/stuff/asteroids2.png

    正如你所希望看到的,图片一中的小行星比图片2中使用SAT代码的小行星密度要大得多。

    有什么想法吗?或者有人知道我可以使用的Java多边形实现吗?

    1 回复  |  直到 15 年前
        1
  •  4
  •   Jherico    15 年前

    看起来你的第二个结果是进行碰撞检测,就像多边形是一个圆,其半径设置为从中心到多边形的最远点。我见过的大多数碰撞检测工具都会创建一个简单的边界框(圆形或矩形),多边形可以放入其中。只有当两个边界框相交时(计算简单得多),才能继续进行更详细的检测。也许合适的算法只是一个边界框计算器?

    还有,来自维基百科

    如果其中一个物体不是凸的,这个定理就不适用了。

    许多小行星在你的图像中有凹面。