Seite 1 von 1

DeltaTime

Verfasst: 28.08.2015, 16:31
von simsim
Hallo,
ich arbeite gerade daran einen "Mainloop" für mein Spiel einzurichten(Java).
Dies ist mein Konzept, um die momentane Framerate zu errechnen:

Code: Alles auswählen

	public void run() {
		double delta_time = System.nanoTime();
		while(run){
			double now = System.nanoTime();
			System.out.print("FPS:"+1/(delta_time/1000000000)+"\n");
			delta_time = System.nanoTime()-now;
		}
		
	}
Meine Denkweise:
1.nanoTime() gibt die Systemzeit in nanosekunden zurück, um diese Zeit nun in Sekunden umzurechnen, teile ich durch 10 hoch 9(1000000000).
2. [Ein Bsp:ein Frame dauert 1/60 s -> Framerate = 60 FPS = (1/(1/60)) ]
-> also allgemein : Framerate = 1/[Dauer eines Frames in Sekunden]

Nun meine Fragen:
1. Gibt mir dieses Programm(das diese Methode laufen lässt) nun wirklich in jedem Schleifendurchlauf die Framerate aus(die der vorherige Frame benötigt hätte), oder bin ich einem Denkfehler aufgelaufen?(wenn ja, welchen?)
2. Kann ich nun mit dieser "DeltaZeit" die Bewegung eines Gegners so skallieren, dass er sich bei 1000FPS genauso schnell bewegt wie bei 100 FPS? (Beispiel-Werte)

Zwar habe ich schon Beispiele gesehen, die einen komplexen Timing-Mechanismus eingebaut haben, aber ich wollte mir selber ein Prinzip herleiten.(Ich will nicht nur copy-paste benutzen :D)

Re: DeltaTime

Verfasst: 28.08.2015, 16:39
von Spiele Programmierer
Zu beiden Fragen: Ja, das geht.
Das Skalieren der Bewegungsgeschwindigkeit hat allerdings auch ein paar Nachteile.
Zum einen sind einige Operationen nicht skalierbar(man denke zum Beispiel an eine Bewegung mit Reibung oder Kollisionserkennung) und zum anderen ist das Spiel nicht mehr deterministisch.

Re: DeltaTime

Verfasst: 28.08.2015, 20:18
von Sternmull
Ist schon ganz gut so. Allerdings hätte ich schon ein paar Kritikpunkte:
  • delta_time initialisierst du anfangs auf einen Zeitpunkt, und verwendest es anschließend als Zeit-Differenz. Die Initialisierung ist so nicht sinnvoll.
  • Du misst die Zeit die zwischen dem ersten und letzten nanoTime()-Aufrufen des Schleifenkörpers vergeht. Allerdings zählst du Zeit die vom Ende bis zum erneuten Start der Schleife vergeht nicht mit. Das wird praktisch natürlich nicht wirklich spürbar sein, ist aber nicht ganz sauber.
Das mit dem Skalieren macht man eigentlich nicht. Das liegt daran das man damit die Simulation des Spielgeschehens innerhalb eines Zeitabschnitts vollkommen anders aussehen kann wenn die Framerate unterschiedlich ist. Wie Spiele Programmierer schon erwähnt hat ist das besonders kritisch für so gravierende Effekte wie Kollisionsbehandlung. Wenn das Spiel bei einem mit 1000 FPS läuft dann macht er auch 1000 Kollisionstests in dieser Sekunde und ist somit recht gründlich. Bei einem anderen springt in dieser Sekunde vielleicht grad der Virenscanner an und er hat nur 2 FPS... und somit nur zwei Kollisionstests in dieser Zeit... man kann sich denken was das für ein schnelles Spiel wie einen Egoshooter bedeutet. Spätestes für Multiplayer-Spiele funktioniert das mit der Skalierung richtig schlecht weil die Simulationen die auf den Clients laufen sich dann sehr schnell von der auf dem Server unterscheiden... und somit die Resynchronisierung mit dem Server-Zustand regelmäßig zu sichtbaren Sprüngen der Objekte führen wird.
Das gängige Gegenmittel: Simulation in festen Zeitschritten ausführen, egal wie die Framerate ist. Also z.B. alle 1/50 Sekunden eine Iteration der Simulation berechnen, und zwar so lange bis die Simulation zum aktuellen Zeitpunkt aufgeholt hat. Für Clients die das Geschehen mit höchstens 50 FPS anzeigen ist es damit gegessen. Für die jenigen die schneller sind müssen aber auch die Zustände zwischen den Simulations-Zeitpunkten simuliert werden (wenn mit 500 FPS dargestellt wird, würde die Simulation ja sonst trotzdem mit 50 Schritten vor sich hindümpeln und somit nur alle 10 Frames mal was anderes angezeigt werden). Deshalb wird der Simulations-Zustand zwischen dem aktuellen und dem vorhergehenden Simulationszustand interpoliert. Damit bekommt der 500 FPS Client zumindest weiche Übergänge zwischen den Zuständen zu sehen, womit er gut bedient ist. Der Nachteil ist allerdings das man für die Interpolation ja zwei Zustände braucht, und somit die Dauer einer Simulations-Iteration als Latenz bekommt.

Re: DeltaTime

Verfasst: 13.09.2015, 13:56
von RedGuy
Hallo zusammen !!

Hinzufügen möchte ich den schlimmen Fall, dass wenn die Programmier - API zu ungenaue timestamps (also Zeitpunkte) liefert - zum Beispiel nur Mikrosekunden. Dann ist ploetzlich dt ist gleich 0.

Man hat dann für die Objekt-Transformation für den aktuellen Zustand ein ungültiges Ergebnis.

Gelöst habe ich dieses Problem schon einmal damit, dass ich in der Hauptschleife die Objekt-Transformation so lange asynchron über mehrere Zyklen abwarte, bis dann das dt größer 0 wird :mrgreen: ;) !

Das empfinde ich heute allerdings als einen Hack. Für professionelle Unterfangen sollte man stets einen Zugang zu einer entsprechend genauen clock haben !

Gruss
RedGuy