28
SEP09Mainloop, FPS, Framebremse und VSync …
Die Framebremse
Lasst mich euch ein paar Codeschnippsel zeigen die ich im Internet gefunden habe, wie man es machen kann aber besser nicht sollte.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
...
RECT Rectangle = { 10, 100, 100, 120 };
int startzeit;
while( !bQuit )
{
if( PeekMessage( &WindowMessages, NULL, 0, 0, PM_REMOVE) )
{
...
}
else
{
startzeit = GetTickCount();
// Frame neu malen
DrawText( hdc, calcFPS(), 32, &Rectangle, DT_LEFT );
while( (GetTickCount() - startzeit ) < 10 );
{
// Hier passiert nichts ;)
}
}
}
...
|
Wenn ich diese Art von Framebremse benutze bekomme ich statt meinen ~4k Frames nur noch rund 64 FPS. Hier eine weitere Variante die mich nicht mehr auf dem Stuhl gehalten hatte
1 2 3 4 5 6 7 8 9 10 11 12 13 |
...
}
else
{
// Frame neu malen
DrawText( hdc, calcFPS(), 32, &Rectangle, DT_LEFT );
for( int i=0; i<1000000; i++ )
{
// Hier passiert nichts ;)
}
}
...
|
Also ersteres findet ihr sogar in meinem Pong und sogar in meinem Frozenbubble Clone wieder, ich hab damals auch nur die erst beste Variante genommen, aber die zweite Variante ist mal echt übel. Also bitte liebe Leser, die erste Variante lass ich ja noch durchgehen aber von der zweiten Variante solltet ihr lieber die Finger lassen. Die Variante die ich euch empfehlen kann ist, die Bewegung der Objekte mit der vergangenen Zeit des letztens Frames zu Multiplizieren. ;)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
...
UINT uiLastRound = 0;
UINT uiDeltaTime = 0;
float PositionX = 0.0f;
while( !bQuit )
{
if( PeekMessage( &WindowMessages, NULL, 0, 0, PM_REMOVE) )
{
...
}
else
{
uiLastRound = GetTickCount();
// Frame neu malen
DrawText( hdc, calcFPS(), 32, &Rectangle, DT_LEFT );
Rectangle.left = static_cast<LONG>( PositionX );
Rectangle.right = Rectangle.left + 90;
// deltaTime berechnen
uiDeltaTime = ( GetTickCount() - uiLastRound );
// deltaTime mit Bewegung multiplizieren
PositionX += ( 0.05f * uiDeltaTime );
}
}
...
|
In diesem Beispiel wollen wir das unsere Objekt xPixel pro Sekunde nach links wandert. Da wir nur Ganzzahlen, für jeden Pixel, darstellen können, wir aber viele kleine Schritte machen werden, müssen wir eine Position als Float definieren. Mit unserem static_cast wird dann von diesem aktuellen Wert immer die Nachkommestellen abgeschnitten. Wenn jetzt jemand mit einem langsamen Rechner dies ausführt, wird nach eine Zeit von X die Position die gleiche sein wie auf einem schnelleren Rechner. Der schnelle Rechner macht zwar viele kleine Schritte aber auch wenige größere Schritte bringen uns auf die gleiche Position ;)
Das ganze Thema mit Framebremse hin oder her zählt je nur bei Rechnern auf denen kein VSync vorhanden oder abgeschaltet ist. Was ist das eigentlich und was macht es genau?
VSync – Vertikale Synchronisation
Ich möchte hier jetzt nicht ausschweifend werden, kurze erklärung zu VSync. VSync verhindert das die Grafikkarte ein weiteres Bild rüber schickt bevor dies überhaupt beim Monitor angekommen ist, somit hat mein quasi eine Framebremse die sich nach der eingestellten Frequenz des Monitors richtet. Genauere Informationen über VSync bekommt ihr schön erklärt in Wikipedia unter http://de.wikipedia.org/wiki/Vsync
Auf folgender Seite findet ihr ein Code-Snippet mit dem ihr VSync Anwendungsgesteuert aus und anschalten könnt. http://dotnet-snippets.de/dns/deaktivieren-von-vsync-unter-opengl-SID860.aspx
Das wars eigentlich auch schon mit diesen Themen der Spieleentwicklung. Ich wünsch euch viel Spaß beim programmieren.
P.S. Wenn ihr die FPS Berechnung und die für DeltaTime in eine Klasse packt dann habt ihr das alles schön kompakt zusammen ;)





1 Kommentare
Diese Funktion:
swprintf_s( szFPS, 7, _T(“%u/s”), static_cast( uiFramerate * 1000.0 / uiElapsedTime ) );
ist leider nicht verwendbar, da diese als ersten parameter wchar_t* erfordert.
verwende bitte die funktion sprintf_s
Kommentar schreiben