Registriert: Di Mär 21, 2006 20:03 Beiträge: 21
Programmiersprache: Delphi, C++
Hi,
jeder der ein Spiel programmieren will, stößt unweigerlich auf die Animation, und auf die zwei häufigsten Vertreter hierfür. Zum einen das Frame-Based Movements, welches wohl die einfachste, jedoch auch unausgeglichenste, Variante. Zum anderen das Time-Based Movement, welches schwieriger umzusetzen ist. Wie die meisten wohl wissen, ist Time-Based Movement dem Frame-Based Movement vorzuziehen.
In einem Buch über Spieleprogrammierung stieß ich jedoch auf eine dritte Variante. Auf eine Variante, die mir persöhnlich ein wenig besser gefällt.
~ Wenn ich mit meinen Äusserungen falsch liege, könnt ihr mich natürlich gerne darauf hinweisen ~ Wenn ich mich nicht irre, haben sowohl Time-Based als auch Frame-Based Movement eine Gemeinsamkeit, die jedem OOP Programmierer ein wenig zu denken geben könnte: Sie werden jeweils nach der Logik ausgeführt. Was mich hierbei stört, ist die Tatsache, dass Logik und Rendering eigentlich nicht zusammengehören.
Dieser dritte Ansatz jedoch trennt eben diese beiden Dinge. Im Grunde werden die Logik (wo z.B. Animation und Bewegung aktualisiert werden) und das Rendering durch verschiedene Threads (oder einen Timer) getrennt. SDL bietet mit dem SDL_Timer eine plattformunabhängige und recht schnelle Lösung an. Damit klar wird, was ich meine, gebe ich ein Beispiel und zeige den Ablauf für jede Begegungsart.
Beispiel: In einem 2D Spiel soll sich der Held in 5 Sekunden 500 Pixel über den Schirm bewegen. Das Bedeutet, dass sich der Held in jeder Sekunde 100 Pixel bewegen muss. Um eine "saubere" Bewegung zu haben, müsste die FPS also bei ~100 liegen. Zur Veranschaulichung gehe ich von einem schnellen PC und einem langsamen PC aus. Der schnelle PC schafft 500 FPS und der langsame PC schafft 20 FPS. Der Schnelle PC hat also 5x mehr Frames als er im Optimalfall hat, während der langsame PC mit einer Geschwindigeit von lediglich 1/5 des Optimalfalles gestraft ist. Interessant sind vor allem Hindernisse die dem Spieler den Weg versperren oder Gegner die auf den Spieler warten ....
Frame-Based Movement: Schneller PC: Benötigte Zeit: 1 Sekunde. Reaktionszeit ist praktisch nicht vorhanden. Langsamer PC: Benötigte Zeit: 25 Sekunden. Der Spieler schläft beim Spielen fast ein.
Fame-Based Movement (Frames-Limitiert): Schneller PC: Benötigte Zeit: 5 Sekunden. Das Spiel läuft wie geplant. Langsamer PC: Benötigte Zeit: 25 Sekunden. Hat sich nichts getan ... (wie auch?!)
Die Frame-Based Movements haben beide den Nachteil, dass sie auf einem langsamen PC dem Spieler einen Vorteil einräumen (mehr Reaktionszeit).
Time-Based Movement: Schneller PC: Benötigte Zeit: 5 Sekunden. Das Spiel läuft optimal. Langsamer PC: Benötigte Zeit: 5 Sekunden. Das Spiel "ruckelt", da die Figur größe Sprünge macht.
Das Time-Based Movement umgeht die Bevorzugung der Frame-Based Varianten und bringt lieber eine neue Bevorzugung (oder auch Benachteiligung) und sogar eine Quelle für Bugs mit. Gegner oder Wände könnten so "übersprungen" werden, da sich die Spielfigur - auch intern - große Entfernungen auf einmal zurücklegt.
Logigal-Frame-Based(?) Movement: Schneller PC: Benötigte Zeit: 5 Sekunden. Wie bei Time-Based Movement auch, bleibt das Spiel optimal. Langsamer PC: Benötigte Zeit: 5 Sekunden. Auch hier "ruckelt" das Spiel, da die Figur (optisch) große Sprünge macht.
Leider kenne ich den Namen dieser Variante nicht. Daher nenne ich sie einfach mal "Logical-Frame Based" da sie in "logische" und "reale" Frames unterscheided. Diese Variante stellt sicher, dass die Logik auf allen Rechnern gleich schnell ausgeführt wird. Auf diese Weise bewegt sich die Spielfigur intern immer gleich schnell. Wie schnell die Bilder letzlich gerendert werden, ist der Logik somit egal. Die Bewegung bleibt also immer gleich schnell (sofern die Logik nicht zu lange braucht). Sämtliche Gegner, Wände etc. werden weiterhin Anstansloss abgefragt und entsprechend reagiert.
Diese These habe ich nicht von "irgendwo" her. Ich habe ein Programm auf einem alten 500 MHz PC gestarted und es funktionierte wie erwartet. Während die realen FPS bei 50~60 lagen, lagen die logischen FPS konstant 100. Auch der Versuch die FPS auf 200 anzuheben zeigte mir das gleiche Ergebnis: Reale FPS bei 50~60; Logische FPS bei 200.
Den (eher unwahrscheinlichen) Fall, dass die Logik zu lange braucht und aufgerufen wird, während sie noch aktiv ist, kann man mit einer einfachen Abfrage unterbinden.
Wie auch immer. Ich will hier niemanden belehren und das soll auch kein Tutorial sein. Ich würde dennoch gerne wissen, was ihr dazu meint.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Bei Physik und Sound ist dieses Verfahren üblich, dabei werden Physik und Sound in einen extra Thread gepackt und mit einer festen Hz versehen. So kann z.B. dann die Game Physik mit 60Hz und der Sound mit 10Hz laufen. Es ist immer noch ein Time based Vorgang, welcher aber auf eine feste Laufzeit eingestellt wird und entsprechend der Verwendung untereinander Priorisiert wird. Dinge wie Programmlogik und Physik sind in Spielen wichtiger als Sound und auch wichtiger als Rendern. Denn wenn diese nicht korrekt läuft, bringt es den anderen nichts, wenn sie korrekt laufen. ODE und Newton z.B. laufen am besten auf 60Hz dafür wurden sie Optimiert. Der Half-Life² Server läuft mit 63Hz auf Physik und Logik. Das Problem liegt in der Parallelisierung, welche auf Single Core einfach kein Sinn gemacht hat.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Di Okt 13, 2009 17:25 Beiträge: 365
Programmiersprache: C++
Ich verstehe den Sinn von dieser "Logigal-Frame-Based Movement"-Methode noch nicht ganz. Auch die These, beim Timebased Movement würden auf langsamen PCs Fehler entstehen, kann ich nicht unterstützen. Denn dass das bei vielen Games leider so ist, liegt nicht am Timebased Movement, sondern an der Implementation der Kollisionsabfrage und solchen Dingen. Man kann ja auch bei jedem Frame den kompletten zurückgelegten Weg eines Objektesseit dem letzten Frame auf Kollision prüfen. Die einzige Schwäche des Timebased Movement ist für mich eigentlich, dass man die Framerate konstant halten muss, damit die Bewegungen nicht ungleichmäßig wirken. Doch das kann man ja einigermaßen gut mit Glätten der Framezeiten usw. umgehen.
Zuletzt geändert von mrtrain am Mi Aug 31, 2011 19:19, insgesamt 1-mal geändert.
Der Grund dafür ist, die Threads bekommen ihre Scheibschen ab und per priority kann man sogar sagen was wichtiger ist, z.B. ist logic wichtiger als audio oder physic und physic oft auch als audio. SwapBuffer wartet bis das rendern durch ist und solange liegt der prozess im tiefschlaf(blocking), wo andere Threads ihr ding machen können. Diese Art hat sich eigentlich erst mit den Mehrkern CPUs bei PC und Consolen durch gesetzt. Bei der PS3 und XBox360 würde man ohne dieses nicht mal ein iPhone schlagen können. Das an sich hat noch nicht viel mit dem zu tun was hier angesprochen wurde, darum mal etwas weiter denken.
Wenn man nun sagt, dass das updaten von den Audio Buffer nur alle 500ms getan werden muss aber mindestens eine Abtastgenauigkeit von 100ms für sound events zur verfügung stehen muss, dann würde man den kleinsten sleep nehmen und durch 2 teilen(Shannon Abtasttheorem).
//do some work like check current audio sample amplitude
HighPrecisionSleep(currenttime+50);//100/2=50 }
Das Soundsystem würde also mit 20Hz laufen, egal wo und sobald es zu wenig Ressourcen hat, geht es den bach runter aber den kann man durch einige tricks dann noch entgegen wirken aber am ende kommt dann die Prio der Threads zum tragen. Grafik würde ich z.B. mit 120Hz(/2=60Hz mehr kann das Auge eh nicht mehr unterscheiden) und Logik mit 120Hz(/2=60Hz reaktion auf Input muss mindestems den Visuellen und wenn möglich Audio Zykluszeit passieren) angeben, wärend Physik den ganzen restlichen Kuchen bekommt(mehr ist bei physik immer besser) und mindestens bei 120Hz(/2=60Hz wieder das böse Auge und Gehirn) und Audio mit z.B. 20Hz(/2=10Hz) laufen muss.
Sascha hat mich letzte Woche z.B. aufgeklärt, dass die Physik von Simulationen meist mit 400Hz und aufwärts läuft, wärend die Grafik mit nur 60Hz läuft.
Der große Unterschied zu Timebased Movement und so weiter ist, dass man anhand der letzten Zeiten eine Laufzeit vorraus sagt und diese ist natürlich oft völlig schwachsinnig und kann bei allen Bereichen schnell auf fliegen. Also legt man besser eine Laufzeit fest und optimiert auf diese, wenn noch ressourcen übrig sind, dann kann man sie in einigen fällen aufbrauchen aber wenn zu wenig da sind werden die nieder priorisierten threads einfach den höheren platz machen, damit es immer noch so aussieht als ob alles richtig ist. Dank Shannon sein Abtasttheorem haben wir auch die doppelte Frequenz gewählt und somit kann man schon die Ressourcen gut verteilen und bei Engpässen vorsorgen(denn man weiß ja schon vorher bescheit) z.B. Audio Qualität senken, Physic prezision reduzieren oder ein paar Objekte mit niederen LOD rendern.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Di Okt 13, 2009 17:25 Beiträge: 365
Programmiersprache: C++
Naja, dass es Sinn macht Physik, Sound und so weiter in jeweils eigene Threads auszulagern, ist mir schon klar. Aber die Physik muss man ja nicht öfter ausführen als das Rendern (vorausgesetzt, man hat vernünftige Phyiskroutinen) und daher würde man in diesem Fall wieder die Spiellogik abhängig von der Framezeit weiter bewegen. Also Timebased Movement. Meinetwegen kann man es auch "Logical-Frame-Based Movement" oder so nennen, aber der einzige Unterschied wäre dann, das mehrere Threads genutzt werden? So habe ich eure Beiträge jedenfalls verstanden. (nehmt's mir nicht übel wenn's falsch ist )
@60 Hz: Ich würde das Programm nicht darauf festlegen. Ich habe z.B. einen LCD mit 75 Hz und wenn ich darauf ein Spiel spiele, dass auf 60 fps begrenzt, habe ich entweder Tearing ohne oder Mikroruckler mit V-Sync. Am besten wäre es, wenn man das Limit im Spiel einstellen kann (wenigstens in einer ini-Datei). Gibt ja vereinzelt auch noch Leute mit Röhren oder sonstigen Exoten.
Zuletzt geändert von mrtrain am Mi Aug 31, 2011 19:20, insgesamt 1-mal geändert.
Registriert: Mo Sep 23, 2002 19:27 Beiträge: 5812
Programmiersprache: C++
Doch, es macht sehr wohl Sinn die Physik mit einer höheren Frequenz laufen zu lassen als z.B. Spiellogik oder die Bildrate. Die meisten halbwegs ernsthaften Rennsimulationen (und selbst einige Rennspiele) machen das, rFactor z.b. berechnet die Physik mit 400Hz, bei Live for Speed wird für die Radrotation (und alles damit verbundene) sogar 2000Hz genommen (100 Hz für den Rest). Hier muss man weiter denken als an dass was man sieht, denn große Schritte können zu größeren Fehlern führen die sich dann auf weitere Systeme ausbreiten, und wenn diese Systeme dann auch so grob berechnet werden, dann setzt sich dieser große Fehler fort und wird immer größer. Grade bei einer Rennsimulation ist es daher wichtig das v.a. Reifenphysik (Simulationen berechnen ja hier extrem viel) und auch Dämpfer mit hoher Frequenz berechnet werden.
Ich mach dass in vielen meiner Physikdemos auch so, nennt sich dann akkumulatives Time-Slicing, dort werden dann ganz viele kleine Simulationsschritte in einem Frame gemacht um die Genauigkeit der Physiksimulation zu erhöhen.
Statt also z.B. pro Frame einmal folgendes zu machen :
Code:
NewtonUpdate(FrameZeit);
macht man dies :
Code:
while AccTimeSlice > 10 do begin NewtonUpdate(NewtonWorld, (10 / 1000)); AccTimeSlice := AccTimeSlice - 10; end;
Registriert: Di Okt 13, 2009 17:25 Beiträge: 365
Programmiersprache: C++
Na gut... nach einiger Überlegung muss ich sagen, bei Rennspielen, wo viele Reibungskräfte usw. im Spiel sind, macht es evtl. durchaus Sinn, die Physik schneller laufen zu lassen. Ich wüsste jedenfalls keinen konkreten Ansatz, wie man die Kräfte sonst unter Berücksichtigung der zurückgelegten Strecke berechnen soll. Aber in vielen Spielen kommt sowas gar nicht vor. Da würde es reichen die Physik, die sich auf "einfache" Dinge wie Kollision beschränkt einmal pro Renderframe auszuführen.
Zuletzt geändert von mrtrain am Mi Aug 31, 2011 19:20, insgesamt 1-mal geändert.
Aber in vielen Spielen kommt sowas gar nicht vor. Da würde es reichen die Physik, die sich auf "einfache" Dinge wie Kollision beschränkt einmal pro Renderframe auszuführen.
Nein. Die Physik sollte immer gleichmäßig laufen. Bei 5fps ruckelt dir ne kleine Kugel sonst durch irgendwas durch.
_________________ Denn wer nur schweigt, weil er Konflikte scheut, der macht Sachen, die er hinterher bereut. Und das ist verkehrt, denn es ist nicht so schwer, jeden Tag zu tun als ob's der letzte wär’. Und du schaust mich an und fragst ob ich das kann. Und ich denk, ich werd' mich ändern irgendwann. _________________Farin Urlaub - Bewegungslos
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Sonst verfehlen bei Johnny, mit seinem 266MHz Rechner, die Abfangraketen irgendwann die Flugzeuge, wenn sie aufeinander zufliegen
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Okt 13, 2009 17:25 Beiträge: 365
Programmiersprache: C++
Ziz hat geschrieben:
Die Physik sollte immer gleichmäßig laufen. Bei 5fps ruckelt dir ne kleine Kugel sonst durch irgendwas durch.
So ein Quatsch! Wo ist das Problem, wenn man einfach den gesamten Weg, den deine Kugel zwischen den beiden Frames zurückgelegt hat, verfolgt und prüft, ob dort irgendwo ein Kollision vorlag? Beispiel.
Zuletzt geändert von mrtrain am Mi Aug 31, 2011 19:21, insgesamt 1-mal geändert.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Dann hast du entweder ein Problem mit nicht-statischen Objekten auf dem Weg oder hast den Ansatz, den Sascha schon vorgeschlagen hat.
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Richtig. Auch bei zwei bewegten Objekten mit konstanter Geschwindigkeit kann man noch den Schnittpunkt berechnen, aber was ist mit vielen Objekten? Oder Objekten mit einer beschleunigten Bewegung oder gar einer nicht vorhersehbaren Beschleunigung? Außerdem kann ein Schnittpunkt zweier Objekte wieder von einer vorherigen in diesem Frame stattgefundenen Kollision abhängen. In dem Moment wird das berechnen alle 1/60 Sekunde einfacher (relativ gesehen, immer noch kompliziertes Zeug) und auch schneller.
Da, Mr. "So ein Quatsch", liegt das "Problem".
_________________ Denn wer nur schweigt, weil er Konflikte scheut, der macht Sachen, die er hinterher bereut. Und das ist verkehrt, denn es ist nicht so schwer, jeden Tag zu tun als ob's der letzte wär’. Und du schaust mich an und fragst ob ich das kann. Und ich denk, ich werd' mich ändern irgendwann. _________________Farin Urlaub - Bewegungslos
Das ist vor allem beim Spiel im Netzwerk wichtig. Die Ergebnisse müssen reproduzierbar sein, den alle Rechner berechnen die Physik unabhängig von einander uns MÜSSEN jeweils zum gleichen Ergebnis kommen. Hat man eine wechselnde Framerate für die Physik sieht das Ergebnis zwar in den meisten Fällen noch glaubwürdig aus, aber die Ergebnisse unterscheiden sich immer leicht. Über einen längeren Zeitraum werden aus den leicht unterschiedlichen Ergebnisse riesige Differenzen.
Registriert: Di Mär 21, 2006 20:03 Beiträge: 21
Programmiersprache: Delphi, C++
Ich muss ehrlich gestehen, dass in meinen Spielen die Physik so einfach gehalten war, das ich sie einfach mit bei "Logik" reinpacken konnte. Die Einwände von mrtrain kann ich auch nicht wirklich nachvollziehen. Es ist wesentlich einfacher und meiner bescheidenen Meinung nach auch wesentlich genauer die Logik und die Physik in einem festen Intervall ablaufen zu lassen.
Aber eine Anmerkung habe ich dann schon noch.
Coolcat hat geschrieben:
Über einen längeren Zeitraum werden aus den leicht unterschiedlichen Ergebnisse riesige Differenzen.
Das dürfte wohl nur halb wahr sein. Denn der Server sollte die Physik und Logik ebenfalls berechnen und - oh Wunder - in festen Zeitintervallen mit den Clients abgleichen. Dieser Abgleich sorgt letztendlich für Laggs in Spielen. Oder irre ich mich hier wieder?
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Nein, die Lags entstehen durch andere Dinge. Bei einigen Spielen würde ein Komplettabgleich einiges an Bandbreite beanspruchen und da soetwas durch konstante Intervalle und gleiche Einstellungen der FPU vermeidbar ist…
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Mitglieder in diesem Forum: Bing [Bot] und 5 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.