Delta Timing - denkblockade im Ansatz

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

 

PhillipK

Betreff: Delta Timing - denkblockade im Ansatz

BeitragDi, Aug 14, 2012 12:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Heyho Community Smile

Mir schwebt seit längerem im kopf herum, das ich gerne ein paar Libs für den Privaten gebrauch erstellen würde, die vielerlei fehler beheben sollen.

Hierzu zählen zb Gui libs, die das ständige bugsuchen in den "fix geschriebenen guis" beheben, wie auch ein ImageFont, welches nur mit TImageFont.DrawText(str:String, x:int, y:int) auskommt, als auch Timing sachen.

Mein größtes problem ist immer, das ich meine Tests und spiele starr auf meinen PC anpasse - nach dem motto: "Wenns bei mir läuft, läufts bei jedem".
Tja, falsch gedacht. Früher wär das durchaus noch in ordnung gewesen, doch mittlerweile verfüge ich über einen Leistungsstarken Rechner, der so ziemlich jedes Modernere spiel in höchsten details und auflösung ohne murren packt.

Zeit für mich, mal ein wenig Frameunabhängiges Programmieren zu lernen Smile

Ich errinnere mich noch grob, wie das mit Leadwerks war - dort gabs eine schicke "TimeDelta" funktion, die einen double ausgespuckt hat, um bewegungen etc sanft zu timen.

Sowas will ich auch, undzwar ohne Leadwerks! Smile

Meine googlesuchen verliefen sich im sand, da ich nur auf C++ foren gestoßen bin, wo auf WinAPI methoden zugegriffen wurde.

Mein ansatz soll allerdings mit einer eingestellten Hertz zahl sowie dem Blitzmax internen Millisecs() auskommen.

Nun, der erste ansatz war schnell geschrieben und lieferte auch gute werte. Aber irgendwie habe ich mir das schwieriger vorgestellt und frage mich deshalb, ob ich wirklich das richtige berechne oder nur "durch zufall" halbwegs sanfte ergebnisse kriege.

Als test diehnt mir Bruceys' box2d wrapper, welcher mir in kombination mit einem Timer und einem Test-Delay immer die gleichen geschwindigkeiten behalten soll.

Hier mal das kleine type:
BlitzMax: [AUSKLAPPEN]

Type TTimeDelta
Global currentMS:Int = MilliSecs()
Global _hertz:Double = Double(60) 'initialwert

Global delta:Double = Double(1) 'initialwert


Const __second:Double = Double(1000) 'speedbonus: sonst würde ich jedesmal Double(1000) verrechnen *hust*
Function Update:Double()
Local oldMS:Int = currentMS 'alten wert einpacken

currentMS = MilliSecs() 'und neuen wert einlesen.

'hier nun die rechnung:
delta = ((currentMS - oldMS) * (_hertz / __second))
Print("Delta: "+delta)
'Bei einer soll-hertzzahl von 60 und einem timer der mit 20 hz läuft erhalte ich den wert 3.0 -> ist meiner vorstellung nach korrekt. Liege ich hier richtig?
End Function
Function SetHertz(hz:Double)
_hertz = hz
End Function
End Type


Wars das wirklich? Irgendwie habe ich das gefühl, das mir noch was entscheidendes fehlt Smile

Den b2world.doStep aufruf mache ich dann übrigends mit folgendem wert:
BlitzMax: [AUSKLAPPEN]
TTimeDelta.delta / TTimeDelta._hertz

Gewünscht ist hier ein timestep.

Also, zerreißt mich! Ich bin einfach zu blöde grade Very Happy

biggicekey

BeitragDi, Aug 14, 2012 18:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Ist B3D aber gilt trotzdem: https://www.blitzforum.de/foru...abh%E4ngig
#45 www.icekeyunlimited.de www.starcrusade.de
Gewinner BCC#17 !!! mit dotkiller
Nothing more to register - you've cleaned us out![/size]

ZEVS

BeitragDi, Aug 14, 2012 19:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
TTimeDelta.delta / TTimeDelta._hertz

Sinnlos (?). TTimeDelta.delta enthält den perfekten Faktor für alle Berechnungen.
Zitat:
'Bei einer soll-hertzzahl von 60 und einem timer der mit 20 hz läuft erhalte ich den wert 3.0 -> ist meiner vorstellung nach korrekt. Liege ich hier richtig?

Ja. Wenn z.B. nur 20 statt 60 Schritte pro Sekunde durchgeführt werden, muss man mit jedem Schritt dreimal so schnell laufen, um nicht hinterher zu hinken.
Zitat:
Wars das wirklich? Irgendwie habe ich das gefühl, das mir noch was entscheidendes fehlt

Wenn du dir die Mühe machst, das Ganze als Modul zu kapseln, sind natürlich Erweiterungen denkbar. Es wäre z.B. im Debug-Modus schön, wenn die FPS gezählt würden (und ggf. auch gleich angezeigt via FlipHook). Außerdem kann die jetzige Version nicht mit Zeitsprüngen (Fenster verschieben u.ä.) umgehen (Delta bekommt absurd hohe Werte). Wenn man eine Pause-Möglichkeit ins Spiel einbauen möchte, muss man dennoch die Funktion oft aufrufen, da sonst o.g. Problem auftritt (das Gegenteil von resourcensparend). Allgemein werden die Felder zu Programmstart initiiert und nicht auf Funktionsaufruf. Das führt z.B. zu absurden Werten nach einem langen Laden.
Fazit: Delta nach oben hin eingrenzen bzw. bei zu hohen Unterschieden einfach auf 1 zurücksetzen. Ferner eine Pause+Resume und Init/Reset-Funktion einbauen. FPS wäre schön (?Debug).

ZEVS
 

PhillipK

BeitragDo, Aug 16, 2012 16:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Im diesem ersten ansatz ging es auch nur darum, einen Delta wert zu ermitteln Very Happy

Zumal ich mir nicht sicher war, was delta überhaupt genau darstellt. Jedesmal wenn ich beim googlen auf eine erklärung getroffen bin, hat mein hirn nach kurzer zeit gesagt "zuviel fachblabla" und abgeschaltet ^^

Das TTimeDelta.delta / TTimeDelta._hertz sinnlos ist, mag sein.
Aber diese berechnung hat sich im ersten test als "sauber" herrausgestellt, da box2d.doStep() einen wert einen fixen timestep von
Code: [AUSKLAPPEN]
1.0 / 60.0

erwartet hatte.
Da ich die 60 als wunsch-hertz interpretiert habe (einzustellen in TTimeDelta._hertz) und TTimeDelta.delta einen timefaktor enthält (idealerweise 1.0), gehe ich davon aus, so meinen wunsch-timestep zu berechnen Smile

Natürlich bedarf es einer initialisierungsfunktion, sowie pause/Resume und fehlerprüfung - das habe ich beim "schnellen hinschreiben" garnicht bedacht.

Wenn das ganze trotzdem soweit richtig berechnet ist, werde ich mich bald dransetzen und das ganze weiter ausbauen. Allerdings bin ich schüchtern, was das hochladen von eigenem code als modul angeht *g*

Trotzdem, danke fürs zerpflücken, ZEVS Smile

ps: FPS zahl habe ich bereits versucht, zu bestimmen.
Allerdings lief es nun darauf hinaus, das ich das ganze per zähler und millisecs()+1000 timesteps realisiert habe. Diese werte weichen allerdings leicht von der wirklichkeit ab.
In der theorie müsste man aus Delta und _hertz die momentane fps berechnen können, aber dafür war ich bisher zu blöde Sad

Deshalb ist das ganze nun lediglich (vorerst!) auf diese spielerei beschränkt:
BlitzMax: [AUSKLAPPEN]
		__currUPS:+1
If __upsTiming < currentMS - 1000 Then
UPS = __currUPS
__upsTiming = currentMS
__currUPS = 0
End If

(eingefügt in TTimeDelta.update()!)

Tornado11

BeitragFr, Aug 17, 2012 11:40
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:

Zumal ich mir nicht sicher war, was delta überhaupt genau darstellt. Jedesmal wenn ich beim googlen auf eine erklärung getroffen bin, hat mein hirn nach kurzer zeit gesagt "zuviel fachblabla" und abgeschaltet ^^


Delta ist ein griechisches symbol und mit dem wird meistens in der Mathematik und Physik eine Differenz von zwei Variablen beschrieben.
In deinem Falle handelt es sich um eine Zeitdifferenz.

Ich würde deine delta variable anders benennen, da es sich bei deiner delta Variable nicht um die rohe Zeitdifferenz handelt, sondern um eine modifizierte Differenz (also das ((_hertz / __second))). Aber das ist nur meine persönliche Meinung wegen der Lesbarkeit.

Zitat:
In der theorie müsste man aus Delta und _hertz die momentane fps berechnen können, aber dafür war ich bisher zu blöde

Nein, man braucht nur die Zeitdifferenz Delta t
Code: [AUSKLAPPEN]
 delta = (currentMS - oldMS)

und mit
Code: [AUSKLAPPEN]
 T = 1/f ;T = Periode oder delta t, f für frequenz

Die momentane Frequenz (fps) ist also 1/delta mit der die Funktion "Update" aufgerufen wird. Für kleine delta t werte wird aber die frequenz f ungenau, deshalb ist es schon besser die Anzahl Frames (Schleifendurchläufe) pro Sekunde zu zählen.

ZEVS

BeitragFr, Aug 17, 2012 18:02
Antworten mit Zitat
Benutzer-Profile anzeigen
@Tornado11: Du hast zweifellos Recht, was Δ angeht. Ziel des sog. Delta Timings ist es aber, einen Faktor für alle Bewegungen zu finden.
Zitat:
Im diesem ersten ansatz ging es auch nur darum, einen Delta wert zu ermitteln

Nehmen wir einmal an, mein Rechner läuft halb so schnell wie deiner, das Programm also mit 30Hz statt 60Hz bei dir. Es bedarf keiner großen Logik um zu ermitteln, dass der Frame bei dir ungefähr 16ms dauert, während mein Rechner 32ms braucht. Diese Werte sind durch eine Differenz der Millisecs zu ermitteln (man kann hier Δt schreiben, was vielleicht der Methode ihren Namen gegeben hat). Im gegebenen Beispiel sollten die Bewegungen auf meinem Rechner doppelt so "schnell" ausgeführt werden, was demnach ruckeliger, aber wenigstens genauso schnell wie auf deinem vonstatten geht. Da du der Nabel der Welt bist, wäre der gewünschte Faktor 2. Es sollte keine höhere Mathematik sein, eine Methode zu finden, um von 16 und 32 (die Framezeiten) auf 2 zu kommen.
Code: [AUSKLAPPEN]
Faktor = Δt/WunschFrameZeit

Die WunschFrameZeit war im Beispiel oben 16ms. Manchmal finden es die Leute aber besser, Frequenzen anzugeben, was Tornado11 gut erklärt hat. 1/60Hz = 16ms.
Code: [AUSKLAPPEN]
WunschFrameZeit = 1/WunschFrequenz

Die 1 steht hier ganz richtig, man muss sie aber manchmal ersetzen:
Code: [AUSKLAPPEN]
WunschFrameZeit = 1/WunschFrequenz = 1/60Hz = 1/(60*1/s) = 1s/60 = 1000ms/16

Ergibt zusammen die von dir verwendete Formel:
Code: [AUSKLAPPEN]
Faktor = Δt/WunschFrameZeit = Δt/(1/WunschFrequenz) = Δt/(1s/WunschFrequenz in Hz)

Der Name Delta ist für den Faktor in der Tat irreführend.
Zitat:
ps: FPS zahl habe ich bereits versucht, zu bestimmen.
Allerdings lief es nun darauf hinaus, das ich das ganze per zähler und millisecs()+1000 timesteps realisiert habe. Diese werte weichen allerdings leicht von der wirklichkeit ab.

Wäre mir ehrlich gesagt egal. Hauptsache, ich weiß, ob ich meine CPU-Grenzen ausgelotet habe bzw. wann das Programm in die Knie geht. Dafür reichen diese ungenauen Angaben.

ZEVS

Tornado11

BeitragFr, Aug 17, 2012 19:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich weiss nicht ob wir jetzt aneinander vorbeireden, aber als Korrekturfaktor genuegt einfach nur das delta:
Zitat:
delta = (currentMS - oldMS)

Also man mulitpliziert alle "Bewegungen" mit diesem Faktor und schont laeuft es frameunabhängig.

Es ist aber üblich, das delta mit einer konstanten K zu multiplizieren (mit der Einheit [1/s]=[hz]) und dies als Korrekturfaktor zu betrachten.

Code: [AUSKLAPPEN]
Faktor = Δt/WunschFrameZeit = Δt/(1/WunschFrequenz) = Δt/(1s/WunschFrequenz in Hz)

= Δt * WunschFrequenz ; Δt  ist das oben von mir beschriebene delta und WunschFrequenz eine willkürliche konstante die den Korrekturfaktor einheitslos macht

Jetzt könnte man den momentanen Korrekturfaktor mit einer weiteren Variablen multiplizieren mit einer anderen Einheit z.B. [Pixel/s].

Nova

BeitragFr, Aug 17, 2012 22:03
Antworten mit Zitat
Benutzer-Profile anzeigen
Es bringt nichts, wenn ihr die Sachen so erklärt, wie man es einem Profi machen würde. Das ganze Gerede um "Korrekturfaktor" oder so ist zwar richtig, aber nicht wirklich nützlich. Wink

Die Sache ist ganz einfach: Die Geschwindigkeiten aller Sachen müssen in einer festen "Einheit" angegeben werden, beispielsweise Pixel pro Sekunde. Also ein Objekt mit der Geschwindigkeit 120 würde sich pro Sekunde um 100 Pixel über den Bildschirm bewegen.
Wie weit müssen wir das Ding denn jetzt pro Bild bewegen, damit wir auf 120 Pixel pro Sekunde kommen? Wenn wir 60 Bilder pro Sekunde haben, dann sind es 2 Pixel pro Sekunde.
Wenn es immer exakt 60 Frames sind, dann wäre das Einfach. Man berechnet die Geschwindigkeit geteilt durch 60, und schon haben wir unseren Wert. Doof nur, dass der Wert meistens nicht immer bei 60 bleibt.
Wir müssen dafür wissen, wie lange das letzte Bild denn gedauert hat (in Millisekunden). Die Differenz von Startzeit und Endzeit der Berechnung des Bildes, Delta genannt, ist ein wichtiges Utensil dafür. Aber mit der Zahl selber können wir nicht viel anfangen. Daher müssen wir sie noch etwas umwandeln, indem wir die Zahl 1000 durch die Dauer des Bildaufbaus teilen. (Also 1000 / Geschw.)
Damit ist uns aber auch noch nicht gedient, denn wir wollen uns ja auf eine bestimmte Framezahl als "Standard-Geschwindigkeit" einigen. Daher müssen wir noch diese Standardgeschwindigkeit durch das Ergebnis von gerade teilen. (Also 60 / Ergebnis)
Welches Ergebnis kommt denn raus, wenn der Bildaufbau 50 Millisekunden dauert? 1000 / 50 ergibt 20. Dann 60 / 20 ergibt 3,0. Tja, wenn unser Spiel also nur mit einem Drittel der erwünschten Geschwindigkeit läuft, dann müssen unsere Objekte sich mit dreifacher Geschwindigkeit über den Bildschirm bewegen, um in der gleichen Zeit am Ziel anzukommen, wie es bei 60 Bilder pro Sekunde wäre.
Dieser berechnete Wert wird in Delta gespeichert. (Dann muss man nur noch die Variable Geschwindigkeit des Objektes mit Delta multiplizieren. Dann haben wir die gewünschte, gleichbleibende Geschwindigkeit.)

Du musst nur darauf achten, dass deine Einheiten nicht über die Karte springen, wenn der Benutzer das Spiel mal pausiert und es so bis zum nächsten Bild vielleicht mal 30 Sekunden dauert. Das wäre bei unserem Beispiel, mit 120 Pixel pro Sekunde schnellen Einheit, mal eben 3600 Pixel. So breit ist kein Bildschirm, den sich 97 Prozent der Nutzer hier leisten können. Wink

Ich hoffe mal, das ganze war einfach zu verstehen und hilft dir. Smile


Gruß, Nova
AMD Athlon II 4x3,1GHz, 8GB Ram DDR3, ATI Radeon HD 6870, Win 7 64bit
 

PhillipK

BeitragFr, Aug 17, 2012 22:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Herrje, da habe ich ja was losgetreten Very Happy

Mal vorweg: ich habe nichts gegen eine genauere erklärung, solange man auch mitkommt Very Happy

Selbst wenn es "über das ziel hinausschießt" (also die erklärung, nicht die px-bewegung), lernt man doch eine menge, wenn sich jemand die mühe macht und etwas kleinlich erklärt.

Ich habe dennoch eine schwerer erklärung erwartet. Nunjut, das thema ist anscheinend doch recht einfach Smile

Das einzige, was sich in meinem kopf quer gestellt hat, war wohl, das ich nie wirklich Hertz basiert gerechnet habe. Das hinter 1/60 eine simpler faktor steckt, kam mira uf den ersten blick nicht in den sinn oO Bin ich blöde ^^

Ich danke euch allen für die erklärungshilfen Very Happy

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group