Ich habe verschiedene "grundlegende" Spieleschleifen gesehen, sowohl aus Büchern wie "Einführung in die 3D-Spielprogrammierung mit DX11" oder dem Online-Tutorial (Rastertek), und wenn wir alle ausgefallenen Dinge zur Steuerung der Framerate und mehr entfernen, sehen sie alle ungefähr so aus:
while (msg != WM_QUIT) //
{
if (PeekMessage(&msg,0,0,0,PM_REMOVE)
{
// Translate and dispatch message
}
else
{
// Do update, rendering and all the real game loop stuff
}
}
Wenn Sie es so ausführen, funktioniert es perfekt, aber das, was ich nicht verstehe, ist das andere . Wenn ich naiv auf die Schleife schaue, könnte ich denken, dass wenn das System weiterhin Ereignisse sendet (Tastendrücke, Mausklicks und mehr), der else- Teil niemals ausgeführt wird, irre ich mich? (Ja !! Ich bin es, aber genau das ist der Punkt, ich verstehe nicht warum!).
Ich würde gerne verstehen, warum die Schleife so funktioniert. Wenn die Nachrichten eng mit dem Fenster verbunden wären (Größe ändern, verschieben, schließen), würde ich es verstehen, aber sie sind es nicht. Nehmen wir an, ich drücke eine beliebige Taste, eine WM_KEYDOWN-Nachricht wird wiederholt gesendet und eine Nachricht wird gespäht, sodass der else-Teil niemals ausgeführt werden kann
Ich habe nicht viel Erfahrung mit der Win32-Bibliothek und mir fehlt wahrscheinlich etwas ^^.
Vielen Dank für Ihre Zeit und viel Spaß beim Codieren!
Ich denke, Sie müssen verstehen, dass die Nachrichtenverarbeitung viel schneller abläuft als die Rate, mit der Nachrichten gesendet werden.
Für den von Ihnen angegebenen Beispielcode finden Sie hier eine Schätzung der Zeitabläufe:
Ich habe die Dokumentation nicht danach durchsucht, aber Windows spammt wahrscheinlich nicht ständig Nachrichten: Sie müssen in regelmäßigen Abständen eingehen, sonst würden sie das System überladen. Möglicherweise verwenden sie die Tastaturaktualisierungsrate, wenn Sie eine Taste gedrückt halten. Vielleicht verwenden sie die Bildschirmaktualisierungsrate.
Nehmen wir an, alle t ms kommt eine neue Nachricht , die einigermaßen größer als epsilon ist . Der
[A]
Teil der Schleife verarbeitet alle gestapelten Nachrichten sehr schnell: Er wird für epsilon ms ausgeführt und erneut gestartet, sodass keine neuen Nachrichten eingehen können. Sobald alle Nachrichten verbraucht sind, wird der[B]
Teil ausgeführt und neue Nachrichten werden wieder gestapelt.Hier ist eine Illustration, um zu versuchen, meinen Standpunkt zu verdeutlichen,
[An]
die Verarbeitung der[Mn]
von Windows gesendeten Nachrichten und[Bn]
die tatsächlichen Frame-Updates:Hier können Sie sehen, dass
[A]
das Spiel noch genügend Zeit hat, um seine Frames zu aktualisieren , solange die Dauer der Aufenthalte im Vergleich zur Nachrichtenrate relativ klein ist (hier ist sie bereits sehr übertrieben).Dies erklärt, warum eine solche Spielschleifenstruktur ein normales Spiel nicht verhindert. Aber die Lösung, die CoderScott in seiner Antwort vorgeschlagen hat, macht diesen Ausführungsfluss viel expliziter, daher sollte er meiner Meinung nach bevorzugt werden.
quelle
if / else in Ihrer Schleife verarbeitet Windows-Nachrichten vor allem. Die Schleife wird nicht zu lange blockiert (natürlich, wenn Ihr WndProc gut ist). Normalerweise gibt es nicht so viele Nachrichten. Ich glaube nicht, dass es einen besseren Weg gibt, um zu verhindern, dass das Fenster nicht mehr reagiert und FPS speichert. Wenn Sie Ihren Nachrichtenverarbeitungscode gut halten, denke ich, dass Ihre Schleife großartig sein wird.
Hier ist mein Code, ich glaube, er wird für Sie interessant sein und er ist ziemlich brauchbar. Aber eines Tages werde ich einen neuen codieren. Zumindest ist es viel besser als viele andere. Für ein spielbares Spiel benötigen Sie auf jeden Fall eine stabile Update-Rate (). Windows-Nachrichten werden es nicht brechen.
Run () Funktion:
quelle
Nein, du liegst nicht falsch. Eigentlich stimmt das - wenn es zu viele Ereignisse gibt, wird das andere nie oder zumindest nicht schnell genug ausgeführt. Wenn Ihre UI-Methoden zu viel Zeit benötigen, um das Ereignis zu verarbeiten, kann dies die OpenGL-Aktualisierung sperren. Zunächst sollten Sie überprüfen, warum die Verarbeitung von Ereignissen so viel Verarbeitung erfordert. Manchmal kann es jedoch zu Spam durch Ereignisse kommen (z. B. schnelle Mausbewegungen mit hohen Aktualisierungsraten), und selbst die einfache Verarbeitung benötigt zu viel Zeit, um mit dem OpenGL-Frame übereinzustimmen Timings aktualisieren.
Diese Schleife ist wirklich sehr schlecht und hat mich getroffen, als ich sie aus vielen Quellen im Internet kopiert habe (beachten Sie, dass dies ein falscher Ansatz ist ):
Das Richtige ist wie folgt:
Wenn also die Prozedur für Verarbeitungsereignisse mit zusätzlicher Unterbrechung zu viel verbraucht, wird eine erzwungene Aktualisierung des OpenGL-Frames durchgeführt.
quelle
Ich arbeite an einer OpenGL Shader Engine von www.MarekKnows.com und das Framework ist wie folgt eingerichtet: Eine Engine-Klasse, die Teil einer statischen Bibliothek mit anderen hilfreichen und wichtigen Klassen ist. Dann gibt es das Hauptstartprojekt, in dem sich die Spielklasse zusammen mit den Spieleigenschaften befindet. Diese Struktur dient dazu, den gesamten Engine-Code vom Spielcode zu trennen. Das Schöne an diesem Setup ist, dass es wiederverwendet werden kann, um eine Vielzahl von Spielen zu erstellen, indem es einfach von der Engine lib erbt. Es ist noch nicht vollständig, da jede Woche ein anderes Segment oder Klassenobjekt aufgenommen wird.
Diese Hierarchie basiert auf der Ordner- und VS-Filterstruktur:
Projekt - Static Lib Engine
GUI
MKO - Diese MKO-Objekthierarchie stützt sich stark auf Vorlagen
Shader - Diese Shader-Hierarchie stützt sich stark auf Vorlagen
Projekt starten - Spiel
Mit diesem Rahmen werde ich die Nachrichtenschleife für Sie demonstrieren
Wenn Sie mehr von diesem Code sehen möchten, müssen Sie www.MarekKnows.com besuchen, um seine wunderbar gut strukturierten und klar erklärten Video-Tutorials für die Spieleentwicklung mit OpenGL zu erhalten. Aus Gründen des Kopierrechts werde ich nur kleine Ausschnitte als Vorschläge an andere weitergeben, die ihnen bei einem bestimmten Fallproblem helfen können. Ich kann dies nicht als meinen eigenen Quellcode beanspruchen, aber mit dem Befolgen seines Kursaufbaus wird alles persönlich von Hand geschrieben und persönlich getestet. Es wird nicht kopiert und eingefügt! Fast alles, was ich über Spieleprogrammierung gelernt habe, ist zusammen mit einigen anderen Quellen in Mareks Videos akkreditiert.
Ich kann versuchen, dies so gut wie möglich aus dem, was ich gelernt habe, und der Ausführung des Codes zu erklären. Irgendwo im Programm wird die Funktion Engine :: start () aufgerufen. Das erste, was passiert, ist, dass wir in eine Endlosschleife gehen; Innerhalb dieser while-Schleife prüfen wir, ob Nachrichten aus Windows gesehen wurden, und ob dies der Fall ist, prüfen wir, ob die WM_QUIT-Nachricht von einem anderen Ort aus gesetzt wurde. Wenn es gesetzt wurde, brechen wir aus der while-Schleife aus und kehren von dieser Funktion zurück. Die Anwendung wird den Speicher bereinigen, das Fenster zerstören und schließen. Andernfalls rufen wir dann TranslateMessage () & DispatchMessage () auf. Wenn PeekMessage () false zurückgibt, gehen wir in die else-Anweisung und rufen proccessFrame () auf.
Auf meinem Computer rendere ich mit diesem Framework grundlegende GUI-Objekte mit etwa 100 bis 120 Bildern pro Sekunde. Ich habe eine EVGA NVidia GeForce GTX 750Ti 2 GB mit Übertaktung und Kühlmittel mit zwei Lüftern unter Windows 7 64 Bit mit 8 GB RAM auf einem Intel Core 2 Quad Extreme 3.0 GHz.
Wir haben uns noch nicht mit umfangreichen Animationen, Physik, Partikelsystemen und Kollisionserkennungen befasst. Wir haben jedoch all das in einer seiner älteren Videoserien behandelt, in denen die ältere GameEngine auf OpenGL v1.0 basierte und alles auf der CPU erledigt wurde. Mit dieser Serie arbeiten wir jetzt an der Verwendung von Shadern und der GPU. Ich bin mir sicher, dass wir mit dieser Rahmenarbeit problemlos ein vollständiges 2D- oder 3D-Spiel auf einem ähnlichen System wie meinem mit vollen 40 - 60 FPS ausführen können.
Eine weitere gute Quelle zum Lernen ist www.GeometricTools.com und der Buchabschnitt . Vor ein paar Jahren habe ich ihr Buch gekauft: 3D Game Engine Design (2. Auflage) von David H. Eberly, Die Morgan Kaufmann-Serie für interaktive 3D-Technologie, und es ist eine großartige Lektüre. Ich hatte noch keine Gelegenheit, ihr neuestes Buch zu kaufen: GPGPU-Programmierung für Spiele und Wissenschaft von David H. Eberly, möchte es aber bald besitzen, da es mit der modernen Hardware- und Softwareentwicklung relevanter, aktueller und aktueller ist. Viel Glück!
quelle