Wie kann man in Farseer eine ganz bestimmte Art von Joint erstellen?

7

Bearbeiten

Problem gelöst (siehe Drackirs Antwort). Hier ist eine Demo von dem, was ich mit diesem Joint erreichen wollte. Weitere Informationen zum Szenario zu dieser anderen Frage .


Problem

Ich versuche, in Farseer eine ganz bestimmte Art von Verbindung zu erstellen, die sich so verhält:

  • Objekte sollten immer halten den gleichen Abstand zwischen ihnen in beiden der X- und Y - Achsen.
  • Übersetzung - Eine Kollision mit einem der Objekte sollte die gesamte Gruppe zusammen bewegen, aber die Gruppe darf sich nicht drehen - nur die einzelnen Objekte können sich aufgrund des Drehmoments um ihre Zentren drehen.
  • Drehung - Objekte sollten immer die gleiche Drehung haben. Bei einer Kollision mit einem der Objekte sollten sich alle anderen Objekte genau um den gleichen Betrag drehen.

Hier ist ein Bild:

Geben Sie hier die Bildbeschreibung ein

Wenn es mit Farseer keine Möglichkeit gibt, dies sofort zu erreichen, wie würde ich es dann erweitern, um einen neuen Join-Typ zu erstellen, der so funktioniert? Grundsätzlich möchte ich, dass sich jeder Körper wie ein "Klon" der anderen verhält, jedoch mit einem festen Versatz zwischen ihnen.

David Gouveia
quelle
Ich bin mir bei diesem speziellen System nicht sicher, aber können Sie die Kinematik für den "Geist" nicht einfach ausschalten und manuell verschieben / drehen?
Tetrad
Würde das nicht auch Kollisionen mit dem Geist deaktivieren? Vielleicht war Ghost nicht die beste Analogie dafür - vielleicht ein Klon.
David Gouveia
Dh Kollisionen mit dem Klon sollten sich auch auf den Hauptkörper auswirken (auf genau die gleiche Weise). Würde Ihr Vorschlag in diesem Fall funktionieren?
David Gouveia
Schlägt mich wahrscheinlich nicht.
Tetrad

Antworten:

6

Ok, nach ungefähr zwei Stunden Basteln habe ich das geschafft, aber es erfordert das Hinzufügen einiger zusätzlicher Körper. Sie werden dieses Zeug wahrscheinlich in eine Methode / Klasse extrahieren wollen, aber die Grundidee ist folgende:

  1. Erstellen Sie für Ihre Objekte so genannte "Halter" -Körper. Diese Körper teilen die Größe und Position Ihrer "Objekte", nehmen aber nicht an Kollisionen teil. Im Wesentlichen sind sie Klone.

    //Create "Main" (center) body
    _bodyMain = BodyFactory.CreateRectangle(World, 5f, 5f, 1f);
    _bodyMain.BodyType = BodyType.Dynamic;
    _bodyMain.Position = new Vector2(2, 2);
    //Create "MainHolder"
    _bodyMainHolder = BodyFactory.CreateRectangle(World, 5f, 5f, 1f);
    _bodyMainHolder.BodyType = BodyType.Dynamic;
    _bodyMainHolder.CollisionCategories = Category.None; //Prevents collisions
    _bodyMainHolder.Position = new Vector2(2, 2);
    _bodyMainHolder.IsSensor = true;
    //See http://farseerphysics.codeplex.com/discussions/222524 for why they're sensors
    _bodyMainHolder.FixedRotation = true;
    //Note: Only add FixedRotation for the main one, leave it off of the other
    //      holders. I'll explain later.
  2. Befestigen Sie jeden Halter mit einem am "Haupthalter" WeldJoint. Dies verhindert, dass sie sich voneinander entfernen. Der FixedRotationauf dem Haupthalter verhindert, dass sie sich drehen. Ich weiß nicht, ob es einen Fehler in Farseer gibt, aber wenn Sie einen hinzufügen WeldJointund beide Körper haben FixedRotation == true, funktioniert das Gelenk nicht richtig. Deshalb hat nur der Haupthalter .FixedRotation = true.

    //Weld the holders together so they don't move. Assumes another holder is defined
    //  for the object on the right side (bodyRightHolder).
    JointFactory.CreateWeldJoint(World, _bodyMainHolder, _bodyRightHolder,
    _bodyRightHolder.Position - _bodyMainHolder.Position, Vector2.Zero);
  3. Befestigen Sie Ihre "Objekt" -Körper mit RevoluteJoints an ihren jeweiligen Haltern . Dadurch werden Ihre Objekte an den Haltern befestigt, sie können sich jedoch frei drehen.

    //Lock the actual bodies to the holders
    JointFactory.CreateRevoluteJoint(World, _bodyMainHolder, _bodyMain, Vector2.Zero);
    JointFactory.CreateRevoluteJoint(World, _bodyRightHolder, _bodyRight, Vector2.Zero);
  4. Passen Sie die Rotationen Ihrer realen Objekte an, indem Sie ein Winkelgelenk anbringen. Hinweis: Sie müssen nicht an jedem Objektpaar ein Winkelgelenk anbringen. Fügen Sie einfach ein Winkelgelenk zum Hauptkörper und zum anderen Körper hinzu, und die Rotationen werden auf alle Objekte übertragen.

    //Make them rotate the same as each other
    JointFactory.CreateAngleJoint(World, _bodyMain, _bodyRight);

Das ist es! Fügen Sie einfach den zusätzlichen Code für jedes andere Objekt / Objekthalter hinzu, das Sie möchten, und der Rest wird erledigt. Hier ist ein Bild, um meinen Test zu veranschaulichen:Beispielbild von Testkörpern.

Hier sehen Sie, dass die grünen Körper die Halter sind. Sie drehen oder kollidieren nicht und sind miteinander verschweißt. Die gelben und roten Körper sind Ihre "Objekte" (gelb ist das Hauptobjekt). Sie können sehen, dass sie um den gleichen Betrag gedreht werden und sich um ihre jeweiligen Halter drehen. Außerdem nehmen nur die roten und gelben Körper an Kollisionen teil. Ich glaube, dies erfüllt alle drei oben genannten Bedingungen.

Arbeitsbeispiel

Wenn Sie die Farseer "Samples XNA" -Lösung laden und SimpleDemo1.cs ("Samples XNA" -Projekt> "Samples" -Ordner) finden, habe ich sie zum Testen neu geschrieben ( Code hier ).

Hoffe das hilft. Lassen Sie mich wissen, wenn Sie Fragen haben.

Richard Marskell - Drackir
quelle
Es scheint, dass noch ein Teil des Puzzles fehlt. So verschieben Sie das gesamte System sofort an eine andere Position in der Welt. Ich brauche dies, um die Objekte um die Bildschirmränder zu "wickeln". Nur die Position auf dem Haupthalter einzustellen, funktioniert nicht.
David Gouveia
Ungeachtet der vorherigen Frage scheint es zu funktionieren, wenn alle Inhaber und Hauptorgane gleichzeitig umgesiedelt werden.
David Gouveia
Ich bin froh zu helfen und ja, Sie müssten alle Leichen umsiedeln. Sie können es in eine Klasse einbauen und die relativen Positionen zum Hauptkörper speichern ( Vector2Unterschied zwischen der Körperposition und dem Hauptkörper). Positionieren Sie dann die Hauptposition neu und aktualisieren Sie einfach ihre Positionen relativ zur Hauptposition.
Richard Marskell - Drackir
Das habe ich so ziemlich getan. :)
David Gouveia
0

Leider kann ich diese Antwort nicht überprüfen, da ich gerade telefoniere. Ich entschuldige mich, wenn es nicht wie erwartet funktioniert.

Ich denke, Sie könnten mehrere vorhandene Gelenke verwenden, um das zu erreichen, was Sie wollen. Erstellen Sie einen Körper ohne Kollisionsgeometrie an der Ecke Ihres Dreiecks. Anschließend können Sie drei Distanzgelenke verwenden, um die gewünschte Übersetzung zu erzielen. Wenn Sie dann die beiden kollidierbaren Körper mit einem festen Winkelgelenk verbinden, drehen sie sich zusammen.

Martin
quelle
Ich habe im Moment auch ein bisschen wenig Zeit und werde es heute Abend versuchen. Aber obwohl mein Beispiel nur zwei Körper hatte, brauche ich tatsächlich etwas Komplexeres mit 9 verbundenen Körpern . Gilt Ihre Idee noch?
David Gouveia
@ David: Das sieht ... interessant aus. Können Sie mehr darüber sagen, was Sie mit diesem Setup erreichen möchten? Ich frage mich, ob es möglicherweise keinen alternativen Weg gibt, um das zu erreichen, was Sie wollen.
Ilmari Karonen
@IlmariKaronen Am Ende meiner Frage befindet sich ein Link zu einer anderen Frage, die genau beschreibt, was ich erreichen möchte. Grundsätzlich versuche ich, die Physik in einer 2D-Umgebung richtig zu handhaben, in der sich Körper um die Ränder "wickeln" und gleichzeitig auf mehreren Seiten des Bildschirms erscheinen können.
David Gouveia
@Martin Ich habe heute noch keine Zeit, dies zu testen, also melde ich mich morgen wieder.
David Gouveia
Okay, ich habe es jetzt versucht, konnte es aber nicht schaffen. Das Problem ist, dass ich verhindern möchte, dass sich das gesamte System dreht. Die 3 Distanzverbindungen (die auch durch 2 Schweißverbindungen ersetzt werden können) halten das System starr, verhindern jedoch nicht, dass es sich dreht.
David Gouveia