2016-02-27 9 views
5

In Java schreibe ich eine mobile App für Android, um mit einigen dynamischen Bällen mit einigen Klassen zu interagieren, die ich selbst geschrieben habe. Die Schwerkraft hängt von der Neigung des Telefons ab.Physikkreiskollisionen knallen und gleiten gegen Grenzen

Ich bemerkte, wenn ich ein Bündel von Bällen in einer Ecke gebündelt habe, dass einige von ihnen anfangen zu jittern, oder manchmal rutschen, während sie mit anderen Bällen kollidieren. Könnte das sein, weil ich Schritte in der falschen Reihenfolge ausführe?

Im Moment habe ich eine einzige Schleife durch jeden Ball gehen:

  • Sim eine Iteration
  • prüfen Kollisionen mit anderen Kugeln
  • prüfen Kollisionen gegen Szene Grenzen

ich sollte fügen Sie hinzu, dass ich Reibung mit den Grenzen habe und wenn eine Ball-zu-Ball-Kollision auftritt, nur um Energie zu verlieren.

Hier ist ein Teil des Codes, wie Kollision behandelt wird:

// 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

Können wir sehen, was Sie bisher getan haben? – Dan

+0

Testen Sie in Ihrem Kollisionstest, ob sich die beiden Objekte aufeinander zu bewegen? Berechnen Sie exakte Kollisionszeiten oder lassen Sie die Objekte ineinander gleiten? – LutzL

+0

Mit einem Code aktualisiert. Ich teste nicht, ob sich zwei Objekte aufeinander zu bewegen. Momentan erlaube ich den Kugeln, sich ineinander zu bewegen und dann mit der Kollision umzugehen. –

Antwort

2

Wenn dies der einzige Code, der für die Wechselwirkungen zwischen den Kugeln überprüft, dann scheint das Problem ziemlich klar. Es gibt keine Möglichkeit, dass ein Ball im Gleichgewicht auf einem anderen Ball ruht.

Angenommen, Sie haben einen Ball direkt übereinander. Wenn Sie die Beschleunigung der oberen Kugel aufgrund der Schwerkraft berechnen, sollten Sie auch eine Kollisionsprüfung wie die von Ihnen gepostete durchführen, außer dass Sie diesmal nach dist <= ball.radius + otherBall.radius suchen. Wenn dies der Fall ist, dann sollten Sie eine Normalkraft zwischen den Kugeln annehmen, die der Gravitation entspricht, und die Schwerkraftkomponente in Übereinstimmung mit dem Vektor neutralisieren, der die beiden Kugelzentren verbindet. Wenn Sie dies nicht tun, beschleunigt sich der obere Ball in den unteren und löst den von Ihnen geposteten Kollisionscode aus, und Sie bekommen die Unruhe.

Eine ähnliche Logik muss verwendet werden, wenn ein Ball mit einer Szenengrenze in Kontakt ist.

+0

Ich glaube, ich verstehe, worauf Sie hinauswollen, aber ich habe Probleme, die Kollisionsreaktion herauszufinden. Nehmen wir an, ich habe 'ball1' oben auf' ball2'. Bevor ich 'ball1' simuliere, teste ich es gegen' ball2', ​​um zu sehen, ob sie sich bereits berühren. Wenn dies der Fall ist, muss ich die Position von "ball1" anpassen und die Richtung der Schwerkraft anpassen, damit sie nicht durchgeht. –

+0

Ihre Einstellung der Position ist in Ordnung; es ist die Schwerkraft, die Sie einstellen müssen, da dies der normalen Kraft zwischen den beiden Kugeln entgegenstehen würde. Wenn also ball1 ball2 berührt und das Vektor-Dot-Produkt der Ball1-Gravitation (g) mit dem von Ball1 zu Ball2 zeigenden Vektor (v) positiv ist, dann möchten Sie den Ball1-Gravitationsvektor v-mal (g-Punkt v)/v subtrahieren^2). Das ist die Komponente des Gravitationsvektors in Richtung v. –

1

Seit ich mit meiner eigenen Phys2D-Engine experimentiere (nur zum Spaß), weiß ich, dass du davon sprichst. (Nur für den Fall - Sie können meine Demo hier überprüfen: http://gwt-dynamic-host.appspot.com/ - wählen Sie "Circle Collisions Demo" dort, und entsprechenden Code hier: https://github.com/domax/gwt-dynamic-plugins/tree/master/gwt-dynamic-main/gwt-dynamic-module-bar).

Das Problem liegt in der Natur von Iterationen und Endlosschleife kollidierender Folgen. Wenn z.B. Ball ist die Szene Ecke erreicht, es erlebt mindestens 3 Vektoren der Kraft: Impuls der Bounce von der Wand, Impuls des Bounce vom Boden und Impuls der Schwerkraft - nachdem Sie alle 3 Impulse zusammenfassen, reduzieren Sie es nach verlieren Energie-Algorithmus, haben Sie um den neuen Vektor zu haben, wo dein Ball sein sollte. Aber z.B. dieser Impuls lenkt ihn in die Wand - dann musst du die Menge der Vektoren wieder neu berechnen nach all dem Zeug: Energie des Bounce, Impulse, Gravitation, usw. Auch wenn alle diese Impulse klein sind, bekommst du nie alle von ihnen 0 , wegen der Genauigkeit der Doppel und Ihrer Toleranz Vergleichskonstanten - dass, weil Sie die "Jitter" und "gleitende" Effekte haben.

Tatsächlich haben die meisten 2D-Engines diese Effekte auf die eine oder andere Art: Sie können sie hier sehen: http://brm.io/matter-js/demo/#wreckingBall oder hier: http://box2d-js.sourceforge.net/index2.html - sie machen nur die kleinen Impulse schneller absorbiert und hören auf zu iterieren, wenn das ganze System wird mehr oder weniger stabil, aber es ist nicht immer möglich.

Wie auch immer, ich würde nur empfehlen, erfinden Sie Ihr eigenes Rad nicht neu, es sei denn, es ist nur für Ihren Spaß - oder für Ihr besseres Verständnis dieses Zeug.

Für letzte (JFF) - hier ist gutes Tutorial: http://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331

Für echte Dinge, würde ich empfehlen, die bestehenden Motoren zu verwenden, z.B. Unity (https://unity3d.com/learn/tutorials/modules/beginner/2d/physics2d) oder Box2d (http://box2d.org/)

Hoffe das hilft.

+0

Danke für die Hinweise! Ich werde anfangen, in sie zu graben. –

1

Iterieren durch alle Bälle und Ändern der Bälle Position für jede Iteration ist wahrscheinlich die Ursache für die Instabilität, bewegen Sie einen Ball links, um eine Kollision auf der rechten Seite zu vermeiden, und dann schob Sie den Ball in einen anderen Ball auf der linken Seite, und dann versucht der linke Ball, ihn wieder zurückzudrücken.

Von der Spitze meines Kopfes könnte ich empfehlen, alle Kräfte auf jedem Ball zusammenzufassen, bevor Sie etwas über die Positionierung tun. Und wenn Sie vom Ball "oben" iterieren (am weitesten weg von der Schwerkraftquelle/-richtung), können Sie wahrscheinlich eine stabile Situation erreichen.

Grundsätzlich muss der obere Ball zuerst Kräfte zwischen sich und den darunter liegenden Kugeln berechnen, zuzüglich der Schwerkraft, dann weiß der Ball unter der Feder, wie viel Kraft von der oberen Kugel kommt, und mit der Schwerkraft würde es dazukommen fügen Sie auch der Kraft hinzu, von der es die Bälle unter ihm schiebt. Wenn alle Kugeln die Kräfte kennen, mit denen sie gedrängt werden, kann diese Kraft in Bewegung umgesetzt werden.

1

Die Art, wie Sie die Physik der Kugeln simulieren, verursacht Instabilitäten. Ihre Kollisionsauflösung versucht die Kugeln zu trennen, indem Sie eine von ihnen in die entgegengesetzte Richtung durch die Kollisionstiefe projizieren. Dies kann die Überlappung für diese zwei Bälle fixieren, aber die Chancen stehen (insbesondere wenn die Bälle gestapelt sind), dass der Ball nun mit einem anderen Ball überlappt.

Es gibt viele Möglichkeiten, die Penetration zu beheben. Eine der einfachsten Möglichkeiten besteht darin, beiden Körpern einen "Bias" oder ein bisschen Push hinzuzufügen, um sie zu zwingen, sich über die nächsten paar Frames zu trennen. Dadurch kann sich diese Energie ausbreiten und alle Körper auseinandertreiben. Das Problem ist, die Verzerrung wird oft überschätzt und verursacht ein bisschen einen Sprung. Um dieses Problem zu beheben, empfehle ich, den sequentiellen Impuls zu lesen.

Die Physik realistisch aussehen zu lassen ist nicht so einfach wie es scheint. Sofern Sie Instabilitäten nicht ablehnen, würde ich Ihnen empfehlen, sich über verschiedene Techniken zu informieren oder eine Engine wie Box2D zu verwenden.

+0

Ich stimme zu, ich muss beide statt nur die eine drücken. Würden beide nicht immer noch die Möglichkeit haben, dass beide andere Bälle überlappen? Ich frage mich, ob ich zuerst Bälle, die den Grenzen am nächsten sind, lösen sollte und sich in Richtung Zentrum arbeiten soll. Ich werde mehr darüber lesen, was du erwähnt hast, das scheint sehr hart zu sein! –

+0

@GreenCell Die Verzerrung ist keine Projektion. Es ist eine angewandte Kraft für beide Körper. Dies bedeutet, dass die Energie sich ausbreitet, wenn der nächste Impulsauflösungsdurchlauf kommt. Ich gehe davon aus, dass Sie die Impulsauflösung verwenden. Wenn Sie nicht sind, würde ich empfehlen, es zu lesen. – py13579