[GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von Mijikai »

mk-soft hat geschrieben:Es ist besser mit Frames zu arbeiten um nicht die CPU Last zu hoch zu schrauben...

...
Danke, verwendet aber leider AddWindowTimer() was ich (später) nicht nutzen kann.
Der Code soll auch bei Fenstern funktionieren die nicht mit PureBasic erstellt wurden.

Hier mal mein Ansatz, leider ist noch was falsch es wird auf ~100 FPS :? gedrosselt anstatt auf 60!

Code:

Code: Alles auswählen

DeclareModule FPS
  Declare.i Init()
  Declare.i Count()
  Declare.f Delta()
  Declare.i Update()
EndDeclareModule

Module FPS
  
  #FPS_60 = 16
  #FPS_30 = 33
  #FPS_25 = 40
  #FPS_80 = 12
  #FPS_75 = 13
  #FPS_24 = 41
  #FPS_20 = 50
  #FPS_10 = 100
    
  Structure PERFORMANCE_STRUCT
    FrameTarget.q
    FrameStart.q
    FrameEnd.q
    FrameTime.f   
    Timing.f
    FrameCount.i
    FPS.i
    DeltaTime.f
  EndStructure
  
  Global Performance.PERFORMANCE_STRUCT
  
  Procedure.i Init()
    With Performance
      \FrameTarget = #FPS_60;GEWÜNSCHTE FPS!
      \FrameStart = ElapsedMilliseconds()
    EndWith
  EndProcedure
  
  Procedure.i Count()
    ProcedureReturn Performance\FPS
  EndProcedure
  
  Procedure.f Delta()
    ProcedureReturn Performance\DeltaTime
  EndProcedure
  
  Procedure.i Update() 
    With Performance
      If \FrameTime < \FrameTarget
        Delay(\FrameTarget - \FrameTime);NICHT KORREKT !?
      EndIf
      \FrameEnd = ElapsedMilliseconds()
      \FrameTime = \FrameEnd - \FrameStart
      \DeltaTime = \FrameTime / \FrameTarget
      \FrameStart = \FrameEnd
      If \Timing > 999
        \FPS = \FrameCount
        \Timing = 0
        \FrameCount = 1
      Else
        \Timing + \FrameTime
        \FrameCount + 1
      EndIf 
    EndWith
  EndProcedure

EndModule

If InitSprite()
  If OpenWindow(0,0,0,400,400,"TestWindow",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
    If OpenWindowedScreen(WindowID(0),0,0,400,400,#False,0,0,#PB_Screen_NoSynchronization);<- KEIN SYNCH!
      FPS::Init()
      Repeat
        ClearScreen($EB8724)
        If StartDrawing(ScreenOutput())
          DrawingMode(#PB_2DDrawing_Transparent)
          DrawText(10,10,"FPS: " + Str(FPS::Count()))
          DrawText(10,30,"DLT: " + StrF(FPS::Delta(),2))
          StopDrawing()
        Else
          PostEvent(#PB_Event_CloseWindow)
        EndIf
        FlipBuffers()
        FPS::Update()
      Until WindowEvent() = #PB_Event_CloseWindow
    EndIf
  EndIf 
EndIf
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von RSBasic »

Achso, du verwendest OpenWindowedScreen. Dann ist ein Delay schon sinnvoll, um den Prozessor zu entlasten.
In der PB-Hilfe unter OpenWindowedScreen gibt es ein Beispielcode mit einem Delay(1) und die Screen-Anwendung verbraucht nur 1 %-Prozessorauslastung.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von ccode_new »

Huhu!!!!

Es ist eigentlich recht simpel.

Wichtig ist eine konstante Framerate festzulegen und die Zeit zwischen dem Aktualisieren zu messen (DeltaT).

Das sind eigentlich die Standards und alles ist locker flockig handelbar.

Man sollte aber beachten das trotz NOSync meist Treibertechnisch trotzdem bei 60 FPS abgeriegelt wird.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Jan125
Beiträge: 31
Registriert: 23.06.2013 06:26
Computerausstattung: Nicht lachen. Atom Z3775, 2GiB RAM, Win8.1.

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von Jan125 »

Hm, keine Ahnung ob das weiterhelfen könnte, aber mal 'ne kleine Entkoppelung via Threads.
Vermutlich müssen sich die erfahreneren Coder hier gleich übergeben. ;P

Code: Alles auswählen

Procedure.l GetTime()
  Static TimeLast.l
  Protected TimeNow.l
  Protected TimeReturn.l
  If TimeLast = 0
    TimeLast = ElapsedMilliseconds()
    ProcedureReturn 0
  EndIf
  TimeNow = ElapsedMilliseconds()
  TimeReturn = TimeNow-TimeLast
  TimeLast = TimeNow
  ProcedureReturn TimeReturn
EndProcedure
Procedure.l ThreadDelay(Delay)
  Delay(Delay)
  ProcedureReturn 0
EndProcedure

Structure ObjectStructure
  
EndStructure


Global Mutex.l
Global NewList svObjectList.ObjectStructure()
Global NewList clObjectList.ObjectStructure()



Procedure GameInit()
  UsePNGImageDecoder()
  
  InitSprite()
  InitSound()
  InitKeyboard()
  
  PrintN("Opening window.")
  OpenWindow(1, #PB_Ignore, #PB_Ignore, 800, 600, "asCL")
  PrintN("Opening screen.")
  OpenWindowedScreen(WindowID(1), 0, 0, 400, 300, 1, 0, 0, #PB_Screen_NoSynchronization)
  TransparentSpriteColor(#PB_Default, $ff00ff)
  
  
  For i = 0 To 0
  AddElement(svObjectList())
Next
EndProcedure

Procedure GameClient()
  Protected Event.l
  ;SetFrameRate(1000)
  UnlockMutex(Mutex)
  
  Repeat
    Repeat
      Event = WindowEvent()
      Select Event
        Case #PB_Event_CloseWindow
          Quit = 1
      EndSelect
    Until Event = 0
    ClearScreen($606060)
    
    
    
    
    
    LockMutex(Mutex)
    CopyList(svObjectList(), clObjectList())
    UnlockMutex(Mutex)
    
    
    
    
    ForEach clObjectList()
      ;;Display Objects
    Next
    
    
    
    
    
    
    
    FlipBuffers()
    
  Until Quit = 1
  
  ProcedureReturn 0
EndProcedure
Procedure GameServer(Rate_TickRate = 100) ;low overhead asynch rate server
  Protected ThreadDelayID.l
  Protected Correction.l
  Protected Time.l
  Protected ThreadCreationCorrection.l
  For i = 1 To 10
    Time = ElapsedMilliseconds()
    ServerDelay = CreateThread(@ThreadDelay(), 1)
    WaitThread(ServerDelay)
    ThreadCreationCorrection+(Time-ElapsedMilliseconds())
  Next
  ThreadCreationCorrection/10
  PrintN("Thread creation delay: "+Str(ThreadCreationCorrection))
  Time = ElapsedMilliseconds()
  Rate_Elapsed = Rate_TickRate
  PrintN("Resuming server loop.")
  Repeat
    Correction = Correction+(Rate_TickRate-Rate_Elapsed)
    If Rate_TickRate+Correction+ThreadCreationCorrection > 0
      ServerDelay = CreateThread(@ThreadDelay(), Rate_TickRate+Correction+ThreadCreationCorrection)
    EndIf
    
    ;;Debugger has to be disabled when calling Keyboard functions in a thread.
    ;;Else it will raise an exception
    DisableDebugger
    ExamineKeyboard()
    LockMutex(Mutex)
    FirstElement(svObjectList())
    ;;Keyboard Queries
    
    EnableDebugger
    
    ForEach svObjectList()
      ;;Object Actions
    Next
    UnlockMutex(Mutex)
    
    WaitThread(ServerDelay)
    Rate_Elapsed = ElapsedMilliseconds()-Time
    Time+Rate_Elapsed
    PrintN(Str(Rate_Elapsed))
    Debug Correction
    
  ForEver
  
  ProcedureReturn 0
EndProcedure



If OpenLibrary(0, "Kernel32.dll")
  Prototype GetConsoleWindow()
  Define GetConsoleWindow.GetConsoleWindow = GetFunction(0, "GetConsoleWindow")
  CloseLibrary(0)
EndIf



OpenConsole()
ConsoleHandle = GetConsoleWindow()
EnableMenuItem_(GetSystemMenu_(ConsoleHandle, #False), #SC_CLOSE, #MF_DISABLED)






Mutex = CreateMutex()

GameInit()
LockMutex(Mutex)
Server = CreateThread(@GameServer(), 20)
GameClient()
PrintN("Locking server thread.")
LockMutex(Mutex)
KillThread(Server)
PrintN("Killed server thread.")
UnlockMutex(Mutex)
PrintN("Shutting down.")
End
Müsstest eben was in die Struktur einfügen und auch Aktionen dafür festlegen...
Zuletzt geändert von Jan125 am 07.05.2018 21:42, insgesamt 3-mal geändert.
Wer braucht schon Unicode? PB5.24LTS
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von ccode_new »

Ah!

"ThreadCreationCorrection" :mrgreen:
Vermutlich müssen sich die erfahreneren Coder hier gleich übergeben. ;P
:mrgreen:

Keine Ahnung!
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von Mijikai »

Jan125 hat geschrieben:Hm, keine Ahnung ob das weiterhelfen könnte, aber mal 'ne kleine Entkoppelung via Threads.
Vermutlich müssen sich die erfahreneren Coder hier gleich übergeben. ;P Müsstest eben was in die Struktur einfügen und auch Aktionen dafür festlegen...
:shock:
Was passiert hier ?
Ist zu komplex/durcheinander für mich.
Jan125
Beiträge: 31
Registriert: 23.06.2013 06:26
Computerausstattung: Nicht lachen. Atom Z3775, 2GiB RAM, Win8.1.

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von Jan125 »

Ups, stimmt ja... :D

Ich entkoppele die Logik von der Anzeige via Threads.
Der Großteil des Codes besteht aus Zeitstabilisierung und Korrektur (dazu eben noch das Thread-Erzeugungs-Delay, denn der Delay wird asynchron über einen weiteren Thread bewerkstelligt).
Im Endeffekt kümmert sich der "Server" um Eingaben und alles andere, packt darzustellende Objekte in eine Liste, der "Client" kopiert diese Liste und stellt sie dann dar.

Somit muss man sich um Frameratediskrepanzen keine Sorgen mehr machen. ^w^


(Das Ganze könnte dennoch nicht ganz Save sein, siehe Anmerkung zu Tastaturevents im Server.)
Wer braucht schon Unicode? PB5.24LTS
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von Mijikai »

Jan125 hat geschrieben:
Würde den Code gerne besser verstehen :)

- Wo ist die Procedure -> ThreadDelay() ?

Code: Alles auswählen

CreateThread(@ThreadDelay(), 1)
;...
CreateThread(@ThreadDelay(), Rate_TickRate+Correction+ThreadCreationCorrection)
;...
- Wird WindowEvent() nicht geblockt solange bis es ein Signal gibt ?

- Der Code scheint den Prozessor nicht zu entlasten hängt bei mir bei 5 - 8% !
Jan125
Beiträge: 31
Registriert: 23.06.2013 06:26
Computerausstattung: Nicht lachen. Atom Z3775, 2GiB RAM, Win8.1.

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von Jan125 »

ThreadDelay ist ganz oben, zweite Prozedur.
Soll einfach nur als Zeitgeber fungieren.

Nö, das wäre WaitWindowEvent, und wenn man das benutzen würde, dann würde die Darstellung blockieren. :D (Oder man macht einen weiteren Thread...)

Entlastung ist hier nicht das Ziel, die Performance wird sogar eher stark abnehmen. Hier soll nur die Tickrate korrigiert werden (wenn in einem Tick zu viel bearbeitet werden muss kann das durch den nächsten Tick u. U. ausgeglichen werden), sowie eine generelle Unabhängigkeit von der britischen Kron-... Äh, von der Bildwiederholfrequenz des Monitors (ältere CRTs haben z. B. meist 75Hz statt 60Hz, manche neueren Monitore 144Hz).

Da ich morgen frei habe setz' ich mich heute Abend mal hin und schreib 'n kleines Beispiel. :>
Wer braucht schon Unicode? PB5.24LTS
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [GameLoop] DeltaTime & FPS ? (kein V-Sync/Framelimit)

Beitrag von Mijikai »

Jan125 hat geschrieben:ThreadDelay ist ganz oben, zweite Prozedur.
Soll einfach nur als Zeitgeber fungieren.
Ah, das habe ich tatsächlich nicht gesehen, sah wie eine Funktion aus.
Jan125 hat geschrieben:Nö, das wäre WaitWindowEvent, und wenn man das benutzen würde, dann würde die Darstellung blockieren. :D (Oder man macht einen weiteren Thread...)
Ok das ist gut, ich steig bei Threads noch nicht wirklich durch.

_________________________________________________________________________________________


Ich hab bei meinem Code jetzt eine 'Clock' hinzugefügt um ein Render-Event auszulösen.

Code: Alles auswählen

If \Clock >= \FrameTarget
;...
Damit funktioniert es jetzt.
Momentan wird der Prozessor mit Delay(1) entlasted, besser
wäre ein Nano-Sleep (möglich aber nur mit OS-API).

Bild
Antworten