framerate-unabhängige GameLoop

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.
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Re: meine derzeitige GameLoop

Beitrag von ZeHa »

@ Stargate, das ist natürlich auch richtig. Wenn (in einem tilebasierten Spiel) Deine Tiles 32 Pixel breit sind, aber ein Objekt sich pro Frame bereits mehr als 32 Pixel bewegt, dann kann das im Prinzip jederzeit auftreten ;)
Aber wer so etwas in seinem Spiel drin hat, der wird dafür so oder so dann eine Lösung finden müssen, egal welche GameLoop er verwendet :)
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Re: meine derzeitige GameLoop

Beitrag von PMV »

ZeHa hat geschrieben:Das ist aber was völlig anderes - sag mir Bescheid falls ich mich irre, aber meinst Du nicht einfach nur die Parallelisierung der Grafik-Prozessoren?
Bescheid. :mrgreen:

Grafikkarten haben immer eine GPU. Für die 2-GPU-Lösung brauchts spezielle
Grafiktreiber, die nVidia und ATI jeweils für das entsprechende Spiel raus bringen
müssen. Grafikkarten, die direkt 2 GPUs eingebaut haben, sind halt von Haus
als 2 Grafikkarten an zu sehen. Und diese Variante gibs eigentlich immer nur mit
den Spitzenmodellen. Die 2. bringt nur was, wenn es entsprechende Treiber für
das Spiel gibt. Es gibt auch andere Möglichkeiten, um eine 2. Grafikkarte aus zu
nutzen, aber das ist nicht Sache des Spieleentwicklers, sondern Treibereinstellung.
:wink: Unter Multithreading ist immer die CPU gemeint, also auch bei DX11.
Wobei natürlich hier vorallem CPU-Aufgaben zwecks der Grafik im Fordergrund
stehen. Aber das nur am Rande, für uns PB-Jünger spielt das natürlich weniger
eine Rolle. Höchstens wenn OGRE mal DX11 kann. Ich wollte das nur mal erwähnen.
:wink:

Doch zurück zum eigentlichen Thema. Ich hab aktuell in meinem Spiel an vielen
stellen Erstellung neuer Objekte, Entfernen, Schleifen in denen die Objektpositionen
aktualisiert werden usw. Um die Gamelogik nun splitten zu können, muss ich
zwangsweise alles grafische bündeln. Erst wenn alles sauber getrennt ist, kann
ich überhaupt mit Threads anfangen. Da DX9 alls in einem Thread braucht, liegt
es daher nahe, auch einen entsprechenden Thread dafür zu starten. Ich werd mir
dafür ein kleines Eventsystem basteln, das alle Grafikaktionen wie erstellen und
entfernen von Entities behandeln kann. Die einen Threads schreiben rein, der
Grafikthread liest alles aus und verarbeitet dann. Nach dem alles verarbeitet ist, wird
gerendert. Während des Verarbeitens und Renderns können die Gamelogik-Threads
wieder neue Events generieren. Und wenn man es richtig macht, kann sogar
teilweise während des einlesens von Events weiter neue Events generiert werden. :wink:

So kann das Spiel mit 25 FPS laufen ... die Steuerung reagiert trotzdem flüssig,
Kollision bleibt sauber, Pathfinding lässt die Kerne glühen und die Bewegung
verläuft intern ohne sprünge, so das selbst wenn die FPS mal in den Keller fallen
sollte, das Spiel stabil weiter läuft. Aber vorallem, während des Renderns muss die
CPU nicht auf die Grafikkarte warten.

Und wen es interessiert: So lange wir keine "StaticGeometry" haben, läuft bei der
OGRE3D implementierung (DX9) von PureBasic mehr über die CPU, als einem lieb
ist. Da ist es sogar unumgänglich, einen eigenen Thread für die Grafikbefehle zu
haben. Und ich kann nur hoffen, das PB mir keinen Strich durch die Rechnung macht
durch einen Bug, der Auftaucht wenn ich Threads nutze. :coderselixir:

MFG PMV
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Re: meine derzeitige GameLoop

Beitrag von Thorium »

Es gibt ne Menge Aufgaben, die sich mit teilweise enormem Performancezuwachs parallelisieren lassen.
In vielen Fällen macht es keinen Sinn Threads verschiedene Aufgaben zu geben, da Aufgabe B das Ergebnis von Aufgabe A braucht. Was aber Sinn macht ist es viele Threads an der gleichen Aufgabe werkeln zu lassen. Nur so reizt man Multicores aus.

Z.B. Kollisionserkennung. Warum nur ein Objekt testen, wenn ich jeden weiteren Core ein weiteres zur gleichen Zeit testen lassen kann?
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: meine derzeitige GameLoop

Beitrag von STARGÅTE »

Das heißt, man könnte bei 5 Objekten (10 Paarungen) jeweils 5 Paarungen auf beide Kerne verteilen.
Diese müssten dann nur bei einer Kollision in eine gemeinsamme Liste schreiben welche Paarung eine Kollision erzeugt.

Problem ist aber, wie verteile ich die Paarungen, schließlich können nicht beide Theads gleichzeitig die Liste der Obejkte durchgehen. Und für je ein Paar ein Thread zu öffnen ist vermutlich eh noch langsammer oder ?

Das heißt, dort müsste man erst zwei Listen anlegen für beide Threads in denne dann die jeweiligen Paarungen vordefiniert werden.
In den Threads wird dann nur noch auf Kollision überprüft.

Werde das mal näher austesten...
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Re: meine derzeitige GameLoop

Beitrag von Thorium »

STARGÅTE hat geschrieben:Das heißt, man könnte bei 5 Objekten (10 Paarungen) jeweils 5 Paarungen auf beide Kerne verteilen.
Diese müssten dann nur bei einer Kollision in eine gemeinsamme Liste schreiben welche Paarung eine Kollision erzeugt.

Problem ist aber, wie verteile ich die Paarungen, schließlich können nicht beide Theads gleichzeitig die Liste der Obejkte durchgehen. Und für je ein Paar ein Thread zu öffnen ist vermutlich eh noch langsammer oder ?

Das heißt, dort müsste man erst zwei Listen anlegen für beide Threads in denne dann die jeweiligen Paarungen vordefiniert werden.
In den Threads wird dann nur noch auf Kollision überprüft.

Werde das mal näher austesten...
Kollision war nur ein Beispiel. Aber ja, man muss immer überlegen wie man es aufteilen kann. Ich mache es so das der Mainthread Jobs an die anderen Threads verteilt, diese haben also keinen Zugriff auf solche Listen, sondern bekommen nur die Daten, die sie brauchen. Und liefern das Ergebnis beim Mainthread ab, der die Einzeljobs dann wieder zu einem Ergebnis zusammenführt.
Am besten funktioniert das natürlich, wenn große Datenmengen durchgeackert werden müssen. Die teilt man durch die Anzahl Cores und verteilt die Jobs als Teilmenge der Daten an die Threads. Funktioniert natürlich nur mit parallelisierbaren Aufgaben.

Ich hatte als POC eine pixelgenaue Kollisionserkennung gemacht, welche mit Collisionmaps in Bitform arbeitet, dort können sogar mehrere Threads an der gleichen Kollision arbeiten, lohnt sich aber nur wenn große Sprites da sind, da diese Kollisionserkennung sowieso bis zu 128 Pixel aufeinmal testet. Das heisst mit 4 Cores könnte sie 512 pixel gleichzeitig testen.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
7x7
Beiträge: 591
Registriert: 14.08.2007 15:41
Computerausstattung: ganz toll
Wohnort: Lelbach

Re: meine derzeitige GameLoop

Beitrag von 7x7 »

@Zeha
Ich programmiere keine Spiele, aber ich bin ein Freund von Multi-Threading.

Um dein Spielablauf-Beispiel parallelisieren zu können, würde ich ein Double-Buffering wie folgt wählen:

Code: Alles auswählen

Vereinfachtes Programmschema:

StartThread:
Do:
	Do:
	   Daten in Buffer Ready?
	Loop:
	
	Buffer sperren
	Rendere Daten aus Buffer
	Buffer freigeben
Loop:



StartMain:
Do:
        Berechne neue Spieldaten
        Do:
           Buffer1 freigegeben?
        Loop:
	     Spieldaten ablegen in Buffer1 und setze Ready-Flag
        
        Berechne neue Spieldaten
        Do:
           Buffer2 freigegeben?
        Loop:       
	     Spieldaten ablegen in Buffer2 und setze Ready-Flag

Loop: 
Während die Mainloop die Daten für den 2.Buffer berechnet, kann der Threadloop
die Daten des 1.Buffers bearbeiten und umgekehrt. Der "Mainloop" kann natürlich auch
ein Threadloop sein und von anderen freigegebenen Spielparametern abhängig sein usw.
- alles was ich hier im Forum sage/schreibe ist lediglich meine Meinung und keine Tatsachenbehauptung
- unkommentierter Quellcode = unqualifizierter Müll
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Re: meine derzeitige GameLoop

Beitrag von ZeHa »

Damit müssen aber wieder beide Threads aufeinander warten, weil Du ja immer wieder die Daten vom einen Buffer in den nächsten kopieren mußt, damit der andere Thread damit weiterarbeiten kann. Das ganze wird dadurch sogar noch langsamer als wenn es single-threaded wäre.

@ Moderatoren:
Im Übrigen fände ich es ganz gut, wenn man diesen Multithreading-Krempel mal in einen eigenen Thread packen könnte (also im Prinzip ab AND51s erstem Posting). Die Diskussion an sich ist ja ok, und vielleicht findet sich ja irgendwann doch noch die Erleuchtung, aber in meinem Ur-Posting ging es eigentlich um die framerate-unabhängige Spieleprogrammierung und nicht um Multithreading.
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Re: meine derzeitige GameLoop

Beitrag von Thorium »

ZeHa hat geschrieben:aber in meinem Ur-Posting ging es eigentlich um die framerate-unabhängige Spieleprogrammierung und nicht um Multithreading.
Das geht aber nicht aus dem Threadtitel hervor: "meine derzeitige GameLoop"
Das läd eher zum allgemeinen diskutieren über die Game Loop ein und wie man sie verbessern/erweitern kann, auf welche Art auch immer.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Re: meine derzeitige GameLoop

Beitrag von ZeHa »

Da hast Du auch wieder Recht, daher werde ich das mal kurzerhand ändern...
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Re: framerate-unabhängige GameLoop

Beitrag von PMV »

Öhm, so eindeutig find ich den Titel jetzt erlich gesagt nicht. :wink:
Aber um auf das
Die Diskussion an sich ist ja ok, und vielleicht findet sich ja irgendwann doch noch die Erleuchtung,
einzugehen. Hab den Thread wieder gefunden, den ich meinte. Verlinkt
hab ich mal die resultierende Loop. http://www.purebasic.fr/english/viewtop ... 65#p346465
Wenn man eine Maus mit hohen Abtastraten hat, ist so ein Thread die
einzige Lösung, selbst bei Single-Core CPUs. Und man will seine Spieler
ja nicht verwehren, die teure Maus auch nutzen zu dürfen. :wink: Ich
würd dir im übrrigen empfehlen, den ganzen Thread mal durch zu lesen.



Ach ja ... und dann noch zu dem Timingproblem. Wenn ein Spiel unter eine
bestimmte Framerate fällt, wird es unspielbar. Selbst wenn es nur eine kurze
Zeit von vielleicht 5 Sekunden so ist, verliert der Benutzer die Kontrolle.
Dein Spiel wird zwar keine Kollisionsbugs haben, aber springen wird trotzdem
alles, und der Spieler kann nicht reagieren. Ich geh daher in meiner Gameloop
immer davon aus, das die Framerate über einem bestimmten Mindestwert
bleibt und ignoriere daher Probleme bei der Kollision. Wenn aber das Spiel
doch unter eine vordefinierte Framerate fällt, pausiere ich es einfach.

MFG PMV
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Antworten