Seite 1 von 4

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

Verfasst: 13.08.2008 23:28
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

Verfasst: 13.08.2008 23:34
von Little John
Danke!
wenn die größer ist als 16 ms
Warum gerade 16?

Gruß, Little John

Verfasst: 13.08.2008 23:35
von Kaeru Gaman
das ist die tatsächlich zuverlässige maximalabweichung.

10ms minimum, 13 ms durchschnitt, 16ms maximum per timeslice.

Verfasst: 13.08.2008 23:40
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

Verfasst: 13.08.2008 23:46
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.

Verfasst: 14.08.2008 00:06
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

Verfasst: 14.08.2008 00:11
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!

Verfasst: 14.08.2008 00:45
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.

Verfasst: 14.08.2008 08:31
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)

Verfasst: 14.08.2008 10:15
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