Problem mit Spielbeschleunigung

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Dummie
Beiträge: 97
Registriert: 09.02.2004, 20:45

Problem mit Spielbeschleunigung

Beitrag von Dummie »

Hey,

ich programmiere gerade aus Spaß mit SFML ein kleines Panzerspiel. Die Panzer werden über Neuronale Netze gesteuert.

Damit die Netze schneller lernen, will ich den Spielablauf auch mal beschleunigen, um die Veränderungen schneller einschätzen zu können. Alle Berechnungen erfolgen in Abhängigkeit der Framezeit. Um das Spiel zu beschleunigen multipliziere ich also einfach die Framezeit mit einem Beschleunigungsfaktor:

Code: Alles auswählen

const double ElapsedTime = myApp.GetFrameTime() * myGameSpeed;

Update(ElapsedTime);
Draw(ElapsedTime);
Wenn ich das Spiel aber beschleunige, so kommt es mir vor als würden die Berechnungen nicht mehr stimmen. Das heißt die gleiche Situation hat mit unterschiedlichen Faktoren evtl. auch unterschiedliche Ergebnisse. Ich bin mir da allerdings nicht sicher, ob das wirklich so ist. Es kommt mir einfach so vor, da die Ergebnisse plötzlich eine Veränderung erfahren. So sinkt z.B. bei höheren Beschleunigungsfaktoren plözulich die Trefferquote meiner Panzer drastisch.

Woran kann das wohl liegen und wie kann ich es beheben? Ich hab mir schon gedacht, dass evtl. die Auflösung von SFML nicht genau genug ist und es zu Abweichungen kommt. Kann das sein?

Bin für Ideen, Anregungen, Vorschläge und Tipps sehr dankbar!

Viele Grüße
Patrick
Benutzeravatar
Artificial Mind
Establishment
Beiträge: 802
Registriert: 17.12.2007, 17:51
Wohnort: Aachen

Re: Problem mit Spielbeschleunigung

Beitrag von Artificial Mind »

Dir reicht es wahrscheinlich, wenn die Logik schneller läuft, also Update.
Wenn dein PC schnell genug ist, würde ich empfehlen, die Logik einfach häufiger aufzurufen (und zwar immer mit dem gleichen Timestep).
CrystalCoder
Beiträge: 54
Registriert: 03.03.2002, 17:51
Kontaktdaten:

Re: Problem mit Spielbeschleunigung

Beitrag von CrystalCoder »

Ich vermute eher nicht, dass es an SFML liegt.
Es könnte darauf ankommen, wie konstant die Framezeiten sind. Bei manchen Berechnungen kann es Probleme geben, wenn drastische Wechsel von Framezeiten stattfinden (z.B. Physikberechnungen, Sequenzabläufe).
Es kommt auch drauf an, wie die Framezeit berechnet wird. Sollte es sich um die Zeit des aktuellen Frames handeln, ist es möglich, dass die Werte sehr stark variieren, da die Messzeit viel zu kurz ist um aussagekräftige Ergebnisse zu bringen. Außerdem ist die Hauptarbeit der Berechnungen dann nicht mit in dieser Zeit mitgerechnet.
Um das Problem zu minimieren, könnte man die Zeit des letzten Frames hernehmen, wo aber das Problem bestehen bleibt, dass die Framezeiten nicht Konstant sind.
Um das Problem zu minimieren, könnte man den Framedurchschnitt, der letzten N Frames berechnen (wobei je mehr Frames berücksichtigt werden, desto konstanter die Framezeiten, aber dafür desto träger das System).

Ein ganz anderes Problem könnte folgendes sein:
Die Framezeiten werden hier offenbar mit einem double gespeichert, was an sich nicht schlimm ist, es jedoch sein kann, wenn innerhalb von Draw/Update mit floats gearbeitet wird. Damit verliert man an genauigkeit und je höher "myGameSpeed" wird, umso mehr Genauigkeit geht verloren. Es kommt auch darauf an, in welcher Einheit die Zeit hier gespeichert wird (je kleiner die Einheit umso größer der Double-Wert und umso kleiner die Präzision, wenn dieser für eine Berechnung mit einem float hergenommen wird)
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Problem mit Spielbeschleunigung

Beitrag von dot »

Guter Artikel der dich interessieren sollte: http://gafferongames.com/game-physics/f ... -timestep/ ;)
Dummie
Beiträge: 97
Registriert: 09.02.2004, 20:45

Re: Problem mit Spielbeschleunigung

Beitrag von Dummie »

Hey,

vielen Dank für die schnellen Antworten :)

App.GetFrameTime() liefert ein float zurück. Ich selber hatte vorher auch ausschließlich mit float gerechnet, aber dann auf double umgestellt, was leider keinen Erfolg brachte. Die Ideen nur Update mit konstanten Werten zu speisen hab ich eben probiert. Das Problem ist absolut identisch.

Code: Alles auswählen

if (myApp.GetInput().IsKeyDown(sf::Key::Code::Return)) 
{
	for (int i = 0; i < 100; ++i)
	{
		Update(0.1); // bei größeren Werten wird es immer schlechter
	}
}	
else
{
	Update(ElapsedTime);
	Draw(ElapsedTime);
}
Je schneller es werden soll, umso geringer wird die Trefferquote meiner Panzer...

Woran könnte das denn noch liegen? Damit mein Neuronales Netz keinen Blödsinn lernt, müssen die Berechnungen natürlich auch bei beschleunigtem Ablauf passen.
Zuletzt geändert von Dummie am 10.06.2012, 22:06, insgesamt 2-mal geändert.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Problem mit Spielbeschleunigung

Beitrag von dot »

Du sollst ja auch eben genau nicht den Timestep größer machen, denn genau das verursacht ja dein Problem. Stattdessen verwendest du einen konstanten Timestep. Unterteil eben die variable Frametime in mehrere Timesteps, wobei die Simulation in jedem Step um die selbe konstate Zeit weiterbewegt wird.
Dummie
Beiträge: 97
Registriert: 09.02.2004, 20:45

Re: Problem mit Spielbeschleunigung

Beitrag von Dummie »

Ich hab mal noch ein Experiment gemacht, um das zu bestätigen. Wenn ich die Anwendung mit srand(100) starte, also die Bedingungen konstant sind, dann gibt es auch bei normaler Spielgeschwindigkeiten Abweichungen.

Dass das so extreme Auswirkungen hat, hätte ich nicht gedacht. :o

Wie meinst du das mit unterteilen? Da grübel ich gerade und komme nicht dahinter. Ich muss dazusagen, dass ich eher selten Spiele programmiere.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Problem mit Spielbeschleunigung

Beitrag von dot »

In dem vorhin von mir verlinkten Artikel ist das alles genaustens erklärt ("Free the physics")... ;)
Dummie
Beiträge: 97
Registriert: 09.02.2004, 20:45

Re: Problem mit Spielbeschleunigung

Beitrag von Dummie »

Hey,

ich habe mir das mal angesehen. Die Frage ist allerdings, wie ich das jetzt einbaue?

Das Beispiel bezieht sich ja auf ein einzelnes Objekt, das auf der X-Achse bewegt werden soll. Ich habe allerdings ganz viele mit Bewegungen auf beiden Achsen.

Schön wäre es ja, wenn ich möglichst wenig Code ändern müsste.
CrystalCoder
Beiträge: 54
Registriert: 03.03.2002, 17:51
Kontaktdaten:

Re: Problem mit Spielbeschleunigung

Beitrag von CrystalCoder »

In dem Artikel geht es nicht um ein bestimmtes Objekt. Es wird berechnet, wie viele Updates mit einer bestimmten (konstanten) Schrittweite in der akkumulierten Zeit vollständig ausgeführt werden können (quasi bis der Zeit-Akku nicht mehr genug Zeit hat, um ein weiteres Simulations-Update komplett auszuführen) und so oft wird dann in der Schleife geupdated - kann abhängig von der Update-Frequenz auch mal 0 sein (z.B. 60FPS und Updatefrequenz von 25Hz)
Daraus folgt, dass man in unterschiedlichen Frames unterschiedlich viele Simulations-Updates hat - je nach Dauer der Frames und/oder Abweichung der Updatefrequenz für die Simulation gegenüber der Updatefrequenz der restlichen Anwendung (z.B. FPS).
Auf diese Weise kann man bspw. bei einer FPS von 60 eine Updatefrequenz von 100 Hz, 50Hz oder was auch immer erreichen.
Dieses "mal mehr, mal weniger" resultiert aber in Time-Aliasing (also u.U. deutliche Sprünge, die sich wie Ruckler "anfühlen" können).
Um das zu vermeiden, wird ein Wert zwischen 0 und 1 berechnet, der als Interpolationswert gilt, für alle Berechnungen zwischen Simulations-Update N in Frame n und Simulations-Update M in Frame m, mit M-N >= 0 (ganzzahlig) und m-n = 1. (kann sein, dass es nicht ganz stimmt, ich hab den Teil nur überflogen, mir gehts jetzt eher um das Prinzip für den Interpolationsfaktor - falls die Details nicht ganz richtig sind, könnt ihr mich gerne korrigieren).
Der berechnete Interpolationsfaktor gilt nun für alle internen Berechnungen der Simulation. Man nimmt quasi die Simulation für N und die Simulation für M (von jeder einzelnen Berechnung) her und Interpoliert linear dazwischen (LERP), indem man den vorher berechneten Interpolationswert benutzt (welcher ja nur einmal berechnet werden muss). Wie man jetzt im einzelnen interpoliert, hängt von deinen Daten ab (wobei es für gewisse Datenstrukturen keine so triviale Aufgabe ist - Rotationsmatrizen z.B.)
Dummie
Beiträge: 97
Registriert: 09.02.2004, 20:45

Re: Problem mit Spielbeschleunigung

Beitrag von Dummie »

Danke für deine ausführliche Erklärung :)

Ich befinde mich glücklicherweise nur im zweidimensionalen Raum und nutze ja eh SFML.

Aktuell multipliziere ich bei allen Berechnungen einfach die Framezeit mit rein. Durch die Interpolation muss ich da wohl jetzt ziemlich umdenken.

Mir erschließt sich der gesamte Sinn und die Notwendigkeit von Inteprolation, usw. aber wie ich das alles im gesamten einbaue ist mir noch immer nicht klar.

Ich habe z.B. ein Sprite mit den Koordinaten X und Y. Als Beispiel wird bei jedem Frame folgendes ausgeführt:

Code: Alles auswählen

Sprite.X += 50 * Frametime;
Sprite.Y += 50 * Frametime;
Jetzt gilt es das im Link angegebene Konzept umzusetzen. Reicht es wenn ich ein State-Objekt einmalig berechnen lasse und es anstatt der Framezeit überall durchreiche? Auch wird ja nur die X-Koordinate berührt. Muss ich das State-Objekt für Y-Koordinaten irgendwie erweitern. Muss jedes Sprite ein eigenes State-Objekt haben? Es wird zwar in dem Artikel erklärt, wie man das alles berechnet, aber nicht was ich damit jetzt anfangen soll.

Ich steh da echt sowas auf dem Schlauch und möchte nicht einfach auf gut Glück alles umschreiben. Und da ich auch kein Mathegenie bin komm ich mit Logik auch nicht mehr sonderlich weiter. So hilflos war ich schon lange nicht mehr. :lol:
Antworten