Motorradspiel - Phsik- Dämpfung der Feder
-
Hallo Freunde,
ich schreibe immer mal an mein 2D-Motorradspiel. Ich habe das so gemacht, das mein Motorrad aus 3 Massepunkten(Zwei Räder, Ein Kopf) besteht. Die Räder und der Kopf sind mit Federn verbunden(Dadurch entsteht ein Dreieck).
Alle 50ms berechne ich für jeden Massepunkt zuerst alle Kraftvektoren, welche auf sie wirken. Dann berechne ich aus den Kraftvektoren Beschleunigungsvektoren, welche ich auf die aktuelle Geschwindigkeit von jeden Massepunkt drauf addiere.
Nun zu meinen Problem: Stellt euch mal zwei Masspunkte vor, die mit einer Feder verbunden sind und wo es auch Schwerkraft gibt. Ich lasse diesen Federstab nun zu Boden fallen.
[A]
\
\
[B]------ <-Boden
Der Stab wird dadurch zusammen gedrückt und fällt dann um, wenn er etwas Schräg als Startbedingung in der Luft war. Bei mir passiert es nun, dass die Massepunkte sich im ständigen Wechselspiel zusammenziehen und auseinander drücken. Es gibt keine Dämpfung. Den Luftwiderstand kann und will ich nicht dazu missbrauchen, da ansonsten das Motorrad nur ganz langsam nach unten fällt, wenn die Luft zu sehr bremst.
Hier mal mein Code:
float federKonstante1 = 10;//Streckung float federKonstante2 = 10;//Stauchung Vektor Ffeder3 = new Vektor(0, 0); Vektor Rfeder3 = (punkte[1].pos - punkte[0].pos); float federLänge3 = Rfeder3.Betrag(); if (federLänge3 != 0) Ffeder3 = Rfeder3 / federLänge3 * (federLänge3 - radAbstand) * (federLänge3 > radAbstand ? federKonstante2 : federKonstante1);//Federkraft zwischen Rad1 und Rad2 //Ffeder3 += -(punkte[1].gesch - punkte[0].gesch) * innereReibung; punkte[0].kraft = /*Ffeder1 +*/ Ffeder3; punkte[1].kraft = /*Ffeder2*/ -Ffeder3; //Berechne für alle Punkte die Gravitations- und Federkraft punkte[0].kraft += new Vektor(0, 9.81f) * punkte[0].masse;// +Ffeder1 + Ffeder3; punkte[1].kraft += new Vektor(0, 9.81f) * punkte[1].masse;// +Ffeder2 - Ffeder3; punkte[2].kraft += new Vektor(0, 9.81f) * punkte[2].masse;// +kopfKraft - Ffeder1 - Ffeder2; //Motorkraft hinzufügen if (IsKeyDown(Keys.Up)) { punkte[blickrichtung ? 0 : 1].kraft += motorKraft * 500 * (blickrichtung?1:-1); } float time = sender.Interval / 1000.0f; for (int i = 0; i < punkte.Length; i++) { //Luftwiderstand punkte[i].kraft -= punkte[i].gesch * 0.02f; //Rollwiederstand if (punkte[i].wandTouchZähler > 0) punkte[i].kraft -= punkte[i].gesch * 0.2f; punkte[i].gesch += punkte[i].kraft * (time) / punkte[i].masse; punkte[i].pos += punkte[i].gesch * time; ...Kollisionsabfrage ... }
Die Feder, welche die Massepunkte [0] und [1] verbindet soll möglichst Starr sein. Schon eine kleine Längenänderung soll sofort die Punkte wieder auf den richtigen Abstand drücken/ziehen. Dabei darf es aber nicht zu unendlichen Schwingungen kommen. Die Gravitation soll ungehindert von der Ferderdämpfung bleiben.
@Anmerkung: Was genau ist es, was eine Feder dämpft? Der Luftwiederstandsvektor ist ja leicht zu berechnen. punkte[i].kraft -= punkte[i].gesch * 0.02f; Wie lautet die Formel um den Federdämpfungsvektor zu berechnen?
Ich brauche eure Hilfe sonst bin ich im Arsch Leute
-
Ein Stossdaempfer, daempft einen Feder. Also Stroemungswiderstand in einer Fluessigkeit.
-
Du sagst eine Flüssigkeit dämpft im Stoßdämpfer die Feder? Das würde ja bedeuten man könnte dort die gleiche Formel wie beim Luftwiderstand anwenden.
Ich habe jetzt den Quelltext so abgehändert:
//Federkraft punkte[0].kraft = /*Ffeder1 +*/ Ffeder3; punkte[1].kraft = /*Ffeder2*/ -Ffeder3; //Dämpfe die Federung for (int i = 0; i < punkte.Length; i++) if (punkte[i].gesch.Betrag()>2) punkte[i].gesch += Vektor.Projektion(punkte[i].kraft, -punkte[i].gesch) * 0.8f;
Die Dämpfung tritt also nur Axial in Richtung der Feder auf und ist auch nur von der Geschwindigkeit, mit der die Federenden durch die Dämpfungsflüssigkeit rauschen abhängig.
Allerdings führt die Dämpfungsformel nun dazu, das mein Motorrad in der Luft zu zucken und zu schweben anfängt, wenn ich eine Klippe runter springe. Was könnte die Ursache sein? Ist meine Dämpfungsformel überhaupt richtig?
Ok, mit dieser Dämpfungsformel schwebt das Motorrad nicht mehr:
//Dämpfe die Federung for (int i = 0; i < punkte.Length; i++) if (punkte[i].gesch.Betrag() > 1 && punkte[i].kraft.Betrag() > 1) { //Dämpfungskraft Vektor daempfung = Vektor.Projektion(punkte[i].gesch, punkte[i].kraft); float daempfLaenge = daempfung.Betrag(); float kraftLaenge = punkte[i].kraft.Betrag(); if (daempfLaenge > 1 && !Vektor.EqualDirection(punkte[i].kraft, daempfung)) punkte[i].kraft -= daempfung * kraftLaenge / daempfLaenge * 1.1f; }
-
Ich würde es so modellieren, dass die Feder nur in eine Richtung geht. Heißt, beim Fahren wird die Feder / das Rad eingedrückt, es kann aber nicht heraus gezogen werden. Wenn du dann von der Klippe springst, dann wird das Rad einmalig von der Feder heraus gedrückt, völlig schwingungsfrei.
-
Mit der starren Feder ist das so eine Sache. Nehmen wir mal ein ich habe die Abfrage
//Feder liegt zwischen [A] und [B]
if (aktuelleFederlänge > optimaleFederlänge)
{
A.position = ???
B.position = ???
}welche Positionen soll ich den Federenden zuweisen?
Die gesuchten Punkte müssen ja nicht zwangsweise auf der A-B-Linie liegen.
Meine Lösung klappt übrigens doch nicht. Wenn ich in der Luft bin und dann das Motorrad drehe, dann schwebt es auf einmal. Also hatte ich die Idee das es ein Geschwindigkeitsvektor gibt, welche NUR aus der Federkraft berechnet wird und dann noch ein Geschwindigkeitsvektor für die restlichen Kräfte. Diese Idee hat leider auch nicht geklappt. Weil was passiert wenn ich gegen den Boden stoße. Müssen dann beide Geschwindigkeitsvektoren reflektiert werden oder nur die ohne Federung? Egal was... es funktioniert momentan garnichts.
Ich probiere ständig rum und probiere neue Ideen aber ich denke mal, dass es noch paar Monate dauern dürfte, bis ich diese Funktionen, welche auf 1 - 2 Bildschirmseiten passt, fertig habe.
-
struct Massepunkt{ float xpos, ypos; //Position des Objekts float xacc, yacc; //beschleunigung in x und y Richtung float mass; //Masse }; void translate(Massepunkt A, Massepunkt B){ float baselength; //basislänge der Feder float strength; //stärke der Feder float currentLength = sqrt(abs((A.xpos - B.xpos) *(A.ypos - B.ypos))); if (currentLength >= baselength) return; float force = strength * (currentLength - baselength); A.xacc += force * (A.xpos - B.xpos) / baselength / A.mass; A.yacc += force * (A.ypos - B.ypos) / baselength / A.mass; B.xacc += force * (B.xpos - A.xpos) / baselength / B.mass; B.yacc += force * (B.ypos - A.ypos) / baselength / B.mass; }
Aus Beschleunigung * Zeit und der alten Position ergibt sich dann die neue Position.
-
Warum teilst du 4 mal durch baselength anstatt durch currentLength? Ich dachte durch das Teilen soll der Richtungsvektor[A-B] normiert werden? Außerdem müssen doch bei A und B die Kraftvektoren entgegengesetzt wirken. Sonste würde die Feder doch einfach nur wandern anstatt sich zusammen zu ziehen/drücken.
Was machtst du wenn currentLength >= baselength? Wodurch wird die Feder dann jemals wieder in ihre baselength zusammen gezogen?
-
Ich konnte soeben mein Feder-Dämpfungsproblem lösen. Ich habe die Begriffe Relativgeschwindigkeit und Absolutgeschwindigkeit in ein Topf geworfen. Das war mein Fehler. So sieht meine Lösung nun aus:
//Dämpfe die Federung Vektor daempfung3 = Vektor.Projektion(punkte[0].gesch, Rfeder3) - Vektor.Projektion(punkte[1].gesch, Rfeder3); punkte[0].kraft -= daempfung3 * 10.0f; punkte[1].kraft += daempfung3 * 10.0f;