[code] Billiges Game-Timing mit nativen PB-Mitteln

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

[code] Billiges Game-Timing mit nativen PB-Mitteln

Beitrag von Kaeru Gaman »

nach Lektüre dieses Artikels:
http://www.geisswerks.com/ryan/FAQS/timing.html
kam ich drauf, dass die letzendlich vorgeschlagene lösung garnicht so unterschiedlich
von der einfachsten Grundmethode mit nativen PB Befehlen ist.

hier als winzige Demo:

Code: Alles auswählen

; *********
; Demo für Timing auf 30 FPS

EnableExplicit

Define.l FPS, Timer, TimerDuration, TimeGap
Define.l n, t, col
Define.l PX, PY
Define.l EXIT

InitSprite()
InitKeyboard()
OpenScreen(1024,768,32,"TimerDemo")

; ** ein Sprite erzeugen, damit man auch was sieht
CreateSprite(0,128,128)
StartDrawing(SpriteOutput(0))
  For n=0 To 127
    col = RGB(64-n/2,128-n,255-n)
    LineXY( 63-n, 63  , 63  , 63-n, col)
    LineXY( 64+n, 64  , 63  , 63-n, col)
    LineXY( 63-n, 63  , 64  , 64+n, col)
    LineXY( 64+n, 64  , 64  , 64+n, col)
  Next
StopDrawing()

FPS = 30
TimerDuration = 1000 / FPS

PX = 512-64
PY = 384-64

Repeat

  ; ** Zeit zu beginn des Schleifendurchlaufs rückspeichern
  timer = ElapsedMilliseconds()
  ; **

  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Escape)
    EXIT = 1
  EndIf
  If KeyboardPushed(#PB_Key_Left)
    PX - 4
  EndIf
  If KeyboardPushed(#PB_Key_Right)
    PX + 4
  EndIf
  If KeyboardPushed(#PB_Key_Up)
    PY - 4
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    PY + 4
  EndIf

  ClearScreen($201008)

  DisplaySprite(0,PX,PY)

  ; ** Aktuelle Differenz zwischen Soll-Zeit ( TimerDuration )
  ; ** und tatsächlich verstrichener Zeit ermitteln
  TimeGap = TimerDuration - (ElapsedMilliseconds() - Timer)
  ; ** wenn die größer ist als 16 ms, per Delay warten
  If TimeGap > 16
   ; ** ein bißchen weniger warten, Luft lassen
    Delay( TimeGap - 10 )
  EndIf
  ; ** den Rest des Wartens überlassen wir FlipBuffers
  FlipBuffers(#PB_Screen_SmartSynchronization)
Until EXIT = 1
das ist natürlich nicght so gut geeignet für ein timing von hohen FPS,
aber mal ehrlich, wer braucht schon sein Minigame mit 140FPS laufen lassen....

Aktualisierung für PB 4.40

Code: Alles auswählen

; *********
; Demo für Timing auf 30 FPS
; Änderungen für PB 4.40 Jan.2010

EnableExplicit

Define.l FPS, Timer, TimerDuration, TimeGap
Define.l n, t, col
Define.l PX, PY
Define.l EXIT

InitSprite()
InitKeyboard()
OpenScreen(1024,768,32,"TimerDemo", #PB_Screen_NoSynchronization)

; ** ein Sprite erzeugen, damit man auch was sieht
CreateSprite(0,128,128)
StartDrawing(SpriteOutput(0))
  For n=0 To 127
    col = RGB(64-n/2,128-n,255-n)
    LineXY( 63-n, 63  , 63  , 63-n, col)
    LineXY( 64+n, 64  , 63  , 63-n, col)
    LineXY( 63-n, 63  , 64  , 64+n, col)
    LineXY( 64+n, 64  , 64  , 64+n, col)
  Next
StopDrawing()

FPS = 30
TimerDuration = 1000 / FPS

PX = 512-64
PY = 384-64

Repeat

  ; ** Zeit zu beginn des Schleifendurchlaufs rückspeichern
  timer = ElapsedMilliseconds()
  ; **

  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Escape)
    EXIT = 1
  EndIf
  If KeyboardPushed(#PB_Key_Left)
    PX - 4
  EndIf
  If KeyboardPushed(#PB_Key_Right)
    PX + 4
  EndIf
  If KeyboardPushed(#PB_Key_Up)
    PY - 4
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    PY + 4
  EndIf

  ClearScreen($201008)

  DisplaySprite(0,PX,PY)

  ; ** Aktuelle Differenz zwischen Soll-Zeit ( TimerDuration )
  ; ** und tatsächlich verstrichener Zeit ermitteln
  TimeGap = TimerDuration - (ElapsedMilliseconds() - Timer)
  ; ** wenn die größer ist als 16 ms, per Delay warten
  If TimeGap > 16
   ; ** ein bißchen weniger warten, Luft lassen
    Delay( TimeGap - 10 )
  EndIf
  ; ** den Rest des Wartens überlassen wir FlipBuffers
  FlipBuffers()
Until EXIT = 1
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Little John

Beitrag von Little John »

Danke!
wenn die größer ist als 16 ms
Warum gerade 16?

Gruß, Little John
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

das ist die tatsächlich zuverlässige maximalabweichung.

10ms minimum, 13 ms durchschnitt, 16ms maximum per timeslice.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Little John

Beitrag von Little John »

Kaeru Gaman hat geschrieben:das ist die tatsächlich zuverlässige maximalabweichung.

10ms minimum, 13 ms durchschnitt, 16ms maximum per timeslice.
Aha. :)
Ich verstehe kein Wort ... Woher kommen diese Zahlen?

Gruß, Little John
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

erfahrung - messungen von boardkollegen immer mal wieder...

seit fast 4 jahren immer wieder über timing und elapsedmilliseconds diskutiert.
herausgekommen ist, dass ich mich lieber auf 16 verlasse als auf 13 oder 10,
um nicht aus versehen drüber zu liegen.


@Topic

das ist wie gesagt ein ganz einfaches Timing.
wenn man präziser vorgehen will, sollte man sowieso getimetes unit-movement
und schnellstmögliches bufferflippen in getrennten threads betreiben.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Little John

Beitrag von Little John »

Die 16 beziehen sich doch auf die 30 FPS, oder? Kann man das verallgemeinern, dass man da als Faustregel einen Wert knapp über der Hälfte nehmen sollte, also z.B. bei 40 FPS dann vielleicht 21?

Gruß, Little John
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag von Thorium »

Timing ist immer interessant.
Die Tolleranz von timeGetTime ist von System zu System unterschiedlich.
Auf meinem System beträgt die Tolleranz tatsächlich nur 1ms, wenn ich Tolleranz entspechend mit timeBeginPeriod festlege.

Also von 16ms auszugehen ist schon nicht schlecht, da ist man auf der sicheren Seite.

Generell ist man mit timeGetTime oder ElapsedMilliseconds auf der sicheren Seite. Gibt ja einige die auf QueryPerformanceCounter schwören. Der hat aber leider einen Bug, der bei hoher PCI-Last zum tragen kommt. Da kann die gemessene Zeit um mehrere Sekunden daneben liegen!
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

Little John hat geschrieben:Die 16 beziehen sich doch auf die 30 FPS, oder?
nein, das ist eher zufall.

wie auch in dem Artikel beschrieben wird:
10ms ist die tatsächliche höchstgenauigkeit eines unjustierten* GetTickCount, und damit auch von Elapsedmilliseconds.
wenn man dann mit nativen PB-Mitteln nachmisst, dann kommt man drauf,
dass die genauigkeit im Mittel um die 13ms liegt.
das kann bis zu 15/16 ms hochgehen, deshalb das als sicherheitsabstand.

Thorium hat geschrieben:Also von 16ms auszugehen ist schon nicht schlecht, da ist man auf der sicheren Seite.
sehe ich auch so.

und wie gesagt, wenn man wirklich was genauer timen will,
sollte man sowieso darstellung und berechnung trennen.


> wenn ich Tolleranz entspechend mit timeBeginPeriod festlege.
*) das ist dann justieren das ist schon ein anfang, aber eben nicht mehr nativ PB.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag von ZeHa »

Thorium hat geschrieben:Gibt ja einige die auf QueryPerformanceCounter schwören. Der hat aber leider einen Bug, der bei hoher PCI-Last zum tragen kommt. Da kann die gemessene Zeit um mehrere Sekunden daneben liegen!
Das wird in besagtem Artikel aber auch angesprochen, soweit ich weiß sogar mit einem Lösungsvorschlag (bin mir aber nicht sicher da ich mir die Stelle noch nicht so genau angeschaut hab)
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Der genannte Hardware-Bug tritt nur bei älteren Chipsätzen auf (Liste gibt´s bei MS). Wer die auf seinem Mutterbrett hat, diskutiert hier garantiert nicht mit ... :mrgreen:
Wichtig ist bei Multi-Cores die Core-Zuweisung!

Gruß
Helle
Antworten