2D球体没有正确碰撞

7

我只是尝试编写一个外观漂亮的物理游戏。

球的碰撞看起来很好,但如果球的碰撞速度太慢,它们就会“粘”在一起。我不知道它们为什么这样做。

这是我的碰撞函数:

private void checkForCollision(ArrayList<Ball> balls) {
    for (int i = 0; i < balls.size(); i++) {
        Ball ball = balls.get(i);
        if (ball != this && ball.intersects(this)) {
            this.collide(ball, false);
        }
    }
}

public boolean intersects(Ball b) {
    double dx = Math.abs(b.posX - posX);
    double dy = Math.abs(b.posY - posY);
    double d = Math.sqrt(dx * dx + dy * dy);
    return d <= (radius + b.radius);
}

private void collide(Ball ball, boolean b) {
    double m1 = this.radius;
    double m2 = ball.radius;
    double v1 = this.motionX;
    double v2 = ball.motionX;

    double vx = (m1 - m2) * v1 / (m1 + m2) + 2 * m2 * v2 / (m1 + m2);

    v1 = this.motionY;
    v2 = ball.motionY;
    double vy = (m1 - m2) * v1 / (m1 + m2) + 2 * m2 * v2 / (m1 + m2);

    if (!b)
        ball.collide(this, true);
    System.out.println(vx + " " + vy);
    motionX = vx * BOUNCEOBJECT;
    motionY = vy * BOUNCEOBJECT;
}

但是当它们与低速碰撞时会发生什么:

此处输入图片描述

那么,你有什么想法吗?

编辑:

Alnitak 的更新效果非常好......但仍然存在一个问题......如果我像这样添加重力:

public void physic() {
    motionY += GRAVITY;                  // <= this part (GRAVITY is set to 0.3D)
    checkForCollision(screen.balls);
    keyMove();
    bounceWalls();

    posX += motionX;
    posY += motionY;
}

他们仍然相互移动。我认为这是错误的添加重力的方式,不是吗?
而且,我认为我在碰撞公式方面做错了什么,因为它们没有正确地下落:
![落球](https://istack.dev59.com/dk9hQ.webp)
然后它们慢慢地沉入地面。
编辑:找到了一个惊人的教程:http://www.ntu.edu.sg/home/ehchua/programming/java/J8a_GameIntro-BouncingBalls.html
3个回答

9
这是一个常见的问题,因为有时弹球的增量速度不足以将其带出碰撞区域。
因此,碰撞例程会再次反转方向,将其带回另一个球内,如此循环往复。
您应该在球的位置上添加足够的偏移量(沿着碰撞力的方向),以确保新计算出的位置不再发生碰撞。
或者,检查当您添加新的运动值时,球是否会发生碰撞:
public boolean intersects(Ball b) {
    double dx = b.posX - (posX + motionX);  // no need for Math.abs()
    double dy = b.posY - (posY - motionY);
    double d = dx * dx + dy * dy;           // no need for Math.sqrt()
    return d < (radius + b.radius) * (radius + b.radius);
}

但你还应该将ball.intersects(this)更改为intersects(ball)

它们可能看起来会稍早地发生碰撞,但在快速移动的球上,这可能不会被注意到。


是的,我遇到了几乎完全相同的问题,只不过是方块,这就是我解决它的方法。 - Shivan Dragon
他应该给予排斥力一个方向 :) 我是这样解决的 ^^ - huseyin tugrul buyukisik
哪种方法是最好的呢? 我理解我的问题...但我不知道如何解决。 在调用collide()方法之前将球彼此分开移动? - TeNNoX
编辑:将其添加到主题中 - TeNNoX
@TeNNoX,这是同样的问题 - 你检查与墙壁的碰撞时没有让它在碰撞为“true”的区域外弹回。 - Alnitak

2
(m1 - m2) * v1 / (m1 + m2) + 2 * m2 * v2 / (m1 + m2);

这个值是整数2。请将其改为2.0f或2.0d,然后检查一下。这可能是小速度的问题,因为整数常量会自动转换为乘以双精度浮点数。
如果这样还不行,那么Alnitak的回答可能会有所帮助。
如果您需要真正好的物理效果,您应该使用力量,然后将其转换为速度,再将其转换为位移。查看积分技术,如Runge Kutta和Euler Integration。
Force-->acceleration-->velocity-->displacement

如果发生碰撞,只需更新力,剩下的就会自然发生。
----> http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/ <-----

http://www.forums.evilmana.com/game-programming-theory/euler-vs-verlet-vs-rk4-physics/

http://www.newagepublishers.com/samplechapter/001579.pdf

http://cwx.prenhall.com/bookbind/pubbooks/walker2/

Verlet积分法是介于Runge-Kutta-4和Euler积分之间的一种方法,通常用于分子动力学(如果忽略电场和键的影响,则可作为弹跳球的良好示例)。

3
在这个表达式中,2会自动晋升为一个双精度数。 - Alnitak
好的,那我会阅读一些关于龙格-库塔或者你们怎么称呼它的文章……因为我读到欧拉方法不是很好。你能推荐一些教程给我吗?因为维基百科的文章对我帮助不大 :P - TeNNoX
即便你使用了这样的技术,你仍然需要考虑到计算机模拟会导致离散的位置变化,这可能会“错过”真正的碰撞点,从而导致OP试图解决的问题。当虚拟球从A移动到B时,并不会经过A和B之间的每个点。 - Alnitak
@TeNNoX:Verlet算法不像Runge Kutta那么难,也不像Euler Integration那样容易出错。我在分子动力学中使用它,因为它直接忽略速度(从力到位移直接计算,但需要2次迭代的位移历史记录)。 - huseyin tugrul buyukisik
以下是不错的例子:http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/ http://www.forums.evilmana.com/game-programming-theory/euler-vs-verlet-vs-rk4-physics/ - huseyin tugrul buyukisik


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接