Ich arbeite an einem Spiel, bei dem der Spieler Objekte mit einem Traktorstrahl aufnehmen und herumtragen kann.
Das Objekt in Richtung Strahlmitte anzuziehen ist nicht schwierig. Aber sobald das Objekt nahe genug an der Mitte ist, muss ich es dort halten, während sich der Spieler bewegt, womit ich Probleme habe. Ich kann mir zwei Möglichkeiten vorstellen, und beide haben Probleme:
Aktualisieren Sie die Position des Objekts, wenn sich die Position des Spielers ändert, und halten Sie es auf dem Strahl zentriert.
Aktualisieren Sie die Geschwindigkeit des Objekts so, dass sie direkt auf die Mitte des Strahls zeigt. Je weiter entfernt, desto höher die Geschwindigkeit.
Das Bewegen und Drehen funktioniert bei beiden Ansätzen einwandfrei, aber die Physik ist falsch, wenn das getragene Objekt mit anderen Objekten kollidiert:
Beim ersten Ansatz wird die Physik völlig ignoriert. Das getragene Objekt schiebt einfach alles aus dem Weg. Das liegt daran, dass Positionsänderungen nur als Teil der Weltphysik basierend auf der Geschwindigkeit vorgenommen werden sollen.
Beim zweiten Ansatz verhält sich die Physik grundsätzlich so, wie sie sollte, reagiert jedoch übermäßig. Das Problem ist: Um das getragene Objekt auch beim Drehen und Bewegen in der Mitte des Strahls zu halten, muss ich hohe Geschwindigkeitswerte verwenden. Sobald das getragene Objekt ein anderes berührt, wird die Kollision viel zu schnell.
Wie kann ich das richtig umsetzen? Meine derzeit beste Vermutung ist, den zweiten Ansatz zu wählen und der Weltphysik eine spezielle Handhabung für getragene Objekte hinzuzufügen, um die Geschwindigkeit auf vernünftige Werte für Kollisionen zu reduzieren oder wenn der Spieler aufhört, sie zu tragen. Aber das scheint eine ziemlich unelegante Problemumgehung zu sein.
Bearbeiten: Hinzufügen von Pseudocode, um zu veranschaulichen, wie es jetzt funktioniert (das wäre der zweite Ansatz oben)
void attract_object(object, ticks) {
Vector distance = beam_center - object.center;
// If the object is not close to the beam center, attract it slowly
if (magnitude(distance) > 10) {
object.velocity += distance.normalized() * ticks * 0.1;
return;
}
// Here comes the part we're talking about. That magic 0.5 is just high enough
// that the object isn't lost while moving around. But it's still so high that
// other objects are repelled with way too much force.
object.velocity = distance * ticks * 0.5;
}
Soweit ich weiß, geschieht dies, wenn das getragene Objekt ein anderes Objekt wegschiebt:
- Das getragene Objekt kollidiert mit einem anderen Objekt
- Die Geschwindigkeiten der Objekte sind richtig verteilt, so dass das getragene Objekt dabei von der Mitte des Strahls weggeschoben wird
- Der obige Code bewirkt, dass das getragene Objekt mit so viel Geschwindigkeit in die Mitte des Strahls zurückkehrt, dass es schnell dorthin zurückkehrt
- Wenn sich das getragene Objekt zur Mitte des Strahls zurückbewegt, wird die Hälfte seiner hohen Geschwindigkeit auf das andere Objekt übertragen, wodurch es heftig abgestoßen wird. Da die Anfangsgeschwindigkeit des getragenen Objekts vernünftig zu sein scheint, kann ich mir vorstellen, dass die Schritte 2 bis 4 mehrmals wiederholt werden, wodurch eine so hohe Geschwindigkeit entsteht.
Das scheint die Ursache zu sein. Ich kann mir keinen guten Weg vorstellen, das Problem zu beheben :(
Antworten:
Im Wesentlichen suchen Sie, dass sich das "gestrahlte" Objekt genau so verhält, als würden Sie es mit Ihren Händen greifen.
Eine Möglichkeit wäre, es die Beschleunigungs-A / O-Geschwindigkeiten der 'Hand' teilen zu lassen, die es hält, anstatt seine Geschwindigkeit anzupassen, um die Lücke mit der Mitte des Strahls zu füllen.
Angenommen, die Mitte des Strahls ist die haltende Hand. Wenn sich Ihr Charakter in 1 Sekunde um 90 Grad nach links dreht, beträgt die Geschwindigkeit der Hand:
If R = length of the arm: which is the radius of the rotation circle
Machen Sie es mal die verstrichene Zeit des Rahmens, um die Geschwindigkeit zu finden, die Sie auf Ihr Objekt anwenden müssen. Finden Sie die horizontale Normale zum Strahl, um seinen Richtungsvektor zu finden.R^2 *PI /4 would be the distance traveled over a second.
Mein Punkt ist, dass Sie keine Probleme lösen müssen, wenn Sie andere Implementierungen ausprobieren, die dies überhaupt nicht verursachen.
Ich würde mit der Schwerkraftkanone in HL2 spielen gehen, um mich von dem Problem inspirieren zu lassen, aber ich habe heute andere Pläne.
EDIT: Es tut mir leid, ich dachte, es wäre für eine 3D-Strahlpistole, aber es ist im Wesentlichen das gleiche mit 2D, außer dass die Achsen unterschiedlich sind (und es keine komplexe Geometrie gibt).
quelle
Wie wäre es, wenn Sie eine Federverbindung hinzufügen, dh das getragene Objekt zwingen, sich basierend auf der Entfernung in die Trageposition zurückzubewegen, es aber dennoch von festen Gegenständen (wie Wänden) wegschieben zu lassen.
Passen Sie die Geschwindigkeit des getragenen Objekts ständig an (indem Sie die Beschleunigung basierend auf Position / Entfernung ändern), um auf die Position des Traktorstrahls zu zeigen (dh auf Ihren zweiten Ansatz). Wenn das Objekt zu weit weggeschoben wird, trennen Sie die Verbindung (und das Objekt).
Ich bin mir nicht sicher, warum Sie hohe Geschwindigkeiten benötigen würden. Insbesondere der Fall "Spieler lässt los" weist darauf hin, dass Ihre Rotationsgeschwindigkeit möglicherweise zu hoch oder unrealistisch ist. Vergessen Sie auch nicht Dinge wie Luftwiderstand und Schwerkraft.
Bearbeiten: In Anbetracht des aktualisierten Codes ist das Problem eher trivial zu finden:
Das Problem ist hier der Fall, in dem der Abstand des Objekts zu seiner Zielposition ständig zu groß ist (dh
> 10
). Solange diese Bedingung erfüllt ist, nimmt die Geschwindigkeit einfach immer wieder zu (dh auf unbestimmte Zeit).Zwei mögliche Lösungen hierfür:
Definieren Sie eine maximale Geschwindigkeit:
Wenden Sie eine feste Geschwindigkeit an, anstatt zu beschleunigen:
Nur zu beschleunigen, während man zu weit weg ist, ist hier definitiv ein falscher Ansatz. Eine Feder oder ein Gummiband ziehen: Es spielt keine Rolle, ob Sie es eine Sekunde oder eine Minute lang halten. Am Ende wird es auf die gleiche Weise beschleunigen (wenn man bedenkt, dass es nicht in Bewegung war und keine anderen Kräfte angewendet werden).
quelle