java - 圆与圆的碰撞

标签 java graphics collision-detection

我正在尝试编写一个Java程序来支持离格扩散有限聚合模拟。模拟移动粒子的基本代码已就位,直到所述粒子撞击静态中心粒子。此时,我尝试确保移动粒子恰好接触(相切)静态粒子。然而,由于未知的原因,它有时会失败(8 个粒子中的前 2 个相交,其他 6 个都很好)。

这是代码:

    boolean killed, collide;
    double xp, yp, dx, dy, theta, xpp, ypp, length;

    int xc = 200;
    int yc = 200;
    int killRadius = 200;
    int releaseRadius = 150;
    int partRadius = 14;
    int partDiam = 2 * partRadius;

    drawCircle(xc, yc, killRadius); // kill
    drawCircle(xc, yc, releaseRadius); // release
    drawCircle(xc, yc, partRadius); // center particle

    //while (true) {
        killed = false;
        collide = false;

        theta = Math.random() * Math.PI * 2;
        xp = xc + releaseRadius * Math.cos(theta);
        yp = yc + releaseRadius * Math.sin(theta);

        while (true) {

            theta = Math.random() * Math.PI * 2;
            length = partDiam;

            xpp = xp;
            ypp = yp;

            xp = xp + length * Math.cos(theta);
            yp = yp + length * Math.sin(theta);

            //drawCircle((int) xp, (int) yp, partRadius);

            // Should it be killed ? (maybe could use a box to fasten
            // computations...
            // Would switching the test for kill w test for collision
            // improve perf ?
            dx = xp - xc;
            dy = yp - yc;
            if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
                killed = true;
                break;
            }

            // Does it collide with center? replace by any particle...
            dx = xp - xc;
            dy = yp - yc;
            if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
                collide = true;
                break;
            }
        }
// Probably something is wrong here...
        if (collide) {
            // no absolute value because particles move at most by diameter
            double depthPenetration = partDiam
                    - Math.sqrt((dx * dx) + (dy * dy));
            dx = xpp - xp;
            dy = ypp - yp;
            // shorten distance travelled by penetration length to ensure
            // that
            // particle is tangeant
            length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration;
            xp = xpp + length * Math.cos(theta);
            yp = ypp + length * Math.sin(theta);
            drawCircle((int) xp, (int) yp, partRadius);
        }
    //}

当然,在询问之前我检查了很多引用资料,但找不到代码有任何问题...我们将不胜感激。

最佳答案

我对你的代码进行了一些简单的重构,只是为了了解它的作用,发生了什么。

首先让我提一件事:这是意大利面条怪物的复兴,不是吗?你喜欢全局变量吗?长而强大的让我们现在就在这里做这件事?

如果你尽可能晚地引入变量,代码的读者就不需要向上搜索这个变量之前是什么——如果某些东西被覆盖,例如,如果有一个不好的重用。

如果你的变量没有改变:将它们定为最终的。这简化了对它们的推理。 final int KillRadius = 200; 表示获取类型信息以及值,希望在第一次使用之前不久,并且它永远不会改变。仅在源代码中进行配置。可能不是一个太复杂的候选人。与 double dx 相比 - 未初始化,因为它是在循环内初始化的,

static void foo () {

    final int xc = 200;
    final int yc = 200;
    final int killRadius = 200;
    final int releaseRadius = 150;
    final int partRadius = 14;

    drawCircle (xc, yc, killRadius); // kill
    drawCircle (xc, yc, releaseRadius); // release
    drawCircle (xc, yc, partRadius); // center particle

    //while (true) {
    boolean killed = false;
    boolean collide = false;

    double theta = Math.random() * Math.PI * 2;     
    double xp = xc + releaseRadius * Math.cos (theta);
    double yp = yc + releaseRadius * Math.sin (theta);
    double dx, dy, xpp, ypp;

    while (true) {

        theta = Math.random () * Math.PI * 2;
        final int partDiam = 2 * partRadius;
        final double length = partDiam;

        xpp = xp;
        ypp = yp;

        xp += length * Math.cos (theta);
        yp += length * Math.sin (theta);

        dx = xp - xc;
        dy = yp - yc;
        if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
            killed = true;
            break;
        }

        // Why again assign dx = xp -xc? Did any of these values change meanwhile? 
        // I don't think so.
        // dx = xp - xc;
        // dy = yp - yc;
        if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
            collide = true;
            break;
        }
    }
    if (collide) {
        // no absolute value because particles move at most by diameter
        double depthPenetration = partDiam - Math.sqrt((dx * dx) + (dy * dy));
        dx = xpp - xp;
        dy = ypp - yp;
        // shorten distance travelled by penetration length to ensure
        // that
        // particle is tangeant
        final double length = Math.sqrt((dx * dx) + (dy * dy)) - depthPenetration;
        xp = xpp + length * Math.cos (theta);
        yp = ypp + length * Math.sin (theta);
        drawCircle ((int) xp, (int) yp, partRadius);
    }

如果你这样构造你的代码,你不仅会看到像 xc 这样的某个值是 200 并且从未改变 - 在 while 循环的头部,你会看到 theta 没有在循环内声明,因此要么稍后在循环外使用它,要么在循环内按顺序修改它。执行 x += 4;你不能在循环传递中初始化 x 。

在最后,你有两个相似的 block :

    dx = xp - xc;
    dy = yp - yc;
    if ((dx * dx) + (dy * dy) (OP) a OP b) {
        c = true;
        break;
    }

但是 xp、xc 和 dx 同时不会改变 - y 等价物也不会改变。这是一个错误,还是为什么要再次分配它们?

然后,您可以通过这种方式摆脱无尽的 while:由于两个条件都会终止 while,因此将条件放入 while - 测试中,并且仅当第一个 block 未输入时才调用第二个 block (不重复赋值) - 这样做的关键字是 else:

    while (!killed && !collide) {

        // ...

        dx = xp - xc;
        dy = yp - yc;
        if ((dx * dx) + (dy * dy) > killRadius * killRadius) {
            killed = true;
        }
        else if ((dx * dx) + (dy * dy) < (partDiam) * (partDiam)) {
            collide = true;
        }
    }   

它对查找错误有什么帮助?没那么多。如果两个圆圈放错了,其余的都很好,那么截图就可以了,而值会导致坏圆圈,而值则可以。

关于java - 圆与圆的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11022156/

相关文章:

java - 我的碰撞检测在 Java 小程序中生成低帧率

unity-game-engine - 如何忽略背景图层或对象上的鼠标点击?

java - 如果源目标相同,Java 中的 fileoutputstream 生成零字节?

java - 在 java 中编写脚本化 BIRT 数据源时访问参数

java - 使用Java图形打印关于线的线标签

java - 如何修复碰撞响应中的圆圈重叠?

java - 具有自定义 ListView 的警报对话框

java - 访问数据库时分离关注点的最佳实践

java - 如何禁用布局对齐?

java - 为什么我的图标不会重新绘制?