2016-02-27 74 views
5

在Java中,我正在为Android编写一个移动应用程序,用一些我自己编写的类与一些动态球进行交互。重力取决于手机的倾斜度。物理圈碰撞弹出并滑动边界

我注意到当我有一堆球团聚在一个角落里时,他们中的一些会开始抖动,或者有时会在与其他球碰撞时滑动。这可能是因为我在错误的顺序执行步骤?

现在我有一个循环遍历每个球会:

  • 辛迭代
  • 检查碰撞与其他球
  • 检查碰撞对现场界

我应该补充说我与边界发生摩擦,当发生球碰撞时,只是为了失去能量。

这里的碰撞是如何被处理的代码的一部分:

// Sim an iteration 
    for (Ball ball : balls) { 
     ball.gravity.set(gravity.x, gravity.y); 

     if (ball.active) { 
      ball.sim(); 

      // Collide against other balls 
      for (Ball otherBall : balls) { 
       if (ball != otherBall) { 
        double dist = ball.pos.distance(otherBall.pos); 
        boolean isColliding = dist < ball.radius + otherBall.radius; 
        if (isColliding) { 
         // Offset so they aren't touching anymore 
         MVector dif = otherBall.pos.copy(); 
         dif.sub(ball.pos); 
         dif.normalize(); 
         double difValue = dist - (ball.radius + otherBall.radius); 
         dif.mult(difValue); 
         ball.pos.add(dif); 

        // Change this velocity 
        double mag = ball.vel.mag(); 
        MVector newVel = ball.pos.copy(); 
        newVel.sub(otherBall.pos); 
        newVel.normalize(); 
        newVel.mult(mag * 0.9); 
        ball.vel = newVel; 

        // Change other velocity 
        double otherMag = otherBall.vel.mag(); 
        MVector newOtherVel = otherBall.pos.copy(); 
        newOtherVel.sub(ball.pos); 
        newOtherVel.normalize(); 
        newOtherVel.mult(otherMag * 0.9); 
        otherBall.vel = newOtherVel; 
        } 
       } 
      } 
     } 
    } 
+0

我们可以看到你迄今为止做了什么吗? – Dan

+0

你在碰撞测试中测试两个物体是否相互靠近?你计算确切的碰撞时间还是允许物体相互移动? – LutzL

+0

更新了一些代码。我不测试两个物体是否正朝着彼此移动。现在我允许球进入对方,然后处理碰撞。 –

回答

2

如果这是检查球之间的相互作用的唯一代码,那么这个问题似乎很清楚。在平衡状态下,球没有办法在另一个球上休息。

比方说,你有一个球直接在另一个之上。当你计算由于重力引起的顶部球的加速度时,你还应该进行碰撞检查,就像你发布的一样,除了这次检查dist <= ball.radius + otherBall.radius。如果是这种情况,那么你应该假设球与球之间的法向力等于重力的大小,并且使连接两个球的中心的矢量与重力分量相抵消。如果你没有做到这一点,那么顶级球将加速到最低点,触发你发布的碰撞代码,你会得到抖动。

当球与场景边界接触时,必须使用类似的逻辑。

+0

我想我明白你在做什么,但我无法计算出碰撞响应。假设我在'ball2'上面有'ball1'。在模拟'ball1'之前,我测试了一下'ball2',看它们是否已经触摸。如果是,我需要调整'ball1'的位置并调整重力的方向,使它不会穿过它? –

+0

你的位置调整很好,这是你需要调整的重力,因为它会被两个球之间的法向力所抵消。因此,如果ball1与ball2接触,并且ball1的引力(g)与从ball1指向ball2的矢量(v)的矢量点积是正的,那么您想要从ball1的重力矢量中减去v次(g dot v)/ v^2)。这是重力矢量的方向上的组成部分。 –

1

因为我一直在试用我自己的Phys2D引擎(只是为了好玩),我知道你在谈论。 (以防万一 - 您可以在这里查看我的演示:http://gwt-dynamic-host.appspot.com/ - 选择“圆形碰撞演示”,并在此处输入相应的代码:https://github.com/domax/gwt-dynamic-plugins/tree/master/gwt-dynamic-main/gwt-dynamic-module-bar)。

问题是在迭代和无限循环的碰撞后果的性质。当例如球到达场景的角落时,它会经历至少3个力的向量:从墙上弹起的冲动,从地面反弹的冲动和重力冲动 - 在总结所有3个冲动后,根据松弛能量算法减少它,在你的球应该在哪里有新的矢量。但是,例如这个冲动将它引导到墙上 - 那么你必须根据所有的东西重新计算矢量集:反弹的能量,冲动,引力等等。即使在所有这些冲动都很小的情况下,你也永远不会得到它们全部0 ,因为双精度和容差比较常数 - 因为你有“抖动”和“滑动”效果。实际上,大多数现有的2D引擎都有这样或那样的效果:你可能会在这里看到它们:http://brm.io/matter-js/demo/#wreckingBall或这里:http://box2d-js.sourceforge.net/index2.html - 它们实际上只是让小的冲动更快被吸收,并在整个系统变得不再重复或多或少稳定,但并非总是可能。

无论如何,我只是建议不要重新发明自己的车轮,除非它只是为了你的乐趣 - 或者为了更好地理解这些东西。

对于最后一个(JFF) - 这里是很好的教程:http://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331

对于真正的东西,我建议你使用现有的内燃机,例如Unity(https://unity3d.com/learn/tutorials/modules/beginner/2d/physics2d)或Box2d(http://box2d.org/

希望这会有所帮助。

+0

感谢您的参考!我会开始挖掘他们。 –

1

迭代所有的球并改变每次迭代的球位置可能是导致不稳定的原因,您将一个球左移以避免右边碰撞,然后您将球推入左边的另一个球,然后左边的球试图再次推回来。

从我的头顶开始,我可以推荐在做任何关于定位的事情之前总结每个球的所有力量。如果你从“顶部”球(离重力源/方向最远)迭代球,你可能会达到稳定的状态。

基本上,顶级球需要先计算自身与其下的球之间的力,再加上重力,那么下方的球就会知道顶球有多大的力,并且会增加重力也增加了它在它下面推动球的力量。当所有的球知道他们与你一起推动的力量时,可以将这个力量转化为运动。

1

你模拟球物理的方式必然会引起不稳定。您的碰撞分辨率会尝试通过将碰撞深度中的一个投影到相反的方向来分离球。这可能会解决这两个球的重叠问题,但有可能(特别是当球堆叠时)球现在与另一个球重叠。

修复渗透的方法有很多。最简单的方法之一是给两个机构增加一个“偏见”或一点点推动力,迫使他们在接下来的几帧内分开。这使得能量传播并强制所有的身体分开。问题是,偏见往往会被高估,并导致一些反弹。要解决这个问题,我建议阅读顺序冲动。

让物理看起来逼真并不像看起来那么简单。除非你不介意不稳定性,否则我建议花一些时间阅读不同的技术或使用Box2D等引擎。

+0

我同意,我需要推两者,而不只是一个。不会推两者仍然有可能与其他球重叠?我想知道我是否应该首先解决最接近边界的球并朝着中心前进。我会更详细地阅读你提到的内容,这似乎非常困难! –

+0

@GreenCell偏见不是投影。这对两个机构都是一个应用的力量。这意味着当下一次脉冲分辨率通过时,能量会传播。我假设你正在使用脉冲分辨率。如果你不是,我会建议阅读它。 – py13579