Jump to content
Unity Insider Forum

Um anderes Objekt kreisen


Stigma

Recommended Posts

Hallo,

ich versuche ein Objekt um ein anderes Objekt im Kreis mit einem gewissen Radius fahren zu lassen.
Ich habe mir dafür ein Empty auf (0/0/0) gesetzt und mein anderes Objekt auf (0/0/-15).  Und dann mit
 

transform.RotateAround(emptyObjectTransform.position, Vector3.up, speed * Time.deltaTime);

ums Objekt fahren lassen. Das funktioniert auch genau so, wie ich mir das vorgestellt habe. Nur leider funktioniert die Collision so ja gar nicht.
Darum wollte ich das nun gerne mit dem CharacterController machen. Nur leider weiss ich nicht genau, wie ich die Rotation um das Objekt als MotionVector genau so berechnet bekomme, wie es transform.RotateAround macht.

Hat da jemand eine Idee, wie man das mit dem CharacterController lösen kann? Oder vielleicht auch eine andere Lösung, bei der Collision funktioniert?

Liebe Grüße
 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hey,

danke für deine Antwort!

Meinst du das so, dass ich ein Parent habe, welches ich mit transform.RotateAround rum fahren lassen und dann ein Child mit einem CC habe, welches dem Parent folgt?
So in entwa?

parent.transform.RotateAround(emptyObjectTransform.position, Vector3.up, speed * Time.deltaTime);
Vector3 direction = parent.transform.position - child.transform.position;
child.CharacterController.Move(direction);

Nur sehe ich dann das Problem, dass wenn das Child kollidiert, dass der Parent einfach weiter fährt und das Child dann irgendwann durch den Collider glitcht.
Oder habe ich dich falsch verstanden?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Naja, wenn dein CC ein Child des sich bewegenden Objekts ist, dann kommt er ja wieder mit, ohne sich eigenständig zu bewegen und wird Kollisionen erstmal wieder ignorieren. Das führende Objekt und der folgende CC sollten daher nicht übereinander in der Hierarchie sein.

vor 38 Minuten schrieb Stigma:

Nur sehe ich dann das Problem, dass wenn das Child kollidiert, dass der Parent einfach weiter fährt und das Child dann irgendwann durch den Collider glitcht.
Oder habe ich dich falsch verstanden?

Genau - wenn du sie einander unterordnest. Wenn du das aber nicht tust, wird der CC (zumindest aufgrund dieses Setups...) nicht irgendwo durch glitchen.

Was aber in der Tat passiert ist, dass der Parent einfach immer weiter geht. Der kriegt von Kollisionen ja nix mit. An diesem Punkt musst du dir überlegen, was du eigentlich für ein Verhalten haben willst. Soll dein CC immer, unter allen Bedingungen, auf dem Kreis bleiben? Oder könnte er an einem Hindernis auch vorbei rutschen und kommt dann irgendwann wieder auf dem Kreis an?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ok, ich verstehe was du meinst. Wenn es nicht untergeordnet wird, glitcht er zwar nicht durch, aber rutscht anhand des Winkels irgendwann am Obstacle vorbei.

Das Verhalten soll schon so sein, dass wenn der CC kollidiert auch angehalten wird. Also das Objekt das im Kreis fährt und das der CC verfolgt, müsste eigentlich auch stehen bleiben. Man kann schon sagen, dass sie immer zusammen bleiben sollen.

Hast du da eine Idee, wie ich das erreichen kann?
Das Einzige was mir in den Sinn kommt, ist bei einer Kollision den Input zu disablen, damit das Objekt, welches im Kreis fährt auch stehen bleibt. Nur dann könnte ich nicht mehr in die andere Richtung fahren. Dann müsste ich mit einem Raycast gucken, ob die andere Seite frei ist oderso. Aber eigentlich wollte ich keine Raycasts benutzen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Kreise können etwas problematisch sein, weil Bewegung immer linear ist. Wenn ein Objekt auf- und vorwärts geworfen wird, dann passiert in der Simulation keine "echte" Kurve, sondern Aneinanderreihung von ganz vielen kleinen Linien, die annähernd eine Kurve beschreiben.

Deshalb bewegst du auch deinen CC nur so "halbwegs wirklich" auf einem Kreis - die Positionen, auf die du ihn in jedem Frame aufs neue schickst, liegen (hoffentlich) alle auf dem Kreis, aber wenn das Ding auf dem Weg von einem Punkt zum nächsten kollidiert, dann wäre diese Kollision halt nicht mehr auf dem Kreis.

grafik.png

Da man meistens keinen Achtelkreis, sondern einen viel kleineren Weg am Stück zurück legt, ist er erst mal nicht so krass - aber da man das ganz oft pro Sekunde macht, kann sich diese kleine Abweichung schnell mit allen anderen Aufsummieren. Eine saubere Lösung geht mit diesem Problem also irgendwie um.

Was du machen könntest wäre ein eigener Physik-Check. Du nimmst dir eine der Funktionen in Physics, z.B. Physics.CapsuleCast, welches eine imaginäre Kapsel (also genau die Form deines CC) durch die Gegend schießt und schaut, ob eine Kollision passieren würde. Du könntest ganz stumpf sagen dass, wenn das passiert, einfach keine Bewegung in diesem Frame passieren soll. Du könntest das mit der oberen Idee (die übrigens nicht unbedingt "die beste" ist!) kombinieren, indem du dann auch den "Vorangeher" anhältst, anstatt dass er sich weiter dreht. Er dreht sich also nur so lange, wie der CC auch folgen kann, und wartet ansonsten.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Vielen Dank für die genaue Erklärung!

Genau das was du mit den Physics.CapsuleCast meinst, meinte ich auch. Nur halt mir einem Physics.RayCast. Aber so richtig glücklich bin ich mit dieser Lösung irgendwie nicht. Am liebsten hätte ich eine Methode, die mir einfach den Motion Vector zurück gibt und ich den einfach für CC.Move verwenden kann. Ich habe auch versucht die transform.TurnAround Funktion "nachzubauen". Aber leider stehe ich da Mathematisch völlig auf dem Schlauch.

Die Frage ist, was ist an dieser Stelle "die beste" Lösung. Du scheinst da ja ziemlich Fit zu sein. Hast du noch eine Idee, wie man das sonst angehen könnte? Vielleicht auch ohne CC. Aber ich denke, dass ich mit einem Rigidbody und AddForce genau das selbe Problem haben werde.  

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn du einfach einen Bewegungsvektor berechnen lässt, ihn in CC.Move reinsteckst und er dann auf dem Weg kollidiert, dann wird der CC halt nicht mehr auf dem Kreis sein. Und wenn das mehrere Frames hintereinander passiert, kann das auch durchaus sichtbar werden. Das war nach meinem Verständnis das, was du vermeiden wolltest.

Du könntest jetzt mit Trigonometrie da ran und dir mit Sinus und Kosinus die nächste Position auf dem Kreis ausrechnen. Der Vorschlag mit dem leeren Objekt, dem gefolgt wird, war nur, um das zu vermeiden - Trigonometrie selber machen ist meh :P

Du musst das Objekt auch nicht durchgehend weiter laufen lassen. Du kannst das Objekt auch in jedem Frame auf die Position des CCs setzen und von dort aus mit RotateAround weiterdrehen. Sollte nichts mit dem CC passieren, dann dreht sich das Ding die ganze Zeit, aber sollte er kollidieren, dann würde das Objekt immer wieder auf die Position des CCs zurückspringen, bevor er sich dreht.

Irgendwie sowas:

public Transform leader;
public CharacterController characterController;

private void FixedUpdate()
{
  leader.position = characterController.position;
  leader.RotateAround( ... );
  var direction = leader.position - characterController.transform.position;
  characterController.Move(direction);
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja genau, dass soll eigentlich nicht passieren. Der soll immer auf dem selben Kreis fahren und nicht abweichen. 
Wenn ich jetzt den leader immer auf die Position vom CC setze und dann gegen ein Obstacle komme und einfach immer weiter gegen fahre, verschiebt sich der CC ja auch und rutscht dann irgendwann einfach dran vorbei. Dann fährt er danach zwar weiter im Kreis. Nur leider nicht auf dem richtigen.

Ich vermute das selbe Problem hätte ich auch, wenn ich das über Trigonometrie löse, da ich da ja den nächsten Punkt auf der Kurve anhand meiner aktuellen Position berechnen würde, wenn ich mich nicht irre. Und wenn durch die Kollision schon eine Verschiebung stattgefunden hat, wäre der nächste Punkt ja auch nicht akkurat.  

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 47 Minuten schrieb Stigma:

Wenn ich jetzt den leader immer auf die Position vom CC setze

Naja - du kannst den Leader auf den Kreis zurück setzen. Dafür musst du nur die Distanz zum Kreismittelpunkt nehmen, die Distanz normalisieren (auf Länge 1 bringen) und dann mit dem Kreisradius multiplizieren. Damit bewegt sich der Leader auf den Kreismittelpunkt zu bzw. davon weg, um wieder auf dem Kreis zu landen.

var directionToCenter = leader.position - centerPosition;
var directionOntoCircle = directionToCenter.normalized * circleRadius;
leader.position = centerPosition + directionOntoCircle;

Und wenn der Leader immer auf dem Kreis bleibt, egal was der CC macht, dann wird der CC auch immer wieder auf den Kreis zusteuern.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe das mal ausprobiert und das funktioniert soweit auch ganz gut. Vielen Dank dafür!

Jetzt habe ich noch das Problem, dass bei der Kollision die Position des leaders wieder auf den Kreis gesetzt wird. Aber die Rotation nicht.
Das habe ich so gelöst:

Vector3 directionToCenter = leader.transform.position - origin.position;
leader.transform.rotation = Quaternion.LookRotation(directionToCenter);

Meinst das ist ok so, oder hast du da eine smartere Idee?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Der CC soll dem rechts Vektor vom Leader folgen. Ich gucke quasi von der Seite in die Mitte auf den CC, während er um den Zylinder fährt. Dabei nimm der CC dann die.

characterController.transform.rotation = Quaternion.LookRotation(leader.transform.right);

 Wenn du verstehst, was ich meine. 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Was du suchst, ist das Kreuzprodukt von Vector3.up und dem Vektor vom CC zum Kreismittelpunkt. Ein Kreuzprodukt zweier Vektoren ist der Vektor, der senkrecht zu beiden Vektoren ist. Das wäre dann (ausgehend davon, dass dein Kreis horizontal ist) die Tangente des Kreises.

var lookDirection = Vector3.Cross(Vector3.up, directionToCenter);
characterController.transform.rotation = Quaternion.LookDirection(lookDirection);

Wenn der Vektor in die falsche Richtung zeigen sollte, Parameter-Reihenfolge vertauschen oder bei einem von beiden ein Minus davor klatschen :D

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...